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_metadata_sig (MonoDomain *domain, const char* sig);
74 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
75 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
76 static CRITICAL_SECTION ldstr_section;
78 static gboolean profile_allocs = TRUE;
81 mono_runtime_object_init (MonoObject *this)
83 MonoMethod *method = NULL;
84 MonoClass *klass = this->vtable->klass;
86 method = mono_class_get_method_from_name (klass, ".ctor", 0);
89 if (method->klass->valuetype)
90 this = mono_object_unbox (this);
91 mono_runtime_invoke (method, this, NULL, NULL);
94 /* The pseudo algorithm for type initialization from the spec
95 Note it doesn't say anything about domains - only threads.
97 2. If the type is initialized you are done.
98 2.1. If the type is not yet initialized, try to take an
100 2.2. If successful, record this thread as responsible for
101 initializing the type and proceed to step 2.3.
102 2.2.1. If not, see whether this thread or any thread
103 waiting for this thread to complete already holds the lock.
104 2.2.2. If so, return since blocking would create a deadlock. This thread
105 will now see an incompletely initialized state for the type,
106 but no deadlock will arise.
107 2.2.3 If not, block until the type is initialized then return.
108 2.3 Initialize the parent type and then all interfaces implemented
110 2.4 Execute the type initialization code for this type.
111 2.5 Mark the type as initialized, release the initialization lock,
112 awaken any threads waiting for this type to be initialized,
119 guint32 initializing_tid;
120 guint32 waiting_count;
122 CRITICAL_SECTION initialization_section;
123 } TypeInitializationLock;
125 /* for locking access to type_initialization_hash and blocked_thread_hash */
126 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
127 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
128 static CRITICAL_SECTION type_initialization_section;
130 /* from vtable to lock */
131 static GHashTable *type_initialization_hash;
133 /* from thread id to thread id being waited on */
134 static GHashTable *blocked_thread_hash;
137 static MonoThread *main_thread;
140 * mono_thread_set_main:
141 * @thread: thread to set as the main thread
143 * This function can be used to instruct the runtime to treat @thread
144 * as the main thread, ie, the thread that would normally execute the Main()
145 * method. This basically means that at the end of @thread, the runtime will
146 * wait for the existing foreground threads to quit and other such details.
149 mono_thread_set_main (MonoThread *thread)
151 main_thread = thread;
155 mono_thread_get_main (void)
161 mono_type_initialization_init (void)
163 InitializeCriticalSection (&type_initialization_section);
164 type_initialization_hash = g_hash_table_new (NULL, NULL);
165 blocked_thread_hash = g_hash_table_new (NULL, NULL);
166 InitializeCriticalSection (&ldstr_section);
170 mono_type_initialization_cleanup (void)
173 /* This is causing race conditions with
174 * mono_release_type_locks
176 DeleteCriticalSection (&type_initialization_section);
178 DeleteCriticalSection (&ldstr_section);
182 * get_type_init_exception_for_vtable:
184 * Return the stored type initialization exception for VTABLE.
186 static MonoException*
187 get_type_init_exception_for_vtable (MonoVTable *vtable)
189 MonoDomain *domain = vtable->domain;
190 MonoClass *klass = vtable->klass;
194 g_assert (vtable->init_failed);
197 * If the initializing thread was rudely aborted, the exception is not stored
201 mono_domain_lock (domain);
202 if (domain->type_init_exception_hash)
203 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
204 mono_domain_unlock (domain);
207 if (klass->name_space && *klass->name_space)
208 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
210 full_name = g_strdup (klass->name);
211 ex = mono_get_exception_type_initialization (full_name, NULL);
218 * mono_runtime_class_init:
219 * @vtable: vtable that needs to be initialized
221 * This routine calls the class constructor for @vtable.
224 mono_runtime_class_init (MonoVTable *vtable)
226 mono_runtime_class_init_full (vtable, TRUE);
230 * mono_runtime_class_init_full:
231 * @vtable that neeeds to be initialized
232 * @raise_exception is TRUE, exceptions are raised intead of returned
236 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
239 MonoException *exc_to_throw;
240 MonoMethod *method = NULL;
246 if (vtable->initialized)
250 klass = vtable->klass;
252 if (!klass->image->checked_module_cctor) {
253 mono_image_check_for_module_cctor (klass->image);
254 if (klass->image->has_module_cctor) {
255 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
256 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
259 method = mono_class_get_cctor (klass);
262 MonoDomain *domain = vtable->domain;
263 TypeInitializationLock *lock;
264 guint32 tid = GetCurrentThreadId();
265 int do_initialization = 0;
266 MonoDomain *last_domain = NULL;
268 mono_type_initialization_lock ();
269 /* double check... */
270 if (vtable->initialized) {
271 mono_type_initialization_unlock ();
274 if (vtable->init_failed) {
275 mono_type_initialization_unlock ();
277 /* The type initialization already failed once, rethrow the same exception */
279 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
280 return get_type_init_exception_for_vtable (vtable);
282 lock = g_hash_table_lookup (type_initialization_hash, vtable);
284 /* This thread will get to do the initialization */
285 if (mono_domain_get () != domain) {
286 /* Transfer into the target domain */
287 last_domain = mono_domain_get ();
288 if (!mono_domain_set (domain, FALSE)) {
289 vtable->initialized = 1;
290 mono_type_initialization_unlock ();
292 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
293 return mono_get_exception_appdomain_unloaded ();
296 lock = g_malloc (sizeof(TypeInitializationLock));
297 InitializeCriticalSection (&lock->initialization_section);
298 lock->initializing_tid = tid;
299 lock->waiting_count = 1;
301 /* grab the vtable lock while this thread still owns type_initialization_section */
302 EnterCriticalSection (&lock->initialization_section);
303 g_hash_table_insert (type_initialization_hash, vtable, lock);
304 do_initialization = 1;
307 TypeInitializationLock *pending_lock;
309 if (lock->initializing_tid == tid || lock->done) {
310 mono_type_initialization_unlock ();
313 /* see if the thread doing the initialization is already blocked on this thread */
314 blocked = GUINT_TO_POINTER (lock->initializing_tid);
315 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
316 if (pending_lock->initializing_tid == tid) {
317 if (!pending_lock->done) {
318 mono_type_initialization_unlock ();
321 /* the thread doing the initialization is blocked on this thread,
322 but on a lock that has already been freed. It just hasn't got
327 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
329 ++lock->waiting_count;
330 /* record the fact that we are waiting on the initializing thread */
331 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
333 mono_type_initialization_unlock ();
335 if (do_initialization) {
336 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
338 /* If the initialization failed, mark the class as unusable. */
339 /* Avoid infinite loops */
341 (klass->image == mono_defaults.corlib &&
342 !strcmp (klass->name_space, "System") &&
343 !strcmp (klass->name, "TypeInitializationException")))) {
344 vtable->init_failed = 1;
346 if (klass->name_space && *klass->name_space)
347 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
349 full_name = g_strdup (klass->name);
350 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
354 * Store the exception object so it could be thrown on subsequent
357 mono_domain_lock (domain);
358 if (!domain->type_init_exception_hash)
359 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
360 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
361 mono_domain_unlock (domain);
365 mono_domain_set (last_domain, TRUE);
367 LeaveCriticalSection (&lock->initialization_section);
369 /* this just blocks until the initializing thread is done */
370 EnterCriticalSection (&lock->initialization_section);
371 LeaveCriticalSection (&lock->initialization_section);
374 mono_type_initialization_lock ();
375 if (lock->initializing_tid != tid)
376 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
377 --lock->waiting_count;
378 if (lock->waiting_count == 0) {
379 DeleteCriticalSection (&lock->initialization_section);
380 g_hash_table_remove (type_initialization_hash, vtable);
383 if (!vtable->init_failed)
384 vtable->initialized = 1;
385 mono_type_initialization_unlock ();
387 if (vtable->init_failed) {
388 /* Either we were the initializing thread or we waited for the initialization */
390 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
391 return get_type_init_exception_for_vtable (vtable);
394 vtable->initialized = 1;
401 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
403 MonoVTable *vtable = (MonoVTable*)key;
405 TypeInitializationLock *lock = (TypeInitializationLock*) value;
406 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
409 * Have to set this since it cannot be set by the normal code in
410 * mono_runtime_class_init (). In this case, the exception object is not stored,
411 * and get_type_init_exception_for_class () needs to be aware of this.
413 vtable->init_failed = 1;
414 LeaveCriticalSection (&lock->initialization_section);
415 --lock->waiting_count;
416 if (lock->waiting_count == 0) {
417 DeleteCriticalSection (&lock->initialization_section);
426 mono_release_type_locks (MonoThread *thread)
428 mono_type_initialization_lock ();
429 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
430 mono_type_initialization_unlock ();
434 default_trampoline (MonoMethod *method)
440 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
442 g_assert_not_reached ();
448 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
450 g_error ("remoting not installed");
455 default_delegate_trampoline (MonoClass *klass)
457 g_assert_not_reached ();
461 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
462 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
463 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
464 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
465 static MonoImtThunkBuilder imt_thunk_builder = NULL;
466 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
467 #if (MONO_IMT_SIZE > 32)
468 #error "MONO_IMT_SIZE cannot be larger than 32"
472 mono_install_trampoline (MonoTrampoline func)
474 arch_create_jit_trampoline = func? func: default_trampoline;
478 mono_install_jump_trampoline (MonoJumpTrampoline func)
480 arch_create_jump_trampoline = func? func: default_jump_trampoline;
484 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
486 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
490 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
492 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
496 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
497 imt_thunk_builder = func;
500 static MonoCompileFunc default_mono_compile_method = NULL;
503 * mono_install_compile_method:
504 * @func: function to install
506 * This is a VM internal routine
509 mono_install_compile_method (MonoCompileFunc func)
511 default_mono_compile_method = func;
515 * mono_compile_method:
516 * @method: The method to compile.
518 * This JIT-compiles the method, and returns the pointer to the native code
522 mono_compile_method (MonoMethod *method)
524 if (!default_mono_compile_method) {
525 g_error ("compile method called on uninitialized runtime");
528 return default_mono_compile_method (method);
532 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
534 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
538 mono_runtime_create_delegate_trampoline (MonoClass *klass)
540 return arch_create_delegate_trampoline (klass);
543 static MonoFreeMethodFunc default_mono_free_method = NULL;
546 * mono_install_free_method:
547 * @func: pointer to the MonoFreeMethodFunc used to release a method
549 * This is an internal VM routine, it is used for the engines to
550 * register a handler to release the resources associated with a method.
552 * Methods are freed when no more references to the delegate that holds
556 mono_install_free_method (MonoFreeMethodFunc func)
558 default_mono_free_method = func;
562 * mono_runtime_free_method:
563 * @domain; domain where the method is hosted
564 * @method: method to release
566 * This routine is invoked to free the resources associated with
567 * a method that has been JIT compiled. This is used to discard
568 * methods that were used only temporarily (for example, used in marshalling)
572 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
574 if (default_mono_free_method != NULL)
575 default_mono_free_method (domain, method);
577 mono_free_method (method);
581 * The vtables in the root appdomain are assumed to be reachable by other
582 * roots, and we don't use typed allocation in the other domains.
585 /* The sync block is no longer a GC pointer */
586 #define GC_HEADER_BITMAP (0)
588 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
591 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
593 MonoClassField *field;
599 max_size = mono_class_data_size (class) / sizeof (gpointer);
601 max_size = class->instance_size / sizeof (gpointer);
602 if (max_size >= size) {
603 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
606 for (p = class; p != NULL; p = p->parent) {
607 gpointer iter = NULL;
608 while ((field = mono_class_get_fields (p, &iter))) {
612 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
614 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
617 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
620 /* FIXME: should not happen, flag as type load error */
621 if (field->type->byref)
624 pos = field->offset / sizeof (gpointer);
627 type = mono_type_get_underlying_type (field->type);
628 switch (type->type) {
631 case MONO_TYPE_FNPTR:
633 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
638 if (class->image != mono_defaults.corlib)
641 case MONO_TYPE_STRING:
642 case MONO_TYPE_SZARRAY:
643 case MONO_TYPE_CLASS:
644 case MONO_TYPE_OBJECT:
645 case MONO_TYPE_ARRAY:
646 g_assert ((field->offset % sizeof(gpointer)) == 0);
648 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
649 *max_set = MAX (*max_set, pos);
651 case MONO_TYPE_GENERICINST:
652 if (!mono_type_generic_inst_is_valuetype (type)) {
653 g_assert ((field->offset % sizeof(gpointer)) == 0);
655 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
656 *max_set = MAX (*max_set, pos);
661 case MONO_TYPE_VALUETYPE: {
662 MonoClass *fclass = mono_class_from_mono_type (field->type);
663 if (fclass->has_references) {
664 /* remove the object header */
665 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
679 case MONO_TYPE_BOOLEAN:
683 g_assert_not_reached ();
695 * similar to the above, but sets the bits in the bitmap for any non-ref field
696 * and ignores static fields
699 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
701 MonoClassField *field;
706 max_size = class->instance_size / sizeof (gpointer);
707 if (max_size >= size) {
708 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
711 for (p = class; p != NULL; p = p->parent) {
712 gpointer iter = NULL;
713 while ((field = mono_class_get_fields (p, &iter))) {
716 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
718 /* FIXME: should not happen, flag as type load error */
719 if (field->type->byref)
722 pos = field->offset / sizeof (gpointer);
725 type = mono_type_get_underlying_type (field->type);
726 switch (type->type) {
727 #if SIZEOF_VOID_P == 8
731 case MONO_TYPE_FNPTR:
736 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
737 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
738 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
741 #if SIZEOF_VOID_P == 4
745 case MONO_TYPE_FNPTR:
750 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
751 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
752 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
758 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
759 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
760 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
763 case MONO_TYPE_BOOLEAN:
766 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
768 case MONO_TYPE_STRING:
769 case MONO_TYPE_SZARRAY:
770 case MONO_TYPE_CLASS:
771 case MONO_TYPE_OBJECT:
772 case MONO_TYPE_ARRAY:
774 case MONO_TYPE_GENERICINST:
775 if (!mono_type_generic_inst_is_valuetype (type)) {
780 case MONO_TYPE_VALUETYPE: {
781 MonoClass *fclass = mono_class_from_mono_type (field->type);
782 /* remove the object header */
783 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
787 g_assert_not_reached ();
796 * mono_class_insecure_overlapping:
797 * check if a class with explicit layout has references and non-references
798 * fields overlapping.
800 * Returns: TRUE if it is insecure to load the type.
803 mono_class_insecure_overlapping (MonoClass *klass)
807 gsize default_bitmap [4] = {0};
809 gsize default_nrbitmap [4] = {0};
810 int i, insecure = FALSE;
813 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
814 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
816 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
817 int idx = i % (sizeof (bitmap [0]) * 8);
818 if (bitmap [idx] & nrbitmap [idx]) {
823 if (bitmap != default_bitmap)
825 if (nrbitmap != default_nrbitmap)
828 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
836 mono_string_alloc (int length)
838 return mono_string_new_size (mono_domain_get (), length);
842 mono_class_compute_gc_descriptor (MonoClass *class)
846 gsize default_bitmap [4] = {0};
847 static gboolean gcj_inited = FALSE;
852 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
853 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
854 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
855 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
857 #ifdef HAVE_GC_GCJ_MALLOC
859 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
863 #ifdef GC_REDIRECT_TO_LOCAL
864 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
865 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
867 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
868 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
873 mono_loader_unlock ();
877 mono_class_init (class);
879 if (class->gc_descr_inited)
882 class->gc_descr_inited = TRUE;
883 class->gc_descr = GC_NO_DESCRIPTOR;
885 bitmap = default_bitmap;
886 if (class == mono_defaults.string_class) {
887 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
888 } else if (class->rank) {
889 mono_class_compute_gc_descriptor (class->element_class);
890 if (!class->element_class->valuetype) {
892 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
893 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
894 class->name_space, class->name);*/
896 /* remove the object header */
897 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
898 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
899 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
900 class->name_space, class->name);*/
901 if (bitmap != default_bitmap)
905 /*static int count = 0;
908 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
909 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
911 if (class->gc_descr == GC_NO_DESCRIPTOR)
912 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
914 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
915 if (bitmap != default_bitmap)
921 * field_is_special_static:
922 * @fklass: The MonoClass to look up.
923 * @field: The MonoClassField describing the field.
925 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
926 * SPECIAL_STATIC_NONE otherwise.
929 field_is_special_static (MonoClass *fklass, MonoClassField *field)
931 MonoCustomAttrInfo *ainfo;
933 ainfo = mono_custom_attrs_from_field (fklass, field);
936 for (i = 0; i < ainfo->num_attrs; ++i) {
937 MonoClass *klass = ainfo->attrs [i].ctor->klass;
938 if (klass->image == mono_defaults.corlib) {
939 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
940 mono_custom_attrs_free (ainfo);
941 return SPECIAL_STATIC_THREAD;
943 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
944 mono_custom_attrs_free (ainfo);
945 return SPECIAL_STATIC_CONTEXT;
949 mono_custom_attrs_free (ainfo);
950 return SPECIAL_STATIC_NONE;
953 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
954 #define mix(a,b,c) { \
955 a -= c; a ^= rot(c, 4); c += b; \
956 b -= a; b ^= rot(a, 6); a += c; \
957 c -= b; c ^= rot(b, 8); b += a; \
958 a -= c; a ^= rot(c,16); c += b; \
959 b -= a; b ^= rot(a,19); a += c; \
960 c -= b; c ^= rot(b, 4); b += a; \
962 #define final(a,b,c) { \
963 c ^= b; c -= rot(b,14); \
964 a ^= c; a -= rot(c,11); \
965 b ^= a; b -= rot(a,25); \
966 c ^= b; c -= rot(b,16); \
967 a ^= c; a -= rot(c,4); \
968 b ^= a; b -= rot(a,14); \
969 c ^= b; c -= rot(b,24); \
973 mono_method_get_imt_slot (MonoMethod *method) {
974 MonoMethodSignature *sig;
976 guint32 *hashes_start, *hashes;
981 * We do this to simplify generic sharing. It will hurt
982 * performance in cases where a class implements two different
983 * instantiations of the same generic interface.
985 if (method->is_inflated)
986 method = ((MonoMethodInflated*)method)->declaring;
988 sig = mono_method_signature (method);
989 hashes_count = sig->param_count + 4;
990 hashes_start = malloc (hashes_count * sizeof (guint32));
991 hashes = hashes_start;
993 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
994 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
995 method->klass->name_space, method->klass->name, method->name);
996 g_assert_not_reached ();
999 /* Initialize hashes */
1000 hashes [0] = g_str_hash (method->klass->name);
1001 hashes [1] = g_str_hash (method->klass->name_space);
1002 hashes [2] = g_str_hash (method->name);
1003 hashes [3] = mono_metadata_type_hash (sig->ret);
1004 for (i = 0; i < sig->param_count; i++) {
1005 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1008 /* Setup internal state */
1009 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1011 /* Handle most of the hashes */
1012 while (hashes_count > 3) {
1021 /* Handle the last 3 hashes (all the case statements fall through) */
1022 switch (hashes_count) {
1023 case 3 : c += hashes [2];
1024 case 2 : b += hashes [1];
1025 case 1 : a += hashes [0];
1027 case 0: /* nothing left to add */
1031 free (hashes_start);
1032 /* Report the result */
1033 return c % MONO_IMT_SIZE;
1042 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1043 guint32 imt_slot = mono_method_get_imt_slot (method);
1044 MonoImtBuilderEntry *entry;
1046 if (slot_num >= 0 && imt_slot != slot_num) {
1047 /* we build just a single imt slot and this is not it */
1051 entry = malloc (sizeof (MonoImtBuilderEntry));
1052 entry->method = method;
1053 entry->vtable_slot = vtable_slot;
1054 entry->next = imt_builder [imt_slot];
1055 if (imt_builder [imt_slot] != NULL) {
1056 entry->children = imt_builder [imt_slot]->children + 1;
1057 if (entry->children == 1) {
1058 mono_stats.imt_slots_with_collisions++;
1059 *imt_collisions_bitmap |= (1 << imt_slot);
1062 entry->children = 0;
1063 mono_stats.imt_used_slots++;
1065 imt_builder [imt_slot] = entry;
1067 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1068 method, method->klass->name_space, method->klass->name,
1069 method->name, imt_slot, vtable_slot, entry->children);
1075 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1077 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1081 e->method->klass->name_space,
1082 e->method->klass->name,
1085 printf (" * %s: NULL\n", message);
1091 compare_imt_builder_entries (const void *p1, const void *p2) {
1092 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1093 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1095 return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
1099 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1101 int count = end - start;
1102 int chunk_start = out_array->len;
1105 for (i = start; i < end; ++i) {
1106 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1107 item->method = sorted_array [i]->method;
1108 item->vtable_slot = sorted_array [i]->vtable_slot;
1109 item->is_equals = TRUE;
1111 item->check_target_idx = out_array->len + 1;
1113 item->check_target_idx = 0;
1114 g_ptr_array_add (out_array, item);
1117 int middle = start + count / 2;
1118 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1120 item->method = sorted_array [middle]->method;
1121 item->is_equals = FALSE;
1122 g_ptr_array_add (out_array, item);
1123 imt_emit_ir (sorted_array, start, middle, out_array);
1124 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1130 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1131 int number_of_entries = entries->children + 1;
1132 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1133 GPtrArray *result = g_ptr_array_new ();
1134 MonoImtBuilderEntry *current_entry;
1137 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1138 sorted_array [i] = current_entry;
1140 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1142 /*for (i = 0; i < number_of_entries; i++) {
1143 print_imt_entry (" sorted array:", sorted_array [i], i);
1146 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1148 free (sorted_array);
1153 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1154 if (imt_builder_entry != NULL) {
1155 if (imt_builder_entry->children == 0) {
1156 /* No collision, return the vtable slot contents */
1157 return vtable->vtable [imt_builder_entry->vtable_slot];
1159 /* Collision, build the thunk */
1160 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1163 result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
1164 for (i = 0; i < imt_ir->len; ++i)
1165 g_free (g_ptr_array_index (imt_ir, i));
1166 g_ptr_array_free (imt_ir, TRUE);
1176 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1179 guint32 imt_collisions_bitmap = 0;
1180 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1181 int method_count = 0;
1182 gboolean record_method_count_for_max_collisions = FALSE;
1185 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1187 for (i = 0; i < klass->interface_offsets_count; ++i) {
1188 MonoClass *iface = klass->interfaces_packed [i];
1189 int interface_offset = klass->interface_offsets_packed [i];
1190 int method_slot_in_interface;
1191 mono_class_setup_methods (iface);
1192 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1193 MonoMethod *method = iface->methods [method_slot_in_interface];
1194 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1197 if (extra_interfaces) {
1198 int interface_offset = klass->vtable_size;
1200 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1201 MonoClass* iface = list_item->data;
1202 int method_slot_in_interface;
1203 mono_class_setup_methods (iface);
1204 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1205 MonoMethod *method = iface->methods [method_slot_in_interface];
1206 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1208 interface_offset += iface->method.count;
1211 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1212 /* overwrite the imt slot only if we're building all the entries or if
1213 * we're uilding this specific one
1215 if (slot_num < 0 || i == slot_num)
1216 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1218 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1220 if (imt_builder [i] != NULL) {
1221 int methods_in_slot = imt_builder [i]->children + 1;
1222 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1223 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1224 record_method_count_for_max_collisions = TRUE;
1226 method_count += methods_in_slot;
1230 mono_stats.imt_number_of_methods += method_count;
1231 if (record_method_count_for_max_collisions) {
1232 mono_stats.imt_method_count_when_max_collisions = method_count;
1235 for (i = 0; i < MONO_IMT_SIZE; i++) {
1236 MonoImtBuilderEntry* entry = imt_builder [i];
1237 while (entry != NULL) {
1238 MonoImtBuilderEntry* next = entry->next;
1244 /* we OR the bitmap since we may build just a single imt slot at a time */
1245 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1249 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1250 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1253 static gpointer imt_trampoline = NULL;
1256 mono_install_imt_trampoline (gpointer tramp_code)
1258 imt_trampoline = tramp_code;
1261 static gpointer vtable_trampoline = NULL;
1264 mono_install_vtable_trampoline (gpointer tramp_code)
1266 vtable_trampoline = tramp_code;
1270 * mono_vtable_build_imt_slot:
1271 * @vtable: virtual object table struct
1272 * @imt_slot: slot in the IMT table
1274 * Fill the given @imt_slot in the IMT table of @vtable with
1275 * a trampoline or a thunk for the case of collisions.
1276 * This is part of the internal mono API.
1279 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1281 gpointer *imt = (gpointer*)vtable;
1282 imt -= MONO_IMT_SIZE;
1283 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1285 /* no support for extra interfaces: the proxy objects will need
1286 * to build the complete IMT
1287 * Update and heck needs to ahppen inside the proper domain lock, as all
1288 * the changes made to a MonoVTable.
1290 mono_domain_lock (vtable->domain);
1291 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1292 if (imt [imt_slot] == imt_trampoline)
1293 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1294 mono_domain_unlock (vtable->domain);
1297 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1300 * mono_class_vtable:
1301 * @domain: the application domain
1302 * @class: the class to initialize
1304 * VTables are domain specific because we create domain specific code, and
1305 * they contain the domain specific static class data.
1306 * On failure, NULL is returned, and class->exception_type is set.
1309 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1311 MonoClassRuntimeInfo *runtime_info;
1315 /* this check can be inlined in jitted code, too */
1316 runtime_info = class->runtime_info;
1317 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1318 return runtime_info->domain_vtables [domain->domain_id];
1319 if (class->exception_type)
1321 return mono_class_create_runtime_vtable (domain, class);
1325 * mono_class_try_get_vtable:
1326 * @domain: the application domain
1327 * @class: the class to initialize
1329 * This function tries to get the associated vtable from @class if
1330 * it was already created.
1333 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1335 MonoClassRuntimeInfo *runtime_info;
1339 runtime_info = class->runtime_info;
1340 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1341 return runtime_info->domain_vtables [domain->domain_id];
1346 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1349 MonoClassRuntimeInfo *runtime_info, *old_info;
1350 MonoClassField *field;
1353 int imt_table_bytes = 0;
1354 guint32 vtable_size, class_size;
1356 guint32 constant_cols [MONO_CONSTANT_SIZE];
1358 gpointer *interface_offsets;
1360 mono_domain_lock (domain);
1361 runtime_info = class->runtime_info;
1362 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1363 mono_domain_unlock (domain);
1364 return runtime_info->domain_vtables [domain->domain_id];
1366 if (!class->inited || class->exception_type) {
1367 if (!mono_class_init (class) || class->exception_type){
1369 mono_domain_unlock (domain);
1370 exc = mono_class_get_exception_for_failure (class);
1372 mono_raise_exception (exc);
1376 mono_class_init (class);
1379 * For some classes, mono_class_init () already computed class->vtable_size, and
1380 * that is all that is needed because of the vtable trampolines.
1382 if (!class->vtable_size)
1383 mono_class_setup_vtable (class);
1385 if (class->exception_type) {
1386 mono_domain_unlock (domain);
1391 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1392 if (class->interface_offsets_count) {
1393 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1394 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1395 mono_stats.imt_number_of_tables++;
1396 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1399 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1400 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1403 mono_stats.used_class_count++;
1404 mono_stats.class_vtable_size += vtable_size;
1405 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1408 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1410 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1412 vt->rank = class->rank;
1413 vt->domain = domain;
1415 mono_class_compute_gc_descriptor (class);
1417 * We can't use typed allocation in the non-root domains, since the
1418 * collector needs the GC descriptor stored in the vtable even after
1419 * the mempool containing the vtable is destroyed when the domain is
1420 * unloaded. An alternative might be to allocate vtables in the GC
1421 * heap, but this does not seem to work (it leads to crashes inside
1422 * libgc). If that approach is tried, two gc descriptors need to be
1423 * allocated for each class: one for the root domain, and one for all
1424 * other domains. The second descriptor should contain a bit for the
1425 * vtable field in MonoObject, since we can no longer assume the
1426 * vtable is reachable by other roots after the appdomain is unloaded.
1428 #ifdef HAVE_BOEHM_GC
1429 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1430 vt->gc_descr = GC_NO_DESCRIPTOR;
1433 vt->gc_descr = class->gc_descr;
1435 if ((class_size = mono_class_data_size (class))) {
1436 if (class->has_static_refs) {
1437 gpointer statics_gc_descr;
1439 gsize default_bitmap [4] = {0};
1442 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1443 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1444 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1445 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1446 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1447 if (bitmap != default_bitmap)
1450 vt->data = mono_domain_alloc0 (domain, class_size);
1452 mono_stats.class_static_data_size += class_size;
1457 while ((field = mono_class_get_fields (class, &iter))) {
1458 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1460 if (mono_field_is_deleted (field))
1462 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1463 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1464 if (special_static != SPECIAL_STATIC_NONE) {
1465 guint32 size, offset;
1467 size = mono_type_size (field->type, &align);
1468 offset = mono_alloc_special_static_data (special_static, size, align);
1469 if (!domain->special_static_fields)
1470 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1471 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1475 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1476 MonoClass *fklass = mono_class_from_mono_type (field->type);
1477 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1478 t = (char*)vt->data + field->offset;
1479 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1482 if (fklass->valuetype) {
1483 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1485 /* it's a pointer type: add check */
1486 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1487 *t = *(char *)field->data;
1491 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1494 /* later do this only on demand if needed */
1496 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1498 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1500 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1501 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1502 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1507 vt->max_interface_id = class->max_interface_id;
1508 vt->interface_bitmap = class->interface_bitmap;
1510 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1511 // class->name, class->interface_offsets_count);
1513 if (! ARCH_USE_IMT) {
1514 /* initialize interface offsets */
1515 for (i = 0; i < class->interface_offsets_count; ++i) {
1516 int interface_id = class->interfaces_packed [i]->interface_id;
1517 int slot = class->interface_offsets_packed [i];
1518 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1522 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1523 * as we change the code in appdomain.c to invalidate vtables by
1524 * looking at the possible MonoClasses created for the domain.
1526 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1527 /* class->runtime_info is protected by the loader lock, both when
1528 * it it enlarged and when it is stored info.
1530 mono_loader_lock ();
1531 old_info = class->runtime_info;
1532 if (old_info && old_info->max_domain >= domain->domain_id) {
1533 /* someone already created a large enough runtime info */
1534 mono_memory_barrier ();
1535 old_info->domain_vtables [domain->domain_id] = vt;
1537 int new_size = domain->domain_id;
1539 new_size = MAX (new_size, old_info->max_domain);
1541 /* make the new size a power of two */
1543 while (new_size > i)
1546 /* this is a bounded memory retention issue: may want to
1547 * handle it differently when we'll have a rcu-like system.
1549 runtime_info = mono_image_alloc0 (class->image, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1550 runtime_info->max_domain = new_size - 1;
1551 /* copy the stuff from the older info */
1553 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1555 runtime_info->domain_vtables [domain->domain_id] = vt;
1557 mono_memory_barrier ();
1558 class->runtime_info = runtime_info;
1560 mono_loader_unlock ();
1562 /* Initialize vtable */
1563 if (vtable_trampoline) {
1564 // This also covers the AOT case
1565 for (i = 0; i < class->vtable_size; ++i) {
1566 vt->vtable [i] = vtable_trampoline;
1569 mono_class_setup_vtable (class);
1571 for (i = 0; i < class->vtable_size; ++i) {
1574 if ((cm = class->vtable [i])) {
1575 if (mono_method_signature (cm)->generic_param_count)
1576 /* FIXME: Why is this needed ? */
1577 vt->vtable [i] = cm;
1579 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1584 if (ARCH_USE_IMT && imt_table_bytes) {
1585 /* Now that the vtable is full, we can actually fill up the IMT */
1586 if (imt_trampoline) {
1587 /* lazy construction of the IMT entries enabled */
1588 for (i = 0; i < MONO_IMT_SIZE; ++i)
1589 interface_offsets [i] = imt_trampoline;
1591 build_imt (class, vt, domain, interface_offsets, NULL);
1595 mono_domain_unlock (domain);
1597 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1598 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1599 MonoException *exc = mono_class_get_exception_for_failure (class);
1601 mono_raise_exception (exc);
1604 /* make sure the parent is initialized */
1606 mono_class_vtable (domain, class->parent);
1608 vt->type = mono_type_get_object (domain, &class->byval_arg);
1609 if (class->contextbound)
1618 * mono_class_proxy_vtable:
1619 * @domain: the application domain
1620 * @remove_class: the remote class
1622 * Creates a vtable for transparent proxies. It is basically
1623 * a copy of the real vtable of the class wrapped in @remote_class,
1624 * but all function pointers invoke the remoting functions, and
1625 * vtable->klass points to the transparent proxy class, and not to @class.
1628 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1630 MonoVTable *vt, *pvt;
1631 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1633 GSList *extra_interfaces = NULL;
1634 MonoClass *class = remote_class->proxy_class;
1635 gpointer *interface_offsets;
1637 vt = mono_class_vtable (domain, class);
1638 max_interface_id = vt->max_interface_id;
1640 /* Calculate vtable space for extra interfaces */
1641 for (j = 0; j < remote_class->interface_count; j++) {
1642 MonoClass* iclass = remote_class->interfaces[j];
1646 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1647 continue; /* interface implemented by the class */
1648 if (g_slist_find (extra_interfaces, iclass))
1651 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1653 method_count = mono_class_num_methods (iclass);
1655 ifaces = mono_class_get_implemented_interfaces (iclass);
1657 for (i = 0; i < ifaces->len; ++i) {
1658 MonoClass *ic = g_ptr_array_index (ifaces, i);
1659 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1660 continue; /* interface implemented by the class */
1661 if (g_slist_find (extra_interfaces, ic))
1663 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1664 method_count += mono_class_num_methods (ic);
1666 g_ptr_array_free (ifaces, TRUE);
1669 extra_interface_vtsize += method_count * sizeof (gpointer);
1670 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1674 mono_stats.imt_number_of_tables++;
1675 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1676 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1677 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1679 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1680 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1683 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1685 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
1687 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1689 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1690 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1692 pvt->klass = mono_defaults.transparent_proxy_class;
1693 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1694 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1696 /* initialize vtable */
1697 mono_class_setup_vtable (class);
1698 for (i = 0; i < class->vtable_size; ++i) {
1701 if ((cm = class->vtable [i]))
1702 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1703 ? cm : arch_create_remoting_trampoline (cm, target_type);
1705 pvt->vtable [i] = NULL;
1708 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1709 /* create trampolines for abstract methods */
1710 for (k = class; k; k = k->parent) {
1712 gpointer iter = NULL;
1713 while ((m = mono_class_get_methods (k, &iter)))
1714 if (!pvt->vtable [m->slot])
1715 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1719 pvt->max_interface_id = max_interface_id;
1720 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
1722 if (! ARCH_USE_IMT) {
1723 /* initialize interface offsets */
1724 for (i = 0; i < class->interface_offsets_count; ++i) {
1725 int interface_id = class->interfaces_packed [i]->interface_id;
1726 int slot = class->interface_offsets_packed [i];
1727 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1730 for (i = 0; i < class->interface_offsets_count; ++i) {
1731 int interface_id = class->interfaces_packed [i]->interface_id;
1732 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1735 if (extra_interfaces) {
1736 int slot = class->vtable_size;
1742 /* Create trampolines for the methods of the interfaces */
1743 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1744 interf = list_item->data;
1746 if (! ARCH_USE_IMT) {
1747 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1749 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1753 while ((cm = mono_class_get_methods (interf, &iter)))
1754 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1756 slot += mono_class_num_methods (interf);
1758 if (! ARCH_USE_IMT) {
1759 g_slist_free (extra_interfaces);
1764 /* Now that the vtable is full, we can actually fill up the IMT */
1765 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1766 if (extra_interfaces) {
1767 g_slist_free (extra_interfaces);
1775 * mono_class_field_is_special_static:
1777 * Returns whether @field is a thread/context static field.
1780 mono_class_field_is_special_static (MonoClassField *field)
1782 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1784 if (mono_field_is_deleted (field))
1786 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1787 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
1794 * mono_class_has_special_static_fields:
1796 * Returns whenever @klass has any thread/context static fields.
1799 mono_class_has_special_static_fields (MonoClass *klass)
1801 MonoClassField *field;
1805 while ((field = mono_class_get_fields (klass, &iter))) {
1806 g_assert (field->parent == klass);
1807 if (mono_class_field_is_special_static (field))
1815 * create_remote_class_key:
1816 * Creates an array of pointers that can be used as a hash key for a remote class.
1817 * The first element of the array is the number of pointers.
1820 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1825 if (remote_class == NULL) {
1826 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1827 key = g_malloc (sizeof(gpointer) * 3);
1828 key [0] = GINT_TO_POINTER (2);
1829 key [1] = mono_defaults.marshalbyrefobject_class;
1830 key [2] = extra_class;
1832 key = g_malloc (sizeof(gpointer) * 2);
1833 key [0] = GINT_TO_POINTER (1);
1834 key [1] = extra_class;
1837 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1838 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1839 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1840 key [1] = remote_class->proxy_class;
1842 // Keep the list of interfaces sorted
1843 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1844 if (extra_class && remote_class->interfaces [i] > extra_class) {
1845 key [j++] = extra_class;
1848 key [j] = remote_class->interfaces [i];
1851 key [j] = extra_class;
1853 // Replace the old class. The interface list is the same
1854 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1855 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1856 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1857 for (i = 0; i < remote_class->interface_count; i++)
1858 key [2 + i] = remote_class->interfaces [i];
1866 * copy_remote_class_key:
1868 * Make a copy of KEY in the domain and return the copy.
1871 copy_remote_class_key (MonoDomain *domain, gpointer *key)
1873 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1874 gpointer *mp_key = mono_domain_alloc (domain, key_size);
1876 memcpy (mp_key, key, key_size);
1882 * mono_remote_class:
1883 * @domain: the application domain
1884 * @class_name: name of the remote class
1886 * Creates and initializes a MonoRemoteClass object for a remote type.
1890 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1892 MonoRemoteClass *rc;
1893 gpointer* key, *mp_key;
1895 key = create_remote_class_key (NULL, proxy_class);
1897 mono_domain_lock (domain);
1898 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1902 mono_domain_unlock (domain);
1906 mp_key = copy_remote_class_key (domain, key);
1910 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1911 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1912 rc->interface_count = 1;
1913 rc->interfaces [0] = proxy_class;
1914 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1916 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass));
1917 rc->interface_count = 0;
1918 rc->proxy_class = proxy_class;
1921 rc->default_vtable = NULL;
1922 rc->xdomain_vtable = NULL;
1923 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1924 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
1926 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1928 mono_domain_unlock (domain);
1933 * clone_remote_class:
1934 * Creates a copy of the remote_class, adding the provided class or interface
1936 static MonoRemoteClass*
1937 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1939 MonoRemoteClass *rc;
1940 gpointer* key, *mp_key;
1942 key = create_remote_class_key (remote_class, extra_class);
1943 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1949 mp_key = copy_remote_class_key (domain, key);
1953 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1955 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1956 rc->proxy_class = remote_class->proxy_class;
1957 rc->interface_count = remote_class->interface_count + 1;
1959 // Keep the list of interfaces sorted, since the hash key of
1960 // the remote class depends on this
1961 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1962 if (remote_class->interfaces [i] > extra_class && i == j)
1963 rc->interfaces [j++] = extra_class;
1964 rc->interfaces [j] = remote_class->interfaces [i];
1967 rc->interfaces [j] = extra_class;
1969 // Replace the old class. The interface array is the same
1970 rc = mono_domain_alloc (domain, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1971 rc->proxy_class = extra_class;
1972 rc->interface_count = remote_class->interface_count;
1973 if (rc->interface_count > 0)
1974 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1977 rc->default_vtable = NULL;
1978 rc->xdomain_vtable = NULL;
1979 rc->proxy_class_name = remote_class->proxy_class_name;
1981 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1987 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1989 mono_domain_lock (domain);
1990 if (rp->target_domain_id != -1) {
1991 if (remote_class->xdomain_vtable == NULL)
1992 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1993 mono_domain_unlock (domain);
1994 return remote_class->xdomain_vtable;
1996 if (remote_class->default_vtable == NULL) {
1999 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2000 klass = mono_class_from_mono_type (type);
2001 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2002 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2004 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2007 mono_domain_unlock (domain);
2008 return remote_class->default_vtable;
2012 * mono_upgrade_remote_class:
2013 * @domain: the application domain
2014 * @tproxy: the proxy whose remote class has to be upgraded.
2015 * @klass: class to which the remote class can be casted.
2017 * Updates the vtable of the remote class by adding the necessary method slots
2018 * and interface offsets so it can be safely casted to klass. klass can be a
2019 * class or an interface.
2022 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2024 MonoTransparentProxy *tproxy;
2025 MonoRemoteClass *remote_class;
2026 gboolean redo_vtable;
2028 mono_domain_lock (domain);
2030 tproxy = (MonoTransparentProxy*) proxy_object;
2031 remote_class = tproxy->remote_class;
2033 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2036 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2037 if (remote_class->interfaces [i] == klass)
2038 redo_vtable = FALSE;
2041 redo_vtable = (remote_class->proxy_class != klass);
2045 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2046 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2049 mono_domain_unlock (domain);
2054 * mono_object_get_virtual_method:
2055 * @obj: object to operate on.
2058 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2059 * the instance of a callvirt of method.
2062 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2065 MonoMethod **vtable;
2067 MonoMethod *res = NULL;
2069 klass = mono_object_class (obj);
2070 if (klass == mono_defaults.transparent_proxy_class) {
2071 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2077 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2080 mono_class_setup_vtable (klass);
2081 vtable = klass->vtable;
2083 if (method->slot == -1) {
2084 /* method->slot might not be set for instances of generic methods */
2085 if (method->is_inflated) {
2086 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2087 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2089 g_assert_not_reached ();
2093 /* check method->slot is a valid index: perform isinstance? */
2094 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2096 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2098 res = vtable [method->slot];
2102 /* It may be an interface, abstract class method or generic method */
2103 if (!res || mono_method_signature (res)->generic_param_count)
2106 /* generic methods demand invoke_with_check */
2107 if (mono_method_signature (res)->generic_param_count)
2108 res = mono_marshal_get_remoting_invoke_with_check (res);
2110 res = mono_marshal_get_remoting_invoke (res);
2112 if (method->is_inflated && !res->is_inflated) {
2113 /* Have to inflate the result */
2114 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2124 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2126 g_error ("runtime invoke called on uninitialized runtime");
2130 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2133 * mono_runtime_invoke:
2134 * @method: method to invoke
2135 * @obJ: object instance
2136 * @params: arguments to the method
2137 * @exc: exception information.
2139 * Invokes the method represented by @method on the object @obj.
2141 * obj is the 'this' pointer, it should be NULL for static
2142 * methods, a MonoObject* for object instances and a pointer to
2143 * the value type for value types.
2145 * The params array contains the arguments to the method with the
2146 * same convention: MonoObject* pointers for object instances and
2147 * pointers to the value type otherwise.
2149 * From unmanaged code you'll usually use the
2150 * mono_runtime_invoke() variant.
2152 * Note that this function doesn't handle virtual methods for
2153 * you, it will exec the exact method you pass: we still need to
2154 * expose a function to lookup the derived class implementation
2155 * of a virtual method (there are examples of this in the code,
2158 * You can pass NULL as the exc argument if you don't want to
2159 * catch exceptions, otherwise, *exc will be set to the exception
2160 * thrown, if any. if an exception is thrown, you can't use the
2161 * MonoObject* result from the function.
2163 * If the method returns a value type, it is boxed in an object
2167 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2169 if (mono_runtime_get_no_exec ())
2170 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2172 return default_mono_runtime_invoke (method, obj, params, exc);
2176 * mono_method_get_unmanaged_thunk:
2177 * @method: method to generate a thunk for.
2179 * Returns an unmanaged->managed thunk that can be used to call
2180 * a managed method directly from C.
2182 * The thunk's C signature closely matches the managed signature:
2184 * C#: public bool Equals (object obj);
2185 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2186 * MonoObject*, MonoException**);
2188 * The 1st ("this") parameter must not be used with static methods:
2190 * C#: public static bool ReferenceEquals (object a, object b);
2191 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2194 * The last argument must be a non-null pointer of a MonoException* pointer.
2195 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2196 * exception has been thrown in managed code. Otherwise it will point
2197 * to the MonoException* caught by the thunk. In this case, the result of
2198 * the thunk is undefined:
2200 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2201 * MonoException *ex = NULL;
2202 * Equals func = mono_method_get_unmanaged_thunk (method);
2203 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2205 * // handle exception
2208 * The calling convention of the thunk matches the platform's default
2209 * convention. This means that under Windows, C declarations must
2210 * contain the __stdcall attribute:
2212 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2213 * MonoObject*, MonoException**);
2217 * Value type arguments and return values are treated as they were objects:
2219 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2220 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2222 * Arguments must be properly boxed upon trunk's invocation, while return
2223 * values must be unboxed.
2226 mono_method_get_unmanaged_thunk (MonoMethod *method)
2228 method = mono_marshal_get_thunk_invoke_wrapper (method);
2229 return mono_compile_method (method);
2233 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2237 gpointer *p = (gpointer*)dest;
2244 case MONO_TYPE_BOOLEAN:
2246 case MONO_TYPE_U1: {
2247 guint8 *p = (guint8*)dest;
2248 *p = value ? *(guint8*)value : 0;
2253 case MONO_TYPE_CHAR: {
2254 guint16 *p = (guint16*)dest;
2255 *p = value ? *(guint16*)value : 0;
2258 #if SIZEOF_VOID_P == 4
2263 case MONO_TYPE_U4: {
2264 gint32 *p = (gint32*)dest;
2265 *p = value ? *(gint32*)value : 0;
2268 #if SIZEOF_VOID_P == 8
2273 case MONO_TYPE_U8: {
2274 gint64 *p = (gint64*)dest;
2275 *p = value ? *(gint64*)value : 0;
2278 case MONO_TYPE_R4: {
2279 float *p = (float*)dest;
2280 *p = value ? *(float*)value : 0;
2283 case MONO_TYPE_R8: {
2284 double *p = (double*)dest;
2285 *p = value ? *(double*)value : 0;
2288 case MONO_TYPE_STRING:
2289 case MONO_TYPE_SZARRAY:
2290 case MONO_TYPE_CLASS:
2291 case MONO_TYPE_OBJECT:
2292 case MONO_TYPE_ARRAY:
2293 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2295 case MONO_TYPE_FNPTR:
2296 case MONO_TYPE_PTR: {
2297 gpointer *p = (gpointer*)dest;
2298 *p = deref_pointer? *(gpointer*)value: value;
2301 case MONO_TYPE_VALUETYPE:
2302 /* note that 't' and 'type->type' can be different */
2303 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2304 t = type->data.klass->enum_basetype->type;
2308 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2310 memset (dest, 0, size);
2312 memcpy (dest, value, size);
2315 case MONO_TYPE_GENERICINST:
2316 t = type->data.generic_class->container_class->byval_arg.type;
2319 g_warning ("got type %x", type->type);
2320 g_assert_not_reached ();
2325 * mono_field_set_value:
2326 * @obj: Instance object
2327 * @field: MonoClassField describing the field to set
2328 * @value: The value to be set
2330 * Sets the value of the field described by @field in the object instance @obj
2331 * to the value passed in @value. This method should only be used for instance
2332 * fields. For static fields, use mono_field_static_set_value.
2334 * The value must be on the native format of the field type.
2337 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2341 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2343 dest = (char*)obj + field->offset;
2344 set_value (field->type, dest, value, FALSE);
2348 * mono_field_static_set_value:
2349 * @field: MonoClassField describing the field to set
2350 * @value: The value to be set
2352 * Sets the value of the static field described by @field
2353 * to the value passed in @value.
2355 * The value must be on the native format of the field type.
2358 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2362 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2363 /* you cant set a constant! */
2364 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2366 dest = (char*)vt->data + field->offset;
2367 set_value (field->type, dest, value, FALSE);
2370 /* Used by the debugger */
2372 mono_vtable_get_static_field_data (MonoVTable *vt)
2378 * mono_field_get_value:
2379 * @obj: Object instance
2380 * @field: MonoClassField describing the field to fetch information from
2381 * @value: pointer to the location where the value will be stored
2383 * Use this routine to get the value of the field @field in the object
2386 * The pointer provided by value must be of the field type, for reference
2387 * types this is a MonoObject*, for value types its the actual pointer to
2392 * mono_field_get_value (obj, int_field, &i);
2395 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2399 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2401 src = (char*)obj + field->offset;
2402 set_value (field->type, value, src, TRUE);
2406 * mono_field_get_value_object:
2407 * @domain: domain where the object will be created (if boxing)
2408 * @field: MonoClassField describing the field to fetch information from
2409 * @obj: The object instance for the field.
2411 * Returns: a new MonoObject with the value from the given field. If the
2412 * field represents a value type, the value is boxed.
2416 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2420 MonoVTable *vtable = NULL;
2422 gboolean is_static = FALSE;
2423 gboolean is_ref = FALSE;
2425 switch (field->type->type) {
2426 case MONO_TYPE_STRING:
2427 case MONO_TYPE_OBJECT:
2428 case MONO_TYPE_CLASS:
2429 case MONO_TYPE_ARRAY:
2430 case MONO_TYPE_SZARRAY:
2435 case MONO_TYPE_BOOLEAN:
2438 case MONO_TYPE_CHAR:
2447 case MONO_TYPE_VALUETYPE:
2448 is_ref = field->type->byref;
2450 case MONO_TYPE_GENERICINST:
2451 is_ref = !field->type->data.generic_class->container_class->valuetype;
2454 g_error ("type 0x%x not handled in "
2455 "mono_field_get_value_object", field->type->type);
2459 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2461 vtable = mono_class_vtable (domain, field->parent);
2462 if (!vtable->initialized)
2463 mono_runtime_class_init (vtable);
2468 mono_field_static_get_value (vtable, field, &o);
2470 mono_field_get_value (obj, field, &o);
2475 /* boxed value type */
2476 klass = mono_class_from_mono_type (field->type);
2477 o = mono_object_new (domain, klass);
2478 v = ((gchar *) o) + sizeof (MonoObject);
2480 mono_field_static_get_value (vtable, field, v);
2482 mono_field_get_value (obj, field, v);
2489 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2492 const char *p = blob;
2493 mono_metadata_decode_blob_size (p, &p);
2496 case MONO_TYPE_BOOLEAN:
2499 *(guint8 *) value = *p;
2501 case MONO_TYPE_CHAR:
2504 *(guint16*) value = read16 (p);
2508 *(guint32*) value = read32 (p);
2512 *(guint64*) value = read64 (p);
2515 readr4 (p, (float*) value);
2518 readr8 (p, (double*) value);
2520 case MONO_TYPE_STRING:
2521 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2523 case MONO_TYPE_CLASS:
2524 *(gpointer*) value = NULL;
2528 g_warning ("type 0x%02x should not be in constant table", type);
2534 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2536 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2537 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2541 * mono_field_static_get_value:
2542 * @vt: vtable to the object
2543 * @field: MonoClassField describing the field to fetch information from
2544 * @value: where the value is returned
2546 * Use this routine to get the value of the static field @field value.
2548 * The pointer provided by value must be of the field type, for reference
2549 * types this is a MonoObject*, for value types its the actual pointer to
2554 * mono_field_static_get_value (vt, int_field, &i);
2557 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2561 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2563 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2564 get_default_field_value (vt->domain, field, value);
2568 src = (char*)vt->data + field->offset;
2569 set_value (field->type, value, src, TRUE);
2573 * mono_property_set_value:
2574 * @prop: MonoProperty to set
2575 * @obj: instance object on which to act
2576 * @params: parameters to pass to the propery
2577 * @exc: optional exception
2579 * Invokes the property's set method with the given arguments on the
2580 * object instance obj (or NULL for static properties).
2582 * You can pass NULL as the exc argument if you don't want to
2583 * catch exceptions, otherwise, *exc will be set to the exception
2584 * thrown, if any. if an exception is thrown, you can't use the
2585 * MonoObject* result from the function.
2588 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2590 default_mono_runtime_invoke (prop->set, obj, params, exc);
2594 * mono_property_get_value:
2595 * @prop: MonoProperty to fetch
2596 * @obj: instance object on which to act
2597 * @params: parameters to pass to the propery
2598 * @exc: optional exception
2600 * Invokes the property's get method with the given arguments on the
2601 * object instance obj (or NULL for static properties).
2603 * You can pass NULL as the exc argument if you don't want to
2604 * catch exceptions, otherwise, *exc will be set to the exception
2605 * thrown, if any. if an exception is thrown, you can't use the
2606 * MonoObject* result from the function.
2608 * Returns: the value from invoking the get method on the property.
2611 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2613 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2617 * mono_nullable_init:
2618 * @buf: The nullable structure to initialize.
2619 * @value: the value to initialize from
2620 * @klass: the type for the object
2622 * Initialize the nullable structure pointed to by @buf from @value which
2623 * should be a boxed value type. The size of @buf should be able to hold
2624 * as much data as the @klass->instance_size (which is the number of bytes
2625 * that will be copies).
2627 * Since Nullables have variable structure, we can not define a C
2628 * structure for them.
2631 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2633 MonoClass *param_class = klass->cast_class;
2635 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2636 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2638 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2640 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2642 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2646 * mono_nullable_box:
2647 * @buf: The buffer representing the data to be boxed
2648 * @klass: the type to box it as.
2650 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2654 mono_nullable_box (guint8 *buf, MonoClass *klass)
2656 MonoClass *param_class = klass->cast_class;
2658 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2659 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2661 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2662 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2663 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2671 * mono_get_delegate_invoke:
2672 * @klass: The delegate class
2674 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2677 mono_get_delegate_invoke (MonoClass *klass)
2681 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2688 * mono_runtime_delegate_invoke:
2689 * @delegate: pointer to a delegate object.
2690 * @params: parameters for the delegate.
2691 * @exc: Pointer to the exception result.
2693 * Invokes the delegate method @delegate with the parameters provided.
2695 * You can pass NULL as the exc argument if you don't want to
2696 * catch exceptions, otherwise, *exc will be set to the exception
2697 * thrown, if any. if an exception is thrown, you can't use the
2698 * MonoObject* result from the function.
2701 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2705 im = mono_get_delegate_invoke (delegate->vtable->klass);
2708 return mono_runtime_invoke (im, delegate, params, exc);
2711 static char **main_args = NULL;
2712 static int num_main_args;
2715 * mono_runtime_get_main_args:
2717 * Returns: a MonoArray with the arguments passed to the main program
2720 mono_runtime_get_main_args (void)
2724 MonoDomain *domain = mono_domain_get ();
2729 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2731 for (i = 0; i < num_main_args; ++i)
2732 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2738 fire_process_exit_event (void)
2740 MonoClassField *field;
2741 MonoDomain *domain = mono_domain_get ();
2743 MonoObject *delegate, *exc;
2745 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2748 if (domain != mono_get_root_domain ())
2751 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2752 if (delegate == NULL)
2757 mono_runtime_delegate_invoke (delegate, pa, &exc);
2761 * mono_runtime_run_main:
2762 * @method: the method to start the application with (usually Main)
2763 * @argc: number of arguments from the command line
2764 * @argv: array of strings from the command line
2765 * @exc: excetption results
2767 * Execute a standard Main() method (argc/argv contains the
2768 * executable name). This method also sets the command line argument value
2769 * needed by System.Environment.
2774 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2778 MonoArray *args = NULL;
2779 MonoDomain *domain = mono_domain_get ();
2780 gchar *utf8_fullpath;
2783 g_assert (method != NULL);
2785 mono_thread_set_main (mono_thread_current ());
2787 main_args = g_new0 (char*, argc);
2788 num_main_args = argc;
2790 if (!g_path_is_absolute (argv [0])) {
2791 gchar *basename = g_path_get_basename (argv [0]);
2792 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2796 utf8_fullpath = mono_utf8_from_external (fullpath);
2797 if(utf8_fullpath == NULL) {
2798 /* Printing the arg text will cause glib to
2799 * whinge about "Invalid UTF-8", but at least
2800 * its relevant, and shows the problem text
2803 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2804 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2811 utf8_fullpath = mono_utf8_from_external (argv[0]);
2812 if(utf8_fullpath == NULL) {
2813 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2814 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2819 main_args [0] = utf8_fullpath;
2821 for (i = 1; i < argc; ++i) {
2824 utf8_arg=mono_utf8_from_external (argv[i]);
2825 if(utf8_arg==NULL) {
2826 /* Ditto the comment about Invalid UTF-8 here */
2827 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2828 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2832 main_args [i] = utf8_arg;
2836 if (mono_method_signature (method)->param_count) {
2837 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2838 for (i = 0; i < argc; ++i) {
2839 /* The encodings should all work, given that
2840 * we've checked all these args for the
2843 gchar *str = mono_utf8_from_external (argv [i]);
2844 MonoString *arg = mono_string_new (domain, str);
2845 mono_array_setref (args, i, arg);
2849 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2852 mono_assembly_set_main (method->klass->image->assembly);
2854 result = mono_runtime_exec_main (method, args, exc);
2855 fire_process_exit_event ();
2859 /* Used in call_unhandled_exception_delegate */
2861 create_unhandled_exception_eventargs (MonoObject *exc)
2865 MonoMethod *method = NULL;
2866 MonoBoolean is_terminating = TRUE;
2869 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2872 mono_class_init (klass);
2874 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2875 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2879 args [1] = &is_terminating;
2881 obj = mono_object_new (mono_domain_get (), klass);
2882 mono_runtime_invoke (method, obj, args, NULL);
2887 /* Used in mono_unhandled_exception */
2889 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2890 MonoObject *e = NULL;
2893 pa [0] = domain->domain;
2894 pa [1] = create_unhandled_exception_eventargs (exc);
2895 mono_runtime_delegate_invoke (delegate, pa, &e);
2898 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2899 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2904 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2907 * mono_runtime_unhandled_exception_policy_set:
2908 * @policy: the new policy
2910 * This is a VM internal routine.
2912 * Sets the runtime policy for handling unhandled exceptions.
2915 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2916 runtime_unhandled_exception_policy = policy;
2920 * mono_runtime_unhandled_exception_policy_get:
2922 * This is a VM internal routine.
2924 * Gets the runtime policy for handling unhandled exceptions.
2926 MonoRuntimeUnhandledExceptionPolicy
2927 mono_runtime_unhandled_exception_policy_get (void) {
2928 return runtime_unhandled_exception_policy;
2932 * mono_unhandled_exception:
2933 * @exc: exception thrown
2935 * This is a VM internal routine.
2937 * We call this function when we detect an unhandled exception
2938 * in the default domain.
2940 * It invokes the * UnhandledException event in AppDomain or prints
2941 * a warning to the console
2944 mono_unhandled_exception (MonoObject *exc)
2946 MonoDomain *current_domain = mono_domain_get ();
2947 MonoDomain *root_domain = mono_get_root_domain ();
2948 MonoClassField *field;
2949 MonoObject *current_appdomain_delegate;
2950 MonoObject *root_appdomain_delegate;
2952 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2953 "UnhandledException");
2956 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2957 gboolean abort_process = (mono_thread_current () == main_thread) ||
2958 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2959 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2960 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2961 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2963 current_appdomain_delegate = NULL;
2966 /* set exitcode only if we will abort the process */
2968 mono_environment_exitcode_set (1);
2969 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2970 mono_print_unhandled_exception (exc);
2972 if (root_appdomain_delegate) {
2973 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2975 if (current_appdomain_delegate) {
2976 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2983 * Launch a new thread to execute a function
2985 * main_func is called back from the thread with main_args as the
2986 * parameter. The callback function is expected to start Main()
2987 * eventually. This function then waits for all managed threads to
2989 * It is not necesseray anymore to execute managed code in a subthread,
2990 * so this function should not be used anymore by default: just
2991 * execute the code and then call mono_thread_manage ().
2994 mono_runtime_exec_managed_code (MonoDomain *domain,
2995 MonoMainThreadFunc main_func,
2998 mono_thread_create (domain, main_func, main_args);
3000 mono_thread_manage ();
3004 * Execute a standard Main() method (args doesn't contain the
3008 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3013 MonoCustomAttrInfo* cinfo;
3014 gboolean has_stathread_attribute;
3015 MonoThread* thread = mono_thread_current ();
3021 domain = mono_object_domain (args);
3022 if (!domain->entry_assembly) {
3024 MonoAssembly *assembly;
3026 assembly = method->klass->image->assembly;
3027 domain->entry_assembly = assembly;
3028 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3030 str = g_strconcat (assembly->image->name, ".config", NULL);
3031 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3035 cinfo = mono_custom_attrs_from_method (method);
3037 static MonoClass *stathread_attribute = NULL;
3038 if (!stathread_attribute)
3039 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3040 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3042 mono_custom_attrs_free (cinfo);
3044 has_stathread_attribute = FALSE;
3046 if (has_stathread_attribute) {
3047 thread->apartment_state = ThreadApartmentState_STA;
3048 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
3049 thread->apartment_state = ThreadApartmentState_Unknown;
3051 thread->apartment_state = ThreadApartmentState_MTA;
3053 mono_thread_init_apartment_state ();
3055 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3057 /* FIXME: check signature of method */
3058 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3060 res = mono_runtime_invoke (method, NULL, pa, exc);
3062 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3066 mono_environment_exitcode_set (rval);
3068 mono_runtime_invoke (method, NULL, pa, exc);
3072 /* If the return type of Main is void, only
3073 * set the exitcode if an exception was thrown
3074 * (we don't want to blow away an
3075 * explicitly-set exit code)
3078 mono_environment_exitcode_set (rval);
3082 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3088 * mono_install_runtime_invoke:
3089 * @func: Function to install
3091 * This is a VM internal routine
3094 mono_install_runtime_invoke (MonoInvokeFunc func)
3096 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3101 * mono_runtime_invoke_array:
3102 * @method: method to invoke
3103 * @obJ: object instance
3104 * @params: arguments to the method
3105 * @exc: exception information.
3107 * Invokes the method represented by @method on the object @obj.
3109 * obj is the 'this' pointer, it should be NULL for static
3110 * methods, a MonoObject* for object instances and a pointer to
3111 * the value type for value types.
3113 * The params array contains the arguments to the method with the
3114 * same convention: MonoObject* pointers for object instances and
3115 * pointers to the value type otherwise. The _invoke_array
3116 * variant takes a C# object[] as the params argument (MonoArray
3117 * *params): in this case the value types are boxed inside the
3118 * respective reference representation.
3120 * From unmanaged code you'll usually use the
3121 * mono_runtime_invoke() variant.
3123 * Note that this function doesn't handle virtual methods for
3124 * you, it will exec the exact method you pass: we still need to
3125 * expose a function to lookup the derived class implementation
3126 * of a virtual method (there are examples of this in the code,
3129 * You can pass NULL as the exc argument if you don't want to
3130 * catch exceptions, otherwise, *exc will be set to the exception
3131 * thrown, if any. if an exception is thrown, you can't use the
3132 * MonoObject* result from the function.
3134 * If the method returns a value type, it is boxed in an object
3138 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3141 MonoMethodSignature *sig = mono_method_signature (method);
3142 gpointer *pa = NULL;
3145 if (NULL != params) {
3146 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3147 for (i = 0; i < mono_array_length (params); i++) {
3148 MonoType *t = sig->params [i];
3154 case MONO_TYPE_BOOLEAN:
3157 case MONO_TYPE_CHAR:
3166 case MONO_TYPE_VALUETYPE:
3167 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3170 g_assert_not_reached ();
3171 /* The runtime invoke wrapper needs the original boxed vtype */
3172 pa [i] = mono_array_get (params, MonoObject*, i);
3174 /* MS seems to create the objects if a null is passed in */
3175 if (!mono_array_get (params, MonoObject*, i))
3176 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3180 * We can't pass the unboxed vtype byref to the callee, since
3181 * that would mean the callee would be able to modify boxed
3182 * primitive types. So we (and MS) make a copy of the boxed
3183 * object, pass that to the callee, and replace the original
3184 * boxed object in the arg array with the copy.
3186 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3187 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3188 mono_array_setref (params, i, copy);
3191 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3194 case MONO_TYPE_STRING:
3195 case MONO_TYPE_OBJECT:
3196 case MONO_TYPE_CLASS:
3197 case MONO_TYPE_ARRAY:
3198 case MONO_TYPE_SZARRAY:
3200 pa [i] = mono_array_addr (params, MonoObject*, i);
3201 // FIXME: I need to check this code path
3203 pa [i] = mono_array_get (params, MonoObject*, i);
3205 case MONO_TYPE_GENERICINST:
3207 t = &t->data.generic_class->container_class->this_arg;
3209 t = &t->data.generic_class->container_class->byval_arg;
3212 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3217 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3220 if (mono_class_is_nullable (method->klass)) {
3221 /* Need to create a boxed vtype instead */
3227 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3231 obj = mono_object_new (mono_domain_get (), method->klass);
3232 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3233 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3235 if (method->klass->valuetype)
3236 o = mono_object_unbox (obj);
3239 } else if (method->klass->valuetype) {
3240 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3243 mono_runtime_invoke (method, o, pa, exc);
3246 if (mono_class_is_nullable (method->klass)) {
3247 MonoObject *nullable;
3249 /* Convert the unboxed vtype into a Nullable structure */
3250 nullable = mono_object_new (mono_domain_get (), method->klass);
3252 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3253 obj = mono_object_unbox (nullable);
3256 /* obj must be already unboxed if needed */
3257 return mono_runtime_invoke (method, obj, pa, exc);
3262 arith_overflow (void)
3264 mono_raise_exception (mono_get_exception_overflow ());
3268 * mono_object_allocate:
3269 * @size: number of bytes to allocate
3271 * This is a very simplistic routine until we have our GC-aware
3274 * Returns: an allocated object of size @size, or NULL on failure.
3276 static inline void *
3277 mono_object_allocate (size_t size, MonoVTable *vtable)
3280 mono_stats.new_object_count++;
3281 ALLOC_OBJECT (o, vtable, size);
3287 * mono_object_allocate_ptrfree:
3288 * @size: number of bytes to allocate
3290 * Note that the memory allocated is not zeroed.
3291 * Returns: an allocated object of size @size, or NULL on failure.
3293 static inline void *
3294 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3297 mono_stats.new_object_count++;
3298 ALLOC_PTRFREE (o, vtable, size);
3302 static inline void *
3303 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3306 ALLOC_TYPED (o, size, vtable);
3307 mono_stats.new_object_count++;
3314 * @klass: the class of the object that we want to create
3316 * Returns: a newly created object whose definition is
3317 * looked up using @klass. This will not invoke any constructors,
3318 * so the consumer of this routine has to invoke any constructors on
3319 * its own to initialize the object.
3322 mono_object_new (MonoDomain *domain, MonoClass *klass)
3324 MONO_ARCH_SAVE_REGS;
3325 return mono_object_new_specific (mono_class_vtable (domain, klass));
3329 * mono_object_new_specific:
3330 * @vtable: the vtable of the object that we want to create
3332 * Returns: A newly created object with class and domain specified
3336 mono_object_new_specific (MonoVTable *vtable)
3340 MONO_ARCH_SAVE_REGS;
3342 /* check for is_com_object for COM Interop */
3343 if (vtable->remote || vtable->klass->is_com_object)
3346 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3349 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3352 mono_class_init (klass);
3354 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3356 vtable->domain->create_proxy_for_type_method = im;
3359 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3361 o = mono_runtime_invoke (im, NULL, pa, NULL);
3362 if (o != NULL) return o;
3365 return mono_object_new_alloc_specific (vtable);
3369 mono_object_new_alloc_specific (MonoVTable *vtable)
3373 if (!vtable->klass->has_references) {
3374 o = mono_object_new_ptrfree (vtable);
3375 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3376 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3378 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3379 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3381 if (G_UNLIKELY (vtable->klass->has_finalize))
3382 mono_object_register_finalizer (o);
3384 if (G_UNLIKELY (profile_allocs))
3385 mono_profiler_allocation (o, vtable->klass);
3390 mono_object_new_fast (MonoVTable *vtable)
3393 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3398 mono_object_new_ptrfree (MonoVTable *vtable)
3401 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3402 #if NEED_TO_ZERO_PTRFREE
3403 /* an inline memset is much faster for the common vcase of small objects
3404 * note we assume the allocated size is a multiple of sizeof (void*).
3406 if (vtable->klass->instance_size < 128) {
3408 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3409 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3415 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3422 mono_object_new_ptrfree_box (MonoVTable *vtable)
3425 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3426 /* the object will be boxed right away, no need to memzero it */
3431 * mono_class_get_allocation_ftn:
3433 * @for_box: the object will be used for boxing
3434 * @pass_size_in_words:
3436 * Return the allocation function appropriate for the given class.
3440 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3442 *pass_size_in_words = FALSE;
3444 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3445 profile_allocs = FALSE;
3447 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3448 return mono_object_new_specific;
3450 if (!vtable->klass->has_references) {
3451 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3453 return mono_object_new_ptrfree_box;
3454 return mono_object_new_ptrfree;
3457 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3459 return mono_object_new_fast;
3462 * FIXME: This is actually slower than mono_object_new_fast, because
3463 * of the overhead of parameter passing.
3466 *pass_size_in_words = TRUE;
3467 #ifdef GC_REDIRECT_TO_LOCAL
3468 return GC_local_gcj_fast_malloc;
3470 return GC_gcj_fast_malloc;
3475 return mono_object_new_specific;
3479 * mono_object_new_from_token:
3480 * @image: Context where the type_token is hosted
3481 * @token: a token of the type that we want to create
3483 * Returns: A newly created object whose definition is
3484 * looked up using @token in the @image image
3487 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3491 class = mono_class_get (image, token);
3493 return mono_object_new (domain, class);
3498 * mono_object_clone:
3499 * @obj: the object to clone
3501 * Returns: A newly created object who is a shallow copy of @obj
3504 mono_object_clone (MonoObject *obj)
3509 size = obj->vtable->klass->instance_size;
3510 o = mono_object_allocate (size, obj->vtable);
3511 /* do not copy the sync state */
3512 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3515 if (obj->vtable->klass->has_references)
3516 mono_gc_wbarrier_object (o);
3518 if (G_UNLIKELY (profile_allocs))
3519 mono_profiler_allocation (o, obj->vtable->klass);
3521 if (obj->vtable->klass->has_finalize)
3522 mono_object_register_finalizer (o);
3527 * mono_array_full_copy:
3528 * @src: source array to copy
3529 * @dest: destination array
3531 * Copies the content of one array to another with exactly the same type and size.
3534 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3536 mono_array_size_t size;
3537 MonoClass *klass = src->obj.vtable->klass;
3539 MONO_ARCH_SAVE_REGS;
3541 g_assert (klass == dest->obj.vtable->klass);
3543 size = mono_array_length (src);
3544 g_assert (size == mono_array_length (dest));
3545 size *= mono_array_element_size (klass);
3547 if (klass->element_class->valuetype) {
3548 if (klass->element_class->has_references)
3549 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3551 memcpy (&dest->vector, &src->vector, size);
3553 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3556 memcpy (&dest->vector, &src->vector, size);
3561 * mono_array_clone_in_domain:
3562 * @domain: the domain in which the array will be cloned into
3563 * @array: the array to clone
3565 * This routine returns a copy of the array that is hosted on the
3566 * specified MonoDomain.
3569 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3572 mono_array_size_t size, i;
3573 mono_array_size_t *sizes;
3574 MonoClass *klass = array->obj.vtable->klass;
3576 MONO_ARCH_SAVE_REGS;
3578 if (array->bounds == NULL) {
3579 size = mono_array_length (array);
3580 o = mono_array_new_full (domain, klass, &size, NULL);
3582 size *= mono_array_element_size (klass);
3584 if (klass->element_class->valuetype) {
3585 if (klass->element_class->has_references)
3586 mono_value_copy_array (o, 0, array, mono_array_length (array));
3588 memcpy (&o->vector, &array->vector, size);
3590 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3593 memcpy (&o->vector, &array->vector, size);
3598 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3599 size = mono_array_element_size (klass);
3600 for (i = 0; i < klass->rank; ++i) {
3601 sizes [i] = array->bounds [i].length;
3602 size *= array->bounds [i].length;
3603 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3605 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3607 if (klass->element_class->valuetype) {
3608 if (klass->element_class->has_references)
3609 mono_value_copy_array (o, 0, array, mono_array_length (array));
3611 memcpy (&o->vector, &array->vector, size);
3613 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3616 memcpy (&o->vector, &array->vector, size);
3624 * @array: the array to clone
3626 * Returns: A newly created array who is a shallow copy of @array
3629 mono_array_clone (MonoArray *array)
3631 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3634 /* helper macros to check for overflow when calculating the size of arrays */
3635 #ifdef MONO_BIG_ARRAYS
3636 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3637 #define MYGUINT_MAX MYGUINT64_MAX
3638 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3639 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3640 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3641 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3642 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3644 #define MYGUINT32_MAX 4294967295U
3645 #define MYGUINT_MAX MYGUINT32_MAX
3646 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3647 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3648 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3649 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3650 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3654 * mono_array_new_full:
3655 * @domain: domain where the object is created
3656 * @array_class: array class
3657 * @lengths: lengths for each dimension in the array
3658 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3660 * This routine creates a new array objects with the given dimensions,
3661 * lower bounds and type.
3664 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3666 mono_array_size_t byte_len, len, bounds_size;
3672 if (!array_class->inited)
3673 mono_class_init (array_class);
3675 byte_len = mono_array_element_size (array_class);
3678 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3679 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3681 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3685 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3687 for (i = 0; i < array_class->rank; ++i) {
3688 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3690 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3691 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3696 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3697 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3699 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3700 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3701 byte_len += sizeof (MonoArray);
3704 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3705 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3706 byte_len = (byte_len + 3) & ~3;
3707 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3708 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3709 byte_len += bounds_size;
3712 * Following three lines almost taken from mono_object_new ():
3713 * they need to be kept in sync.
3715 vtable = mono_class_vtable (domain, array_class);
3716 if (!array_class->has_references) {
3717 o = mono_object_allocate_ptrfree (byte_len, vtable);
3718 #if NEED_TO_ZERO_PTRFREE
3719 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3721 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3722 o = mono_object_allocate_spec (byte_len, vtable);
3724 o = mono_object_allocate (byte_len, vtable);
3727 array = (MonoArray*)o;
3728 array->max_length = len;
3731 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3732 array->bounds = bounds;
3733 for (i = 0; i < array_class->rank; ++i) {
3734 bounds [i].length = lengths [i];
3736 bounds [i].lower_bound = lower_bounds [i];
3740 if (G_UNLIKELY (profile_allocs))
3741 mono_profiler_allocation (o, array_class);
3748 * @domain: domain where the object is created
3749 * @eclass: element class
3750 * @n: number of array elements
3752 * This routine creates a new szarray with @n elements of type @eclass.
3755 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3759 MONO_ARCH_SAVE_REGS;
3761 ac = mono_array_class_get (eclass, 1);
3764 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3768 * mono_array_new_specific:
3769 * @vtable: a vtable in the appropriate domain for an initialized class
3770 * @n: number of array elements
3772 * This routine is a fast alternative to mono_array_new() for code which
3773 * can be sure about the domain it operates in.
3776 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
3780 guint32 byte_len, elem_size;
3782 MONO_ARCH_SAVE_REGS;
3784 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
3789 elem_size = mono_array_element_size (vtable->klass);
3790 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
3791 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3794 byte_len = n * elem_size;
3795 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
3796 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3799 byte_len += sizeof (MonoArray);
3800 if (!vtable->klass->has_references) {
3801 o = mono_object_allocate_ptrfree (byte_len, vtable);
3802 #if NEED_TO_ZERO_PTRFREE
3803 ((MonoArray*)o)->bounds = NULL;
3804 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3806 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3807 o = mono_object_allocate_spec (byte_len, vtable);
3809 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3810 o = mono_object_allocate (byte_len, vtable);
3813 ao = (MonoArray *)o;
3815 if (G_UNLIKELY (profile_allocs))
3816 mono_profiler_allocation (o, vtable->klass);
3822 * mono_string_new_utf16:
3823 * @text: a pointer to an utf16 string
3824 * @len: the length of the string
3826 * Returns: A newly created string object which contains @text.
3829 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3833 s = mono_string_new_size (domain, len);
3834 g_assert (s != NULL);
3836 memcpy (mono_string_chars (s), text, len * 2);
3842 * mono_string_new_size:
3843 * @text: a pointer to an utf16 string
3844 * @len: the length of the string
3846 * Returns: A newly created string object of @len
3849 mono_string_new_size (MonoDomain *domain, gint32 len)
3853 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3855 /* overflow ? can't fit it, can't allocate it! */
3857 mono_gc_out_of_memory (-1);
3859 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3861 s = mono_object_allocate_ptrfree (size, vtable);
3864 #if NEED_TO_ZERO_PTRFREE
3867 if (G_UNLIKELY (profile_allocs))
3868 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3874 * mono_string_new_len:
3875 * @text: a pointer to an utf8 string
3876 * @length: number of bytes in @text to consider
3878 * Returns: A newly created string object which contains @text.
3881 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3883 GError *error = NULL;
3884 MonoString *o = NULL;
3886 glong items_written;
3888 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3891 o = mono_string_new_utf16 (domain, ut, items_written);
3893 g_error_free (error);
3902 * @text: a pointer to an utf8 string
3904 * Returns: A newly created string object which contains @text.
3907 mono_string_new (MonoDomain *domain, const char *text)
3909 GError *error = NULL;
3910 MonoString *o = NULL;
3912 glong items_written;
3917 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3920 o = mono_string_new_utf16 (domain, ut, items_written);
3922 g_error_free (error);
3925 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
3930 MonoString *o = NULL;
3932 if (!g_utf8_validate (text, -1, &end))
3935 len = g_utf8_strlen (text, -1);
3936 o = mono_string_new_size (domain, len);
3937 str = mono_string_chars (o);
3939 while (text < end) {
3940 *str++ = g_utf8_get_char (text);
3941 text = g_utf8_next_char (text);
3948 * mono_string_new_wrapper:
3949 * @text: pointer to utf8 characters.
3951 * Helper function to create a string object from @text in the current domain.
3954 mono_string_new_wrapper (const char *text)
3956 MonoDomain *domain = mono_domain_get ();
3958 MONO_ARCH_SAVE_REGS;
3961 return mono_string_new (domain, text);
3968 * @class: the class of the value
3969 * @value: a pointer to the unboxed data
3971 * Returns: A newly created object which contains @value.
3974 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3980 g_assert (class->valuetype);
3981 if (mono_class_is_nullable (class))
3982 return mono_nullable_box (value, class);
3984 vtable = mono_class_vtable (domain, class);
3985 size = mono_class_instance_size (class);
3986 res = mono_object_new_alloc_specific (vtable);
3987 if (G_UNLIKELY (profile_allocs))
3988 mono_profiler_allocation (res, class);
3990 size = size - sizeof (MonoObject);
3993 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3996 #if NO_UNALIGNED_ACCESS
3997 memcpy ((char *)res + sizeof (MonoObject), value, size);
4001 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4004 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4007 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4010 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4013 memcpy ((char *)res + sizeof (MonoObject), value, size);
4016 if (class->has_finalize)
4017 mono_object_register_finalizer (res);
4023 * @dest: destination pointer
4024 * @src: source pointer
4025 * @klass: a valuetype class
4027 * Copy a valuetype from @src to @dest. This function must be used
4028 * when @klass contains references fields.
4031 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4033 int size = mono_class_value_size (klass, NULL);
4034 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4035 memcpy (dest, src, size);
4039 * mono_value_copy_array:
4040 * @dest: destination array
4041 * @dest_idx: index in the @dest array
4042 * @src: source pointer
4043 * @count: number of items
4045 * Copy @count valuetype items from @src to @dest. This function must be used
4046 * when @klass contains references fields.
4047 * Overlap is handled.
4050 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4052 int size = mono_array_element_size (dest->obj.vtable->klass);
4053 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4054 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4055 memmove (d, src, size * count);
4059 * mono_object_get_domain:
4060 * @obj: object to query
4062 * Returns: the MonoDomain where the object is hosted
4065 mono_object_get_domain (MonoObject *obj)
4067 return mono_object_domain (obj);
4071 * mono_object_get_class:
4072 * @obj: object to query
4074 * Returns: the MonOClass of the object.
4077 mono_object_get_class (MonoObject *obj)
4079 return mono_object_class (obj);
4082 * mono_object_get_size:
4083 * @o: object to query
4085 * Returns: the size, in bytes, of @o
4088 mono_object_get_size (MonoObject* o)
4090 MonoClass* klass = mono_object_class (o);
4091 if (klass == mono_defaults.string_class) {
4092 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4093 } else if (o->vtable->rank) {
4094 MonoArray *array = (MonoArray*)o;
4095 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4096 if (array->bounds) {
4099 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4103 return mono_class_instance_size (klass);
4108 * mono_object_unbox:
4109 * @obj: object to unbox
4111 * Returns: a pointer to the start of the valuetype boxed in this
4114 * This method will assert if the object passed is not a valuetype.
4117 mono_object_unbox (MonoObject *obj)
4119 /* add assert for valuetypes? */
4120 g_assert (obj->vtable->klass->valuetype);
4121 return ((char*)obj) + sizeof (MonoObject);
4125 * mono_object_isinst:
4127 * @klass: a pointer to a class
4129 * Returns: @obj if @obj is derived from @klass
4132 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4135 mono_class_init (klass);
4137 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4138 return mono_object_isinst_mbyref (obj, klass);
4143 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4147 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4156 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4157 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4161 MonoClass *oklass = vt->klass;
4162 if ((oklass == mono_defaults.transparent_proxy_class))
4163 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4165 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4169 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4171 MonoDomain *domain = mono_domain_get ();
4173 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4174 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4175 MonoMethod *im = NULL;
4178 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4179 im = mono_object_get_virtual_method (rp, im);
4182 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4185 res = mono_runtime_invoke (im, rp, pa, NULL);
4187 if (*(MonoBoolean *) mono_object_unbox(res)) {
4188 /* Update the vtable of the remote type, so it can safely cast to this new type */
4189 mono_upgrade_remote_class (domain, obj, klass);
4198 * mono_object_castclass_mbyref:
4200 * @klass: a pointer to a class
4202 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4205 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4207 if (!obj) return NULL;
4208 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4210 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4212 "InvalidCastException"));
4217 MonoDomain *orig_domain;
4223 str_lookup (MonoDomain *domain, gpointer user_data)
4225 LDStrInfo *info = user_data;
4226 if (info->res || domain == info->orig_domain)
4228 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4234 mono_string_get_pinned (MonoString *str)
4238 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4239 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4240 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4241 news->length = mono_string_length (str);
4246 #define mono_string_get_pinned(str) (str)
4250 mono_string_is_interned_lookup (MonoString *str, int insert)
4252 MonoGHashTable *ldstr_table;
4256 domain = ((MonoObject *)str)->vtable->domain;
4257 ldstr_table = domain->ldstr_table;
4259 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4264 str = mono_string_get_pinned (str);
4265 mono_g_hash_table_insert (ldstr_table, str, str);
4269 LDStrInfo ldstr_info;
4270 ldstr_info.orig_domain = domain;
4271 ldstr_info.ins = str;
4272 ldstr_info.res = NULL;
4274 mono_domain_foreach (str_lookup, &ldstr_info);
4275 if (ldstr_info.res) {
4277 * the string was already interned in some other domain:
4278 * intern it in the current one as well.
4280 mono_g_hash_table_insert (ldstr_table, str, str);
4290 * mono_string_is_interned:
4291 * @o: String to probe
4293 * Returns whether the string has been interned.
4296 mono_string_is_interned (MonoString *o)
4298 return mono_string_is_interned_lookup (o, FALSE);
4302 * mono_string_intern:
4303 * @o: String to intern
4305 * Interns the string passed.
4306 * Returns: The interned string.
4309 mono_string_intern (MonoString *str)
4311 return mono_string_is_interned_lookup (str, TRUE);
4316 * @domain: the domain where the string will be used.
4317 * @image: a metadata context
4318 * @idx: index into the user string table.
4320 * Implementation for the ldstr opcode.
4321 * Returns: a loaded string from the @image/@idx combination.
4324 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4326 MONO_ARCH_SAVE_REGS;
4329 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4331 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4335 * mono_ldstr_metadata_sig
4336 * @domain: the domain for the string
4337 * @sig: the signature of a metadata string
4339 * Returns: a MonoString for a string stored in the metadata
4342 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4344 const char *str = sig;
4345 MonoString *o, *interned;
4348 len2 = mono_metadata_decode_blob_size (str, &str);
4351 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4352 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4355 guint16 *p2 = (guint16*)mono_string_chars (o);
4356 for (i = 0; i < len2; ++i) {
4357 *p2 = GUINT16_FROM_LE (*p2);
4363 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4365 /* o will get garbage collected */
4369 o = mono_string_get_pinned (o);
4370 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4377 * mono_string_to_utf8:
4378 * @s: a System.String
4380 * Return the UTF8 representation for @s.
4381 * the resulting buffer nedds to be freed with g_free().
4384 mono_string_to_utf8 (MonoString *s)
4388 GError *error = NULL;
4394 return g_strdup ("");
4396 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4398 MonoException *exc = mono_get_exception_argument ("string", error->message);
4399 g_error_free (error);
4400 mono_raise_exception(exc);
4402 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4403 if (s->length > written) {
4404 /* allocate the total length and copy the part of the string that has been converted */
4405 char *as2 = g_malloc0 (s->length);
4406 memcpy (as2, as, written);
4415 * mono_string_to_utf16:
4418 * Return an null-terminated array of the utf-16 chars
4419 * contained in @s. The result must be freed with g_free().
4420 * This is a temporary helper until our string implementation
4421 * is reworked to always include the null terminating char.
4424 mono_string_to_utf16 (MonoString *s)
4431 as = g_malloc ((s->length * 2) + 2);
4432 as [(s->length * 2)] = '\0';
4433 as [(s->length * 2) + 1] = '\0';
4436 return (gunichar2 *)(as);
4439 memcpy (as, mono_string_chars(s), s->length * 2);
4440 return (gunichar2 *)(as);
4444 * mono_string_from_utf16:
4445 * @data: the UTF16 string (LPWSTR) to convert
4447 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4449 * Returns: a MonoString.
4452 mono_string_from_utf16 (gunichar2 *data)
4454 MonoDomain *domain = mono_domain_get ();
4460 while (data [len]) len++;
4462 return mono_string_new_utf16 (domain, data, len);
4466 * mono_string_to_utf8_mp:
4467 * @s: a System.String
4469 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4472 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4474 char *r = mono_string_to_utf8 (s);
4481 len = strlen (r) + 1;
4482 mp_s = mono_mempool_alloc (mp, len);
4483 memcpy (mp_s, r, len);
4491 default_ex_handler (MonoException *ex)
4493 MonoObject *o = (MonoObject*)ex;
4494 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4498 static MonoExceptionFunc ex_handler = default_ex_handler;
4501 * mono_install_handler:
4502 * @func: exception handler
4504 * This is an internal JIT routine used to install the handler for exceptions
4508 mono_install_handler (MonoExceptionFunc func)
4510 ex_handler = func? func: default_ex_handler;
4514 * mono_raise_exception:
4515 * @ex: exception object
4517 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4520 mono_raise_exception (MonoException *ex)
4523 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4524 * that will cause gcc to omit the function epilog, causing problems when
4525 * the JIT tries to walk the stack, since the return address on the stack
4526 * will point into the next function in the executable, not this one.
4529 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4530 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4536 * mono_wait_handle_new:
4537 * @domain: Domain where the object will be created
4538 * @handle: Handle for the wait handle
4540 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4543 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4545 MonoWaitHandle *res;
4546 gpointer params [1];
4547 static MonoMethod *handle_set;
4549 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4551 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4553 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4555 params [0] = &handle;
4556 mono_runtime_invoke (handle_set, res, params, NULL);
4562 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4564 static MonoClassField *f_os_handle;
4565 static MonoClassField *f_safe_handle;
4567 if (!f_os_handle && !f_safe_handle) {
4568 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4569 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4574 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4578 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4584 * mono_async_result_new:
4585 * @domain:domain where the object will be created.
4586 * @handle: wait handle.
4587 * @state: state to pass to AsyncResult
4588 * @data: C closure data.
4590 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4591 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4595 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4597 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4598 MonoMethod *method = mono_get_context_capture_method ();
4600 /* we must capture the execution context from the original thread */
4602 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4603 /* note: result may be null if the flow is suppressed */
4607 MONO_OBJECT_SETREF (res, object_data, object_data);
4608 MONO_OBJECT_SETREF (res, async_state, state);
4610 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4612 res->sync_completed = FALSE;
4613 res->completed = FALSE;
4619 mono_message_init (MonoDomain *domain,
4620 MonoMethodMessage *this,
4621 MonoReflectionMethod *method,
4622 MonoArray *out_args)
4624 static MonoClass *object_array_klass;
4625 static MonoClass *byte_array_klass;
4626 static MonoClass *string_array_klass;
4627 MonoMethodSignature *sig = mono_method_signature (method->method);
4633 if (!object_array_klass) {
4636 klass = mono_array_class_get (mono_defaults.object_class, 1);
4639 mono_memory_barrier ();
4640 object_array_klass = klass;
4642 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4645 mono_memory_barrier ();
4646 byte_array_klass = klass;
4648 klass = mono_array_class_get (mono_defaults.string_class, 1);
4651 mono_memory_barrier ();
4652 string_array_klass = klass;
4655 MONO_OBJECT_SETREF (this, method, method);
4657 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4658 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4659 this->async_result = NULL;
4660 this->call_type = CallType_Sync;
4662 names = g_new (char *, sig->param_count);
4663 mono_method_get_param_names (method->method, (const char **) names);
4664 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4666 for (i = 0; i < sig->param_count; i++) {
4667 name = mono_string_new (domain, names [i]);
4668 mono_array_setref (this->names, i, name);
4672 for (i = 0, j = 0; i < sig->param_count; i++) {
4673 if (sig->params [i]->byref) {
4675 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4676 mono_array_setref (this->args, i, arg);
4680 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4684 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4687 mono_array_set (this->arg_types, guint8, i, arg_type);
4692 * mono_remoting_invoke:
4693 * @real_proxy: pointer to a RealProxy object
4694 * @msg: The MonoMethodMessage to execute
4695 * @exc: used to store exceptions
4696 * @out_args: used to store output arguments
4698 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4699 * IMessage interface and it is not trivial to extract results from there. So
4700 * we call an helper method PrivateInvoke instead of calling
4701 * RealProxy::Invoke() directly.
4703 * Returns: the result object.
4706 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4707 MonoObject **exc, MonoArray **out_args)
4709 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4712 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4715 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4717 real_proxy->vtable->domain->private_invoke_method = im;
4720 pa [0] = real_proxy;
4725 return mono_runtime_invoke (im, NULL, pa, exc);
4729 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4730 MonoObject **exc, MonoArray **out_args)
4732 static MonoClass *object_array_klass;
4735 MonoMethodSignature *sig;
4737 int i, j, outarg_count = 0;
4739 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4741 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4742 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4743 target = tp->rp->unwrapped_server;
4745 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4749 domain = mono_domain_get ();
4750 method = msg->method->method;
4751 sig = mono_method_signature (method);
4753 for (i = 0; i < sig->param_count; i++) {
4754 if (sig->params [i]->byref)
4758 if (!object_array_klass) {
4761 klass = mono_array_class_get (mono_defaults.object_class, 1);
4764 mono_memory_barrier ();
4765 object_array_klass = klass;
4768 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4769 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
4772 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4774 for (i = 0, j = 0; i < sig->param_count; i++) {
4775 if (sig->params [i]->byref) {
4777 arg = mono_array_get (msg->args, gpointer, i);
4778 mono_array_setref (*out_args, j, arg);
4787 * mono_print_unhandled_exception:
4788 * @exc: The exception
4790 * Prints the unhandled exception.
4793 mono_print_unhandled_exception (MonoObject *exc)
4795 char *message = (char *) "";
4799 gboolean free_message = FALSE;
4801 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4802 klass = exc->vtable->klass;
4804 while (klass && method == NULL) {
4805 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4807 klass = klass->parent;
4812 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4814 message = mono_string_to_utf8 (str);
4815 free_message = TRUE;
4820 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4821 * exc->vtable->klass->name, message);
4823 g_printerr ("\nUnhandled Exception: %s\n", message);
4830 * mono_delegate_ctor:
4831 * @this: pointer to an uninitialized delegate object
4832 * @target: target object
4833 * @addr: pointer to native code
4836 * Initialize a delegate and sets a specific method, not the one
4837 * associated with addr. This is useful when sharing generic code.
4838 * In that case addr will most probably not be associated with the
4839 * correct instantiation of the method.
4842 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
4844 MonoDelegate *delegate = (MonoDelegate *)this;
4851 delegate->method = method;
4853 class = this->vtable->klass;
4854 mono_stats.delegate_creations++;
4856 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4858 method = mono_marshal_get_remoting_invoke (method);
4859 delegate->method_ptr = mono_compile_method (method);
4860 MONO_OBJECT_SETREF (delegate, target, target);
4861 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4862 method = mono_marshal_get_unbox_wrapper (method);
4863 delegate->method_ptr = mono_compile_method (method);
4864 MONO_OBJECT_SETREF (delegate, target, target);
4866 delegate->method_ptr = addr;
4867 MONO_OBJECT_SETREF (delegate, target, target);
4870 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4874 * mono_delegate_ctor:
4875 * @this: pointer to an uninitialized delegate object
4876 * @target: target object
4877 * @addr: pointer to native code
4879 * This is used to initialize a delegate.
4882 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4884 MonoDomain *domain = mono_domain_get ();
4886 MonoMethod *method = NULL;
4890 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4891 method = ji->method;
4892 g_assert (!method->klass->generic_container);
4895 mono_delegate_ctor_with_method (this, target, addr, method);
4899 * mono_method_call_message_new:
4900 * @method: method to encapsulate
4901 * @params: parameters to the method
4902 * @invoke: optional, delegate invoke.
4903 * @cb: async callback delegate.
4904 * @state: state passed to the async callback.
4906 * Translates arguments pointers into a MonoMethodMessage.
4909 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4910 MonoDelegate **cb, MonoObject **state)
4912 MonoDomain *domain = mono_domain_get ();
4913 MonoMethodSignature *sig = mono_method_signature (method);
4914 MonoMethodMessage *msg;
4917 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4920 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4921 count = sig->param_count - 2;
4923 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4924 count = sig->param_count;
4927 for (i = 0; i < count; i++) {
4932 if (sig->params [i]->byref)
4933 vpos = *((gpointer *)params [i]);
4937 type = sig->params [i]->type;
4938 class = mono_class_from_mono_type (sig->params [i]);
4940 if (class->valuetype)
4941 arg = mono_value_box (domain, class, vpos);
4943 arg = *((MonoObject **)vpos);
4945 mono_array_setref (msg->args, i, arg);
4948 if (cb != NULL && state != NULL) {
4949 *cb = *((MonoDelegate **)params [i]);
4951 *state = *((MonoObject **)params [i]);
4958 * mono_method_return_message_restore:
4960 * Restore results from message based processing back to arguments pointers
4963 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4965 MonoMethodSignature *sig = mono_method_signature (method);
4966 int i, j, type, size, out_len;
4968 if (out_args == NULL)
4970 out_len = mono_array_length (out_args);
4974 for (i = 0, j = 0; i < sig->param_count; i++) {
4975 MonoType *pt = sig->params [i];
4980 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4982 arg = mono_array_get (out_args, gpointer, j);
4986 case MONO_TYPE_VOID:
4987 g_assert_not_reached ();
4991 case MONO_TYPE_BOOLEAN:
4994 case MONO_TYPE_CHAR:
5001 case MONO_TYPE_VALUETYPE: {
5003 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5004 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5007 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5008 memset (*((gpointer *)params [i]), 0, size);
5012 case MONO_TYPE_STRING:
5013 case MONO_TYPE_CLASS:
5014 case MONO_TYPE_ARRAY:
5015 case MONO_TYPE_SZARRAY:
5016 case MONO_TYPE_OBJECT:
5017 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5020 g_assert_not_reached ();
5029 * mono_load_remote_field:
5030 * @this: pointer to an object
5031 * @klass: klass of the object containing @field
5032 * @field: the field to load
5033 * @res: a storage to store the result
5035 * This method is called by the runtime on attempts to load fields of
5036 * transparent proxy objects. @this points to such TP, @klass is the class of
5037 * the object containing @field. @res is a storage location which can be
5038 * used to store the result.
5040 * Returns: an address pointing to the value of field.
5043 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5045 static MonoMethod *getter = NULL;
5046 MonoDomain *domain = mono_domain_get ();
5047 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5048 MonoClass *field_class;
5049 MonoMethodMessage *msg;
5050 MonoArray *out_args;
5054 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5055 g_assert (res != NULL);
5057 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5058 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5063 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5067 field_class = mono_class_from_mono_type (field->type);
5069 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5070 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5071 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5073 full_name = mono_type_get_full_name (klass);
5074 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5075 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5078 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5080 if (exc) mono_raise_exception ((MonoException *)exc);
5082 if (mono_array_length (out_args) == 0)
5085 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5087 if (field_class->valuetype) {
5088 return ((char *)*res) + sizeof (MonoObject);
5094 * mono_load_remote_field_new:
5099 * Missing documentation.
5102 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5104 static MonoMethod *getter = NULL;
5105 MonoDomain *domain = mono_domain_get ();
5106 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5107 MonoClass *field_class;
5108 MonoMethodMessage *msg;
5109 MonoArray *out_args;
5110 MonoObject *exc, *res;
5113 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5115 field_class = mono_class_from_mono_type (field->type);
5117 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5119 if (field_class->valuetype) {
5120 res = mono_object_new (domain, field_class);
5121 val = ((gchar *) res) + sizeof (MonoObject);
5125 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5130 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5134 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5135 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5137 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5139 full_name = mono_type_get_full_name (klass);
5140 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5141 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5144 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5146 if (exc) mono_raise_exception ((MonoException *)exc);
5148 if (mono_array_length (out_args) == 0)
5151 res = mono_array_get (out_args, MonoObject *, 0);
5157 * mono_store_remote_field:
5158 * @this: pointer to an object
5159 * @klass: klass of the object containing @field
5160 * @field: the field to load
5161 * @val: the value/object to store
5163 * This method is called by the runtime on attempts to store fields of
5164 * transparent proxy objects. @this points to such TP, @klass is the class of
5165 * the object containing @field. @val is the new value to store in @field.
5168 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5170 static MonoMethod *setter = NULL;
5171 MonoDomain *domain = mono_domain_get ();
5172 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5173 MonoClass *field_class;
5174 MonoMethodMessage *msg;
5175 MonoArray *out_args;
5180 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5182 field_class = mono_class_from_mono_type (field->type);
5184 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5185 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5186 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5191 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5195 if (field_class->valuetype)
5196 arg = mono_value_box (domain, field_class, val);
5198 arg = *((MonoObject **)val);
5201 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5202 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5204 full_name = mono_type_get_full_name (klass);
5205 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5206 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5207 mono_array_setref (msg->args, 2, arg);
5210 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5212 if (exc) mono_raise_exception ((MonoException *)exc);
5216 * mono_store_remote_field_new:
5222 * Missing documentation
5225 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5227 static MonoMethod *setter = NULL;
5228 MonoDomain *domain = mono_domain_get ();
5229 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5230 MonoClass *field_class;
5231 MonoMethodMessage *msg;
5232 MonoArray *out_args;
5236 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5238 field_class = mono_class_from_mono_type (field->type);
5240 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5241 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5242 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5247 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5251 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5252 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5254 full_name = mono_type_get_full_name (klass);
5255 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5256 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5257 mono_array_setref (msg->args, 2, arg);
5260 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5262 if (exc) mono_raise_exception ((MonoException *)exc);
5266 * mono_create_ftnptr:
5268 * Given a function address, create a function descriptor for it.
5269 * This is only needed on IA64 and PPC64.
5272 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5277 mono_domain_lock (domain);
5278 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5279 mono_domain_unlock (domain);
5285 #elif defined(__ppc64__) || defined(__powerpc64__)
5288 mono_domain_lock (domain);
5289 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5290 mono_domain_unlock (domain);
5303 * mono_get_addr_from_ftnptr:
5305 * Given a pointer to a function descriptor, return the function address.
5306 * This is only needed on IA64 and PPC64.
5309 mono_get_addr_from_ftnptr (gpointer descr)
5311 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5312 return *(gpointer*)descr;
5320 * mono_string_chars:
5323 * Returns a pointer to the UCS16 characters stored in the MonoString
5326 mono_string_chars(MonoString *s)
5328 /* This method is here only for documentation extraction, this is a macro */
5332 * mono_string_length:
5335 * Returns the lenght in characters of the string
5338 mono_string_length (MonoString *s)
5340 /* This method is here only for documentation extraction, this is a macro */