2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
82 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
83 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
84 static CRITICAL_SECTION ldstr_section;
86 static gboolean profile_allocs = TRUE;
89 mono_runtime_object_init (MonoObject *this)
91 MonoMethod *method = NULL;
92 MonoClass *klass = this->vtable->klass;
94 method = mono_class_get_method_from_name (klass, ".ctor", 0);
97 if (method->klass->valuetype)
98 this = mono_object_unbox (this);
99 mono_runtime_invoke (method, this, NULL, NULL);
102 /* The pseudo algorithm for type initialization from the spec
103 Note it doesn't say anything about domains - only threads.
105 2. If the type is initialized you are done.
106 2.1. If the type is not yet initialized, try to take an
108 2.2. If successful, record this thread as responsible for
109 initializing the type and proceed to step 2.3.
110 2.2.1. If not, see whether this thread or any thread
111 waiting for this thread to complete already holds the lock.
112 2.2.2. If so, return since blocking would create a deadlock. This thread
113 will now see an incompletely initialized state for the type,
114 but no deadlock will arise.
115 2.2.3 If not, block until the type is initialized then return.
116 2.3 Initialize the parent type and then all interfaces implemented
118 2.4 Execute the type initialization code for this type.
119 2.5 Mark the type as initialized, release the initialization lock,
120 awaken any threads waiting for this type to be initialized,
127 guint32 initializing_tid;
128 guint32 waiting_count;
130 CRITICAL_SECTION initialization_section;
131 } TypeInitializationLock;
133 /* for locking access to type_initialization_hash and blocked_thread_hash */
134 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
135 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
136 static CRITICAL_SECTION type_initialization_section;
138 /* from vtable to lock */
139 static GHashTable *type_initialization_hash;
141 /* from thread id to thread id being waited on */
142 static GHashTable *blocked_thread_hash;
145 static MonoThread *main_thread;
147 /* Functions supplied by the runtime */
148 static MonoRuntimeCallbacks callbacks;
151 * mono_thread_set_main:
152 * @thread: thread to set as the main thread
154 * This function can be used to instruct the runtime to treat @thread
155 * as the main thread, ie, the thread that would normally execute the Main()
156 * method. This basically means that at the end of @thread, the runtime will
157 * wait for the existing foreground threads to quit and other such details.
160 mono_thread_set_main (MonoThread *thread)
162 main_thread = thread;
166 mono_thread_get_main (void)
172 mono_type_initialization_init (void)
174 InitializeCriticalSection (&type_initialization_section);
175 type_initialization_hash = g_hash_table_new (NULL, NULL);
176 blocked_thread_hash = g_hash_table_new (NULL, NULL);
177 InitializeCriticalSection (&ldstr_section);
181 mono_type_initialization_cleanup (void)
184 /* This is causing race conditions with
185 * mono_release_type_locks
187 DeleteCriticalSection (&type_initialization_section);
189 DeleteCriticalSection (&ldstr_section);
190 g_hash_table_destroy (type_initialization_hash);
191 g_hash_table_destroy (blocked_thread_hash);
195 * get_type_init_exception_for_vtable:
197 * Return the stored type initialization exception for VTABLE.
199 static MonoException*
200 get_type_init_exception_for_vtable (MonoVTable *vtable)
202 MonoDomain *domain = vtable->domain;
203 MonoClass *klass = vtable->klass;
207 g_assert (vtable->init_failed);
210 * If the initializing thread was rudely aborted, the exception is not stored
214 mono_domain_lock (domain);
215 if (domain->type_init_exception_hash)
216 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
217 mono_domain_unlock (domain);
220 if (klass->name_space && *klass->name_space)
221 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
223 full_name = g_strdup (klass->name);
224 ex = mono_get_exception_type_initialization (full_name, NULL);
231 * mono_runtime_class_init:
232 * @vtable: vtable that needs to be initialized
234 * This routine calls the class constructor for @vtable.
237 mono_runtime_class_init (MonoVTable *vtable)
239 mono_runtime_class_init_full (vtable, TRUE);
243 * mono_runtime_class_init_full:
244 * @vtable that neeeds to be initialized
245 * @raise_exception is TRUE, exceptions are raised intead of returned
249 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
252 MonoException *exc_to_throw;
253 MonoMethod *method = NULL;
259 if (vtable->initialized)
263 klass = vtable->klass;
265 if (!klass->image->checked_module_cctor) {
266 mono_image_check_for_module_cctor (klass->image);
267 if (klass->image->has_module_cctor) {
268 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
269 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
272 mono_runtime_class_init (module_vtable);
275 method = mono_class_get_cctor (klass);
278 MonoDomain *domain = vtable->domain;
279 TypeInitializationLock *lock;
280 guint32 tid = GetCurrentThreadId();
281 int do_initialization = 0;
282 MonoDomain *last_domain = NULL;
284 mono_type_initialization_lock ();
285 /* double check... */
286 if (vtable->initialized) {
287 mono_type_initialization_unlock ();
290 if (vtable->init_failed) {
291 mono_type_initialization_unlock ();
293 /* The type initialization already failed once, rethrow the same exception */
295 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
296 return get_type_init_exception_for_vtable (vtable);
298 lock = g_hash_table_lookup (type_initialization_hash, vtable);
300 /* This thread will get to do the initialization */
301 if (mono_domain_get () != domain) {
302 /* Transfer into the target domain */
303 last_domain = mono_domain_get ();
304 if (!mono_domain_set (domain, FALSE)) {
305 vtable->initialized = 1;
306 mono_type_initialization_unlock ();
308 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
309 return mono_get_exception_appdomain_unloaded ();
312 lock = g_malloc (sizeof(TypeInitializationLock));
313 InitializeCriticalSection (&lock->initialization_section);
314 lock->initializing_tid = tid;
315 lock->waiting_count = 1;
317 /* grab the vtable lock while this thread still owns type_initialization_section */
318 EnterCriticalSection (&lock->initialization_section);
319 g_hash_table_insert (type_initialization_hash, vtable, lock);
320 do_initialization = 1;
323 TypeInitializationLock *pending_lock;
325 if (lock->initializing_tid == tid || lock->done) {
326 mono_type_initialization_unlock ();
329 /* see if the thread doing the initialization is already blocked on this thread */
330 blocked = GUINT_TO_POINTER (lock->initializing_tid);
331 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
332 if (pending_lock->initializing_tid == tid) {
333 if (!pending_lock->done) {
334 mono_type_initialization_unlock ();
337 /* the thread doing the initialization is blocked on this thread,
338 but on a lock that has already been freed. It just hasn't got
343 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
345 ++lock->waiting_count;
346 /* record the fact that we are waiting on the initializing thread */
347 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
349 mono_type_initialization_unlock ();
351 if (do_initialization) {
352 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
354 /* If the initialization failed, mark the class as unusable. */
355 /* Avoid infinite loops */
357 (klass->image == mono_defaults.corlib &&
358 !strcmp (klass->name_space, "System") &&
359 !strcmp (klass->name, "TypeInitializationException")))) {
360 vtable->init_failed = 1;
362 if (klass->name_space && *klass->name_space)
363 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
365 full_name = g_strdup (klass->name);
366 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
370 * Store the exception object so it could be thrown on subsequent
373 mono_domain_lock (domain);
374 if (!domain->type_init_exception_hash)
375 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
376 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
377 mono_domain_unlock (domain);
381 mono_domain_set (last_domain, TRUE);
383 LeaveCriticalSection (&lock->initialization_section);
385 /* this just blocks until the initializing thread is done */
386 EnterCriticalSection (&lock->initialization_section);
387 LeaveCriticalSection (&lock->initialization_section);
390 mono_type_initialization_lock ();
391 if (lock->initializing_tid != tid)
392 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
393 --lock->waiting_count;
394 if (lock->waiting_count == 0) {
395 DeleteCriticalSection (&lock->initialization_section);
396 g_hash_table_remove (type_initialization_hash, vtable);
399 if (!vtable->init_failed)
400 vtable->initialized = 1;
401 mono_type_initialization_unlock ();
403 if (vtable->init_failed) {
404 /* Either we were the initializing thread or we waited for the initialization */
406 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
407 return get_type_init_exception_for_vtable (vtable);
410 vtable->initialized = 1;
417 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
419 MonoVTable *vtable = (MonoVTable*)key;
421 TypeInitializationLock *lock = (TypeInitializationLock*) value;
422 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
425 * Have to set this since it cannot be set by the normal code in
426 * mono_runtime_class_init (). In this case, the exception object is not stored,
427 * and get_type_init_exception_for_class () needs to be aware of this.
429 vtable->init_failed = 1;
430 LeaveCriticalSection (&lock->initialization_section);
431 --lock->waiting_count;
432 if (lock->waiting_count == 0) {
433 DeleteCriticalSection (&lock->initialization_section);
442 mono_release_type_locks (MonoInternalThread *thread)
444 mono_type_initialization_lock ();
445 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
446 mono_type_initialization_unlock ();
450 default_trampoline (MonoMethod *method)
456 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
458 g_assert_not_reached ();
464 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
466 g_error ("remoting not installed");
471 default_delegate_trampoline (MonoClass *klass)
473 g_assert_not_reached ();
477 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
478 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
479 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
480 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
481 static MonoImtThunkBuilder imt_thunk_builder = NULL;
482 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
483 #if (MONO_IMT_SIZE > 32)
484 #error "MONO_IMT_SIZE cannot be larger than 32"
488 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
490 memcpy (&callbacks, cbs, sizeof (*cbs));
493 MonoRuntimeCallbacks*
494 mono_get_runtime_callbacks (void)
500 mono_install_trampoline (MonoTrampoline func)
502 arch_create_jit_trampoline = func? func: default_trampoline;
506 mono_install_jump_trampoline (MonoJumpTrampoline func)
508 arch_create_jump_trampoline = func? func: default_jump_trampoline;
512 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
514 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
518 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
520 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
524 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
525 imt_thunk_builder = func;
528 static MonoCompileFunc default_mono_compile_method = NULL;
531 * mono_install_compile_method:
532 * @func: function to install
534 * This is a VM internal routine
537 mono_install_compile_method (MonoCompileFunc func)
539 default_mono_compile_method = func;
543 * mono_compile_method:
544 * @method: The method to compile.
546 * This JIT-compiles the method, and returns the pointer to the native code
550 mono_compile_method (MonoMethod *method)
552 if (!default_mono_compile_method) {
553 g_error ("compile method called on uninitialized runtime");
556 return default_mono_compile_method (method);
560 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
562 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
566 mono_runtime_create_delegate_trampoline (MonoClass *klass)
568 return arch_create_delegate_trampoline (klass);
571 static MonoFreeMethodFunc default_mono_free_method = NULL;
574 * mono_install_free_method:
575 * @func: pointer to the MonoFreeMethodFunc used to release a method
577 * This is an internal VM routine, it is used for the engines to
578 * register a handler to release the resources associated with a method.
580 * Methods are freed when no more references to the delegate that holds
584 mono_install_free_method (MonoFreeMethodFunc func)
586 default_mono_free_method = func;
590 * mono_runtime_free_method:
591 * @domain; domain where the method is hosted
592 * @method: method to release
594 * This routine is invoked to free the resources associated with
595 * a method that has been JIT compiled. This is used to discard
596 * methods that were used only temporarily (for example, used in marshalling)
600 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
602 if (default_mono_free_method != NULL)
603 default_mono_free_method (domain, method);
605 mono_method_clear_object (domain, method);
607 mono_free_method (method);
611 * The vtables in the root appdomain are assumed to be reachable by other
612 * roots, and we don't use typed allocation in the other domains.
615 /* The sync block is no longer a GC pointer */
616 #define GC_HEADER_BITMAP (0)
618 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
621 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
623 MonoClassField *field;
629 max_size = mono_class_data_size (class) / sizeof (gpointer);
631 max_size = class->instance_size / sizeof (gpointer);
632 if (max_size > size) {
633 g_assert (offset <= 0);
634 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
639 /*An Ephemeron cannot be marked by sgen*/
640 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
642 memset (bitmap, 0, size / 8);
647 for (p = class; p != NULL; p = p->parent) {
648 gpointer iter = NULL;
649 while ((field = mono_class_get_fields (p, &iter))) {
653 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
655 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
658 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
661 /* FIXME: should not happen, flag as type load error */
662 if (field->type->byref)
665 if (static_fields && field->offset == -1)
669 pos = field->offset / sizeof (gpointer);
672 type = mono_type_get_underlying_type (field->type);
673 switch (type->type) {
676 case MONO_TYPE_FNPTR:
678 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
683 if (class->image != mono_defaults.corlib)
686 case MONO_TYPE_STRING:
687 case MONO_TYPE_SZARRAY:
688 case MONO_TYPE_CLASS:
689 case MONO_TYPE_OBJECT:
690 case MONO_TYPE_ARRAY:
691 g_assert ((field->offset % sizeof(gpointer)) == 0);
693 g_assert (pos < size || pos <= max_size);
694 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
695 *max_set = MAX (*max_set, pos);
697 case MONO_TYPE_GENERICINST:
698 if (!mono_type_generic_inst_is_valuetype (type)) {
699 g_assert ((field->offset % sizeof(gpointer)) == 0);
701 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
702 *max_set = MAX (*max_set, pos);
707 case MONO_TYPE_VALUETYPE: {
708 MonoClass *fclass = mono_class_from_mono_type (field->type);
709 if (fclass->has_references) {
710 /* remove the object header */
711 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
725 case MONO_TYPE_BOOLEAN:
729 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
741 * similar to the above, but sets the bits in the bitmap for any non-ref field
742 * and ignores static fields
745 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
747 MonoClassField *field;
752 max_size = class->instance_size / sizeof (gpointer);
753 if (max_size >= size) {
754 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
757 for (p = class; p != NULL; p = p->parent) {
758 gpointer iter = NULL;
759 while ((field = mono_class_get_fields (p, &iter))) {
762 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
764 /* FIXME: should not happen, flag as type load error */
765 if (field->type->byref)
768 pos = field->offset / sizeof (gpointer);
771 type = mono_type_get_underlying_type (field->type);
772 switch (type->type) {
773 #if SIZEOF_VOID_P == 8
777 case MONO_TYPE_FNPTR:
782 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
783 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
784 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
787 #if SIZEOF_VOID_P == 4
791 case MONO_TYPE_FNPTR:
796 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
797 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
798 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
804 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
805 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
806 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
809 case MONO_TYPE_BOOLEAN:
812 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
814 case MONO_TYPE_STRING:
815 case MONO_TYPE_SZARRAY:
816 case MONO_TYPE_CLASS:
817 case MONO_TYPE_OBJECT:
818 case MONO_TYPE_ARRAY:
820 case MONO_TYPE_GENERICINST:
821 if (!mono_type_generic_inst_is_valuetype (type)) {
826 case MONO_TYPE_VALUETYPE: {
827 MonoClass *fclass = mono_class_from_mono_type (field->type);
828 /* remove the object header */
829 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
833 g_assert_not_reached ();
842 * mono_class_insecure_overlapping:
843 * check if a class with explicit layout has references and non-references
844 * fields overlapping.
846 * Returns: TRUE if it is insecure to load the type.
849 mono_class_insecure_overlapping (MonoClass *klass)
853 gsize default_bitmap [4] = {0};
855 gsize default_nrbitmap [4] = {0};
856 int i, insecure = FALSE;
859 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
860 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
862 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
863 int idx = i % (sizeof (bitmap [0]) * 8);
864 if (bitmap [idx] & nrbitmap [idx]) {
869 if (bitmap != default_bitmap)
871 if (nrbitmap != default_nrbitmap)
874 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
882 mono_string_alloc (int length)
884 return mono_string_new_size (mono_domain_get (), length);
888 mono_class_compute_gc_descriptor (MonoClass *class)
892 gsize default_bitmap [4] = {0};
893 static gboolean gcj_inited = FALSE;
898 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
899 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
900 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
901 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
903 #ifdef HAVE_GC_GCJ_MALLOC
905 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
909 #ifdef GC_REDIRECT_TO_LOCAL
910 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
911 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
913 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
914 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
919 mono_loader_unlock ();
923 mono_class_init (class);
925 if (class->gc_descr_inited)
928 class->gc_descr_inited = TRUE;
929 class->gc_descr = GC_NO_DESCRIPTOR;
931 bitmap = default_bitmap;
932 if (class == mono_defaults.string_class) {
933 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
934 } else if (class->rank) {
935 mono_class_compute_gc_descriptor (class->element_class);
936 if (!class->element_class->valuetype) {
938 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
939 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
940 class->name_space, class->name);*/
942 /* remove the object header */
943 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
944 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
945 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
946 class->name_space, class->name);*/
947 if (bitmap != default_bitmap)
951 /*static int count = 0;
954 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
955 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
957 if (class->gc_descr == GC_NO_DESCRIPTOR)
958 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
960 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
961 if (bitmap != default_bitmap)
967 * field_is_special_static:
968 * @fklass: The MonoClass to look up.
969 * @field: The MonoClassField describing the field.
971 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
972 * SPECIAL_STATIC_NONE otherwise.
975 field_is_special_static (MonoClass *fklass, MonoClassField *field)
977 MonoCustomAttrInfo *ainfo;
979 ainfo = mono_custom_attrs_from_field (fklass, field);
982 for (i = 0; i < ainfo->num_attrs; ++i) {
983 MonoClass *klass = ainfo->attrs [i].ctor->klass;
984 if (klass->image == mono_defaults.corlib) {
985 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
986 mono_custom_attrs_free (ainfo);
987 return SPECIAL_STATIC_THREAD;
989 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
990 mono_custom_attrs_free (ainfo);
991 return SPECIAL_STATIC_CONTEXT;
995 mono_custom_attrs_free (ainfo);
996 return SPECIAL_STATIC_NONE;
999 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1000 #define mix(a,b,c) { \
1001 a -= c; a ^= rot(c, 4); c += b; \
1002 b -= a; b ^= rot(a, 6); a += c; \
1003 c -= b; c ^= rot(b, 8); b += a; \
1004 a -= c; a ^= rot(c,16); c += b; \
1005 b -= a; b ^= rot(a,19); a += c; \
1006 c -= b; c ^= rot(b, 4); b += a; \
1008 #define final(a,b,c) { \
1009 c ^= b; c -= rot(b,14); \
1010 a ^= c; a -= rot(c,11); \
1011 b ^= a; b -= rot(a,25); \
1012 c ^= b; c -= rot(b,16); \
1013 a ^= c; a -= rot(c,4); \
1014 b ^= a; b -= rot(a,14); \
1015 c ^= b; c -= rot(b,24); \
1019 * mono_method_get_imt_slot:
1021 * The IMT slot is embedded into AOTed code, so this must return the same value
1022 * for the same method across all executions. This means:
1023 * - pointers shouldn't be used as hash values.
1024 * - mono_metadata_str_hash () should be used for hashing strings.
1027 mono_method_get_imt_slot (MonoMethod *method)
1029 MonoMethodSignature *sig;
1031 guint32 *hashes_start, *hashes;
1035 /* This can be used to stress tests the collision code */
1039 * We do this to simplify generic sharing. It will hurt
1040 * performance in cases where a class implements two different
1041 * instantiations of the same generic interface.
1042 * The code in build_imt_slots () depends on this.
1044 if (method->is_inflated)
1045 method = ((MonoMethodInflated*)method)->declaring;
1047 sig = mono_method_signature (method);
1048 hashes_count = sig->param_count + 4;
1049 hashes_start = malloc (hashes_count * sizeof (guint32));
1050 hashes = hashes_start;
1052 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1053 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1054 method->klass->name_space, method->klass->name, method->name);
1055 g_assert_not_reached ();
1058 /* Initialize hashes */
1059 hashes [0] = mono_metadata_str_hash (method->klass->name);
1060 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1061 hashes [2] = mono_metadata_str_hash (method->name);
1062 hashes [3] = mono_metadata_type_hash (sig->ret);
1063 for (i = 0; i < sig->param_count; i++) {
1064 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1067 /* Setup internal state */
1068 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1070 /* Handle most of the hashes */
1071 while (hashes_count > 3) {
1080 /* Handle the last 3 hashes (all the case statements fall through) */
1081 switch (hashes_count) {
1082 case 3 : c += hashes [2];
1083 case 2 : b += hashes [1];
1084 case 1 : a += hashes [0];
1086 case 0: /* nothing left to add */
1090 free (hashes_start);
1091 /* Report the result */
1092 return c % MONO_IMT_SIZE;
1101 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1102 guint32 imt_slot = mono_method_get_imt_slot (method);
1103 MonoImtBuilderEntry *entry;
1105 if (slot_num >= 0 && imt_slot != slot_num) {
1106 /* we build just a single imt slot and this is not it */
1110 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1111 entry->key = method;
1112 entry->value.vtable_slot = vtable_slot;
1113 entry->next = imt_builder [imt_slot];
1114 if (imt_builder [imt_slot] != NULL) {
1115 entry->children = imt_builder [imt_slot]->children + 1;
1116 if (entry->children == 1) {
1117 mono_stats.imt_slots_with_collisions++;
1118 *imt_collisions_bitmap |= (1 << imt_slot);
1121 entry->children = 0;
1122 mono_stats.imt_used_slots++;
1124 imt_builder [imt_slot] = entry;
1127 char *method_name = mono_method_full_name (method, TRUE);
1128 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1129 method, method_name, imt_slot, vtable_slot, entry->children);
1130 g_free (method_name);
1137 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1139 MonoMethod *method = e->key;
1140 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1144 method->klass->name_space,
1145 method->klass->name,
1148 printf (" * %s: NULL\n", message);
1154 compare_imt_builder_entries (const void *p1, const void *p2) {
1155 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1156 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1158 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1162 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1164 int count = end - start;
1165 int chunk_start = out_array->len;
1168 for (i = start; i < end; ++i) {
1169 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1170 item->key = sorted_array [i]->key;
1171 item->value = sorted_array [i]->value;
1172 item->has_target_code = sorted_array [i]->has_target_code;
1173 item->is_equals = TRUE;
1175 item->check_target_idx = out_array->len + 1;
1177 item->check_target_idx = 0;
1178 g_ptr_array_add (out_array, item);
1181 int middle = start + count / 2;
1182 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1184 item->key = sorted_array [middle]->key;
1185 item->is_equals = FALSE;
1186 g_ptr_array_add (out_array, item);
1187 imt_emit_ir (sorted_array, start, middle, out_array);
1188 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1194 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1195 int number_of_entries = entries->children + 1;
1196 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1197 GPtrArray *result = g_ptr_array_new ();
1198 MonoImtBuilderEntry *current_entry;
1201 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1202 sorted_array [i] = current_entry;
1204 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1206 /*for (i = 0; i < number_of_entries; i++) {
1207 print_imt_entry (" sorted array:", sorted_array [i], i);
1210 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1212 free (sorted_array);
1217 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1219 if (imt_builder_entry != NULL) {
1220 if (imt_builder_entry->children == 0 && !fail_tramp) {
1221 /* No collision, return the vtable slot contents */
1222 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1224 /* Collision, build the thunk */
1225 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1228 result = imt_thunk_builder (vtable, domain,
1229 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1230 for (i = 0; i < imt_ir->len; ++i)
1231 g_free (g_ptr_array_index (imt_ir, i));
1232 g_ptr_array_free (imt_ir, TRUE);
1244 static MonoImtBuilderEntry*
1245 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1248 * LOCKING: requires the loader and domain locks.
1252 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1256 guint32 imt_collisions_bitmap = 0;
1257 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1258 int method_count = 0;
1259 gboolean record_method_count_for_max_collisions = FALSE;
1260 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1263 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1265 for (i = 0; i < klass->interface_offsets_count; ++i) {
1266 MonoClass *iface = klass->interfaces_packed [i];
1267 int interface_offset = klass->interface_offsets_packed [i];
1268 int method_slot_in_interface, vt_slot;
1270 if (mono_class_has_variant_generic_params (iface))
1271 has_variant_iface = TRUE;
1273 vt_slot = interface_offset;
1274 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1277 if (slot_num >= 0 && iface->is_inflated) {
1279 * The imt slot of the method is the same as for its declaring method,
1280 * see the comment in mono_method_get_imt_slot (), so we can
1281 * avoid inflating methods which will be discarded by
1282 * add_imt_builder_entry anyway.
1284 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1285 if (mono_method_get_imt_slot (method) != slot_num) {
1290 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1291 if (method->is_generic) {
1292 has_generic_virtual = TRUE;
1297 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1298 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1303 if (extra_interfaces) {
1304 int interface_offset = klass->vtable_size;
1306 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1307 MonoClass* iface = list_item->data;
1308 int method_slot_in_interface;
1309 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1310 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1311 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1313 interface_offset += iface->method.count;
1316 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1317 /* overwrite the imt slot only if we're building all the entries or if
1318 * we're building this specific one
1320 if (slot_num < 0 || i == slot_num) {
1321 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1324 if (imt_builder [i]) {
1325 MonoImtBuilderEntry *entry;
1327 /* Link entries with imt_builder [i] */
1328 for (entry = entries; entry->next; entry = entry->next) {
1330 MonoMethod *method = (MonoMethod*)entry->key;
1331 char *method_name = mono_method_full_name (method, TRUE);
1332 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1333 g_free (method_name);
1336 entry->next = imt_builder [i];
1337 entries->children += imt_builder [i]->children + 1;
1339 imt_builder [i] = entries;
1342 if (has_generic_virtual || has_variant_iface) {
1344 * There might be collisions later when the the thunk is expanded.
1346 imt_collisions_bitmap |= (1 << i);
1349 * The IMT thunk might be called with an instance of one of the
1350 * generic virtual methods, so has to fallback to the IMT trampoline.
1352 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1354 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1357 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1361 if (imt_builder [i] != NULL) {
1362 int methods_in_slot = imt_builder [i]->children + 1;
1363 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1364 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1365 record_method_count_for_max_collisions = TRUE;
1367 method_count += methods_in_slot;
1371 mono_stats.imt_number_of_methods += method_count;
1372 if (record_method_count_for_max_collisions) {
1373 mono_stats.imt_method_count_when_max_collisions = method_count;
1376 for (i = 0; i < MONO_IMT_SIZE; i++) {
1377 MonoImtBuilderEntry* entry = imt_builder [i];
1378 while (entry != NULL) {
1379 MonoImtBuilderEntry* next = entry->next;
1385 /* we OR the bitmap since we may build just a single imt slot at a time */
1386 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1390 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1391 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1395 * mono_vtable_build_imt_slot:
1396 * @vtable: virtual object table struct
1397 * @imt_slot: slot in the IMT table
1399 * Fill the given @imt_slot in the IMT table of @vtable with
1400 * a trampoline or a thunk for the case of collisions.
1401 * This is part of the internal mono API.
1403 * LOCKING: Take the domain lock.
1406 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1408 gpointer *imt = (gpointer*)vtable;
1409 imt -= MONO_IMT_SIZE;
1410 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1412 /* no support for extra interfaces: the proxy objects will need
1413 * to build the complete IMT
1414 * Update and heck needs to ahppen inside the proper domain lock, as all
1415 * the changes made to a MonoVTable.
1417 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1418 mono_domain_lock (vtable->domain);
1419 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1420 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1421 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1422 mono_domain_unlock (vtable->domain);
1423 mono_loader_unlock ();
1428 * The first two free list entries both belong to the wait list: The
1429 * first entry is the pointer to the head of the list and the second
1430 * entry points to the last element. That way appending and removing
1431 * the first element are both O(1) operations.
1433 #ifdef MONO_SMALL_CONFIG
1434 #define NUM_FREE_LISTS 6
1436 #define NUM_FREE_LISTS 12
1438 #define FIRST_FREE_LIST_SIZE 64
1439 #define MAX_WAIT_LENGTH 50
1440 #define THUNK_THRESHOLD 10
1443 * LOCKING: The domain lock must be held.
1446 init_thunk_free_lists (MonoDomain *domain)
1448 if (domain->thunk_free_lists)
1450 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1454 list_index_for_size (int item_size)
1457 int size = FIRST_FREE_LIST_SIZE;
1459 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1468 * mono_method_alloc_generic_virtual_thunk:
1470 * @size: size in bytes
1472 * Allocs size bytes to be used for the code of a generic virtual
1473 * thunk. It's either allocated from the domain's code manager or
1474 * reused from a previously invalidated piece.
1476 * LOCKING: The domain lock must be held.
1479 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1481 static gboolean inited = FALSE;
1482 static int generic_virtual_thunks_size = 0;
1486 MonoThunkFreeList **l;
1488 init_thunk_free_lists (domain);
1490 size += sizeof (guint32);
1491 if (size < sizeof (MonoThunkFreeList))
1492 size = sizeof (MonoThunkFreeList);
1494 i = list_index_for_size (size);
1495 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1496 if ((*l)->size >= size) {
1497 MonoThunkFreeList *item = *l;
1499 return ((guint32*)item) + 1;
1503 /* no suitable item found - search lists of larger sizes */
1504 while (++i < NUM_FREE_LISTS) {
1505 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1508 g_assert (item->size > size);
1509 domain->thunk_free_lists [i] = item->next;
1510 return ((guint32*)item) + 1;
1513 /* still nothing found - allocate it */
1515 mono_counters_register ("Generic virtual thunk bytes",
1516 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1519 generic_virtual_thunks_size += size;
1521 p = mono_domain_code_reserve (domain, size);
1528 * LOCKING: The domain lock must be held.
1531 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1534 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1536 init_thunk_free_lists (domain);
1538 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1539 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1540 int length = item->length;
1543 /* unlink the first item from the wait list */
1544 domain->thunk_free_lists [0] = item->next;
1545 domain->thunk_free_lists [0]->length = length - 1;
1547 i = list_index_for_size (item->size);
1549 /* put it in the free list */
1550 item->next = domain->thunk_free_lists [i];
1551 domain->thunk_free_lists [i] = item;
1555 if (domain->thunk_free_lists [1]) {
1556 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1557 domain->thunk_free_lists [0]->length++;
1559 g_assert (!domain->thunk_free_lists [0]);
1561 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1562 domain->thunk_free_lists [0]->length = 1;
1566 typedef struct _GenericVirtualCase {
1570 struct _GenericVirtualCase *next;
1571 } GenericVirtualCase;
1574 * get_generic_virtual_entries:
1576 * Return IMT entries for the generic virtual method instances and
1577 * variant interface methods for vtable slot
1580 static MonoImtBuilderEntry*
1581 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1583 GenericVirtualCase *list;
1584 MonoImtBuilderEntry *entries;
1586 mono_domain_lock (domain);
1587 if (!domain->generic_virtual_cases)
1588 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1590 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1593 for (; list; list = list->next) {
1594 MonoImtBuilderEntry *entry;
1596 if (list->count < THUNK_THRESHOLD)
1599 entry = g_new0 (MonoImtBuilderEntry, 1);
1600 entry->key = list->method;
1601 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1602 entry->has_target_code = 1;
1604 entry->children = entries->children + 1;
1605 entry->next = entries;
1609 mono_domain_unlock (domain);
1611 /* FIXME: Leaking memory ? */
1616 * mono_method_add_generic_virtual_invocation:
1618 * @vtable_slot: pointer to the vtable slot
1619 * @method: the inflated generic virtual method
1620 * @code: the method's code
1622 * Registers a call via unmanaged code to a generic virtual method
1623 * instantiation or variant interface method. If the number of calls reaches a threshold
1624 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1625 * virtual method thunk.
1628 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1629 gpointer *vtable_slot,
1630 MonoMethod *method, gpointer code)
1632 static gboolean inited = FALSE;
1633 static int num_added = 0;
1635 GenericVirtualCase *gvc, *list;
1636 MonoImtBuilderEntry *entries;
1640 mono_domain_lock (domain);
1641 if (!domain->generic_virtual_cases)
1642 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1644 /* Check whether the case was already added */
1645 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1648 if (gvc->method == method)
1653 /* If not found, make a new one */
1655 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1656 gvc->method = method;
1659 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1661 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1664 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1670 if (++gvc->count == THUNK_THRESHOLD) {
1671 gpointer *old_thunk = *vtable_slot;
1672 gpointer vtable_trampoline = NULL;
1673 gpointer imt_trampoline = NULL;
1675 if ((gpointer)vtable_slot < (gpointer)vtable) {
1676 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1677 int imt_slot = MONO_IMT_SIZE + displacement;
1679 /* Force the rebuild of the thunk at the next call */
1680 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1681 *vtable_slot = imt_trampoline;
1683 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1685 entries = get_generic_virtual_entries (domain, vtable_slot);
1687 sorted = imt_sort_slot_entries (entries);
1689 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1693 MonoImtBuilderEntry *next = entries->next;
1698 for (i = 0; i < sorted->len; ++i)
1699 g_free (g_ptr_array_index (sorted, i));
1700 g_ptr_array_free (sorted, TRUE);
1703 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1704 invalidate_generic_virtual_thunk (domain, old_thunk);
1707 mono_domain_unlock (domain);
1710 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1713 * mono_class_vtable:
1714 * @domain: the application domain
1715 * @class: the class to initialize
1717 * VTables are domain specific because we create domain specific code, and
1718 * they contain the domain specific static class data.
1719 * On failure, NULL is returned, and class->exception_type is set.
1722 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1724 return mono_class_vtable_full (domain, class, FALSE);
1728 * mono_class_vtable_full:
1729 * @domain: the application domain
1730 * @class: the class to initialize
1731 * @raise_on_error if an exception should be raised on failure or not
1733 * VTables are domain specific because we create domain specific code, and
1734 * they contain the domain specific static class data.
1737 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1739 MonoClassRuntimeInfo *runtime_info;
1743 if (class->exception_type) {
1745 mono_raise_exception (mono_class_get_exception_for_failure (class));
1749 /* this check can be inlined in jitted code, too */
1750 runtime_info = class->runtime_info;
1751 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1752 return runtime_info->domain_vtables [domain->domain_id];
1753 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1757 * mono_class_try_get_vtable:
1758 * @domain: the application domain
1759 * @class: the class to initialize
1761 * This function tries to get the associated vtable from @class if
1762 * it was already created.
1765 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1767 MonoClassRuntimeInfo *runtime_info;
1771 runtime_info = class->runtime_info;
1772 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1773 return runtime_info->domain_vtables [domain->domain_id];
1778 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1781 MonoClassRuntimeInfo *runtime_info, *old_info;
1782 MonoClassField *field;
1785 int imt_table_bytes = 0;
1786 guint32 vtable_size, class_size;
1789 gpointer *interface_offsets;
1791 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1792 mono_domain_lock (domain);
1793 runtime_info = class->runtime_info;
1794 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1795 mono_domain_unlock (domain);
1796 mono_loader_unlock ();
1797 return runtime_info->domain_vtables [domain->domain_id];
1799 if (!class->inited || class->exception_type) {
1800 if (!mono_class_init (class) || class->exception_type) {
1801 mono_domain_unlock (domain);
1802 mono_loader_unlock ();
1804 mono_raise_exception (mono_class_get_exception_for_failure (class));
1809 /* Array types require that their element type be valid*/
1810 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1811 MonoClass *element_class = class->element_class;
1812 if (!element_class->inited)
1813 mono_class_init (element_class);
1815 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1816 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1817 mono_class_setup_vtable (element_class);
1819 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1820 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1821 if (class->exception_type == MONO_EXCEPTION_NONE)
1822 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1823 mono_domain_unlock (domain);
1824 mono_loader_unlock ();
1826 mono_raise_exception (mono_class_get_exception_for_failure (class));
1832 * For some classes, mono_class_init () already computed class->vtable_size, and
1833 * that is all that is needed because of the vtable trampolines.
1835 if (!class->vtable_size)
1836 mono_class_setup_vtable (class);
1838 if (class->exception_type) {
1839 mono_domain_unlock (domain);
1840 mono_loader_unlock ();
1842 mono_raise_exception (mono_class_get_exception_for_failure (class));
1847 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1848 if (class->interface_offsets_count) {
1849 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1850 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1851 mono_stats.imt_number_of_tables++;
1852 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1855 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1856 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1859 mono_stats.used_class_count++;
1860 mono_stats.class_vtable_size += vtable_size;
1861 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1864 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1866 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1868 vt->rank = class->rank;
1869 vt->domain = domain;
1871 mono_class_compute_gc_descriptor (class);
1873 * We can't use typed allocation in the non-root domains, since the
1874 * collector needs the GC descriptor stored in the vtable even after
1875 * the mempool containing the vtable is destroyed when the domain is
1876 * unloaded. An alternative might be to allocate vtables in the GC
1877 * heap, but this does not seem to work (it leads to crashes inside
1878 * libgc). If that approach is tried, two gc descriptors need to be
1879 * allocated for each class: one for the root domain, and one for all
1880 * other domains. The second descriptor should contain a bit for the
1881 * vtable field in MonoObject, since we can no longer assume the
1882 * vtable is reachable by other roots after the appdomain is unloaded.
1884 #ifdef HAVE_BOEHM_GC
1885 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1886 vt->gc_descr = GC_NO_DESCRIPTOR;
1889 vt->gc_descr = class->gc_descr;
1891 if ((class_size = mono_class_data_size (class))) {
1892 if (class->has_static_refs) {
1893 gpointer statics_gc_descr;
1895 gsize default_bitmap [4] = {0};
1898 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1899 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1900 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1901 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1902 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1903 if (bitmap != default_bitmap)
1906 vt->data = mono_domain_alloc0 (domain, class_size);
1908 mono_stats.class_static_data_size += class_size;
1913 while ((field = mono_class_get_fields (class, &iter))) {
1914 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1916 if (mono_field_is_deleted (field))
1918 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1919 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1920 if (special_static != SPECIAL_STATIC_NONE) {
1921 guint32 size, offset;
1923 gsize default_bitmap [4] = {0};
1927 if (mono_type_is_reference (field->type)) {
1928 default_bitmap [0] = 1;
1930 bitmap = default_bitmap;
1931 } else if (mono_type_is_struct (field->type)) {
1932 fclass = mono_class_from_mono_type (field->type);
1933 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1935 default_bitmap [0] = 0;
1937 bitmap = default_bitmap;
1939 size = mono_type_size (field->type, &align);
1940 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1941 if (!domain->special_static_fields)
1942 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1943 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1944 if (bitmap != default_bitmap)
1947 * This marks the field as special static to speed up the
1948 * checks in mono_field_static_get/set_value ().
1954 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1955 MonoClass *fklass = mono_class_from_mono_type (field->type);
1956 const char *data = mono_field_get_data (field);
1958 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1959 t = (char*)vt->data + field->offset;
1960 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1963 if (fklass->valuetype) {
1964 memcpy (t, data, mono_class_value_size (fklass, NULL));
1966 /* it's a pointer type: add check */
1967 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1974 vt->max_interface_id = class->max_interface_id;
1975 vt->interface_bitmap = class->interface_bitmap;
1977 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1978 // class->name, class->interface_offsets_count);
1980 if (! ARCH_USE_IMT) {
1981 /* initialize interface offsets */
1982 for (i = 0; i < class->interface_offsets_count; ++i) {
1983 int interface_id = class->interfaces_packed [i]->interface_id;
1984 int slot = class->interface_offsets_packed [i];
1985 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1989 /* class_vtable_array keeps an array of created vtables
1991 g_ptr_array_add (domain->class_vtable_array, vt);
1992 /* class->runtime_info is protected by the loader lock, both when
1993 * it it enlarged and when it is stored info.
1996 old_info = class->runtime_info;
1997 if (old_info && old_info->max_domain >= domain->domain_id) {
1998 /* someone already created a large enough runtime info */
1999 mono_memory_barrier ();
2000 old_info->domain_vtables [domain->domain_id] = vt;
2002 int new_size = domain->domain_id;
2004 new_size = MAX (new_size, old_info->max_domain);
2006 /* make the new size a power of two */
2008 while (new_size > i)
2011 /* this is a bounded memory retention issue: may want to
2012 * handle it differently when we'll have a rcu-like system.
2014 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2015 runtime_info->max_domain = new_size - 1;
2016 /* copy the stuff from the older info */
2018 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2020 runtime_info->domain_vtables [domain->domain_id] = vt;
2022 mono_memory_barrier ();
2023 class->runtime_info = runtime_info;
2026 /* Initialize vtable */
2027 if (callbacks.get_vtable_trampoline) {
2028 // This also covers the AOT case
2029 for (i = 0; i < class->vtable_size; ++i) {
2030 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2033 mono_class_setup_vtable (class);
2035 for (i = 0; i < class->vtable_size; ++i) {
2038 if ((cm = class->vtable [i]))
2039 vt->vtable [i] = arch_create_jit_trampoline (cm);
2043 if (ARCH_USE_IMT && imt_table_bytes) {
2044 /* Now that the vtable is full, we can actually fill up the IMT */
2045 if (callbacks.get_imt_trampoline) {
2046 /* lazy construction of the IMT entries enabled */
2047 for (i = 0; i < MONO_IMT_SIZE; ++i)
2048 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2050 build_imt (class, vt, domain, interface_offsets, NULL);
2054 mono_domain_unlock (domain);
2055 mono_loader_unlock ();
2057 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2058 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2059 mono_raise_exception (mono_class_get_exception_for_failure (class));
2061 /* make sure the parent is initialized */
2062 /*FIXME shouldn't this fail the current type?*/
2064 mono_class_vtable_full (domain, class->parent, raise_on_error);
2066 /*FIXME check for OOM*/
2067 vt->type = mono_type_get_object (domain, &class->byval_arg);
2069 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2070 static void *type_desc = NULL;
2074 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2077 /* This is unregistered in
2078 unregister_vtable_reflection_type() in
2080 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2083 if (class->contextbound)
2092 * mono_class_proxy_vtable:
2093 * @domain: the application domain
2094 * @remove_class: the remote class
2096 * Creates a vtable for transparent proxies. It is basically
2097 * a copy of the real vtable of the class wrapped in @remote_class,
2098 * but all function pointers invoke the remoting functions, and
2099 * vtable->klass points to the transparent proxy class, and not to @class.
2102 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2105 MonoVTable *vt, *pvt;
2106 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2108 GSList *extra_interfaces = NULL;
2109 MonoClass *class = remote_class->proxy_class;
2110 gpointer *interface_offsets;
2114 #ifdef COMPRESSED_INTERFACE_BITMAP
2118 vt = mono_class_vtable (domain, class);
2119 g_assert (vt); /*FIXME property handle failure*/
2120 max_interface_id = vt->max_interface_id;
2122 /* Calculate vtable space for extra interfaces */
2123 for (j = 0; j < remote_class->interface_count; j++) {
2124 MonoClass* iclass = remote_class->interfaces[j];
2128 /*FIXME test for interfaces with variant generic arguments*/
2129 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2130 continue; /* interface implemented by the class */
2131 if (g_slist_find (extra_interfaces, iclass))
2134 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2136 method_count = mono_class_num_methods (iclass);
2138 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2139 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2141 for (i = 0; i < ifaces->len; ++i) {
2142 MonoClass *ic = g_ptr_array_index (ifaces, i);
2143 /*FIXME test for interfaces with variant generic arguments*/
2144 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2145 continue; /* interface implemented by the class */
2146 if (g_slist_find (extra_interfaces, ic))
2148 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2149 method_count += mono_class_num_methods (ic);
2151 g_ptr_array_free (ifaces, TRUE);
2154 extra_interface_vtsize += method_count * sizeof (gpointer);
2155 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2159 mono_stats.imt_number_of_tables++;
2160 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2161 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2162 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2164 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2165 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2168 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2170 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2172 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2174 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2175 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2177 pvt->klass = mono_defaults.transparent_proxy_class;
2178 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2179 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2181 /* initialize vtable */
2182 mono_class_setup_vtable (class);
2183 for (i = 0; i < class->vtable_size; ++i) {
2186 if ((cm = class->vtable [i]))
2187 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2189 pvt->vtable [i] = NULL;
2192 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2193 /* create trampolines for abstract methods */
2194 for (k = class; k; k = k->parent) {
2196 gpointer iter = NULL;
2197 while ((m = mono_class_get_methods (k, &iter)))
2198 if (!pvt->vtable [m->slot])
2199 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2203 pvt->max_interface_id = max_interface_id;
2204 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2205 #ifdef COMPRESSED_INTERFACE_BITMAP
2206 bitmap = g_malloc0 (bsize);
2208 bitmap = mono_domain_alloc0 (domain, bsize);
2211 if (! ARCH_USE_IMT) {
2212 /* initialize interface offsets */
2213 for (i = 0; i < class->interface_offsets_count; ++i) {
2214 int interface_id = class->interfaces_packed [i]->interface_id;
2215 int slot = class->interface_offsets_packed [i];
2216 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2219 for (i = 0; i < class->interface_offsets_count; ++i) {
2220 int interface_id = class->interfaces_packed [i]->interface_id;
2221 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2224 if (extra_interfaces) {
2225 int slot = class->vtable_size;
2231 /* Create trampolines for the methods of the interfaces */
2232 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2233 interf = list_item->data;
2235 if (! ARCH_USE_IMT) {
2236 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2238 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2242 while ((cm = mono_class_get_methods (interf, &iter)))
2243 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2245 slot += mono_class_num_methods (interf);
2247 if (! ARCH_USE_IMT) {
2248 g_slist_free (extra_interfaces);
2253 /* Now that the vtable is full, we can actually fill up the IMT */
2254 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2255 if (extra_interfaces) {
2256 g_slist_free (extra_interfaces);
2260 #ifdef COMPRESSED_INTERFACE_BITMAP
2261 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2262 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2263 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2266 pvt->interface_bitmap = bitmap;
2272 * mono_class_field_is_special_static:
2274 * Returns whether @field is a thread/context static field.
2277 mono_class_field_is_special_static (MonoClassField *field)
2279 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2281 if (mono_field_is_deleted (field))
2283 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2284 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2291 * mono_class_has_special_static_fields:
2293 * Returns whenever @klass has any thread/context static fields.
2296 mono_class_has_special_static_fields (MonoClass *klass)
2298 MonoClassField *field;
2302 while ((field = mono_class_get_fields (klass, &iter))) {
2303 g_assert (field->parent == klass);
2304 if (mono_class_field_is_special_static (field))
2312 * create_remote_class_key:
2313 * Creates an array of pointers that can be used as a hash key for a remote class.
2314 * The first element of the array is the number of pointers.
2317 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2322 if (remote_class == NULL) {
2323 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2324 key = g_malloc (sizeof(gpointer) * 3);
2325 key [0] = GINT_TO_POINTER (2);
2326 key [1] = mono_defaults.marshalbyrefobject_class;
2327 key [2] = extra_class;
2329 key = g_malloc (sizeof(gpointer) * 2);
2330 key [0] = GINT_TO_POINTER (1);
2331 key [1] = extra_class;
2334 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2335 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2336 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2337 key [1] = remote_class->proxy_class;
2339 // Keep the list of interfaces sorted
2340 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2341 if (extra_class && remote_class->interfaces [i] > extra_class) {
2342 key [j++] = extra_class;
2345 key [j] = remote_class->interfaces [i];
2348 key [j] = extra_class;
2350 // Replace the old class. The interface list is the same
2351 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2352 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2353 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2354 for (i = 0; i < remote_class->interface_count; i++)
2355 key [2 + i] = remote_class->interfaces [i];
2363 * copy_remote_class_key:
2365 * Make a copy of KEY in the domain and return the copy.
2368 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2370 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2371 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2373 memcpy (mp_key, key, key_size);
2379 * mono_remote_class:
2380 * @domain: the application domain
2381 * @class_name: name of the remote class
2383 * Creates and initializes a MonoRemoteClass object for a remote type.
2385 * Can raise an exception on failure.
2388 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2391 MonoRemoteClass *rc;
2392 gpointer* key, *mp_key;
2395 key = create_remote_class_key (NULL, proxy_class);
2397 mono_domain_lock (domain);
2398 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2402 mono_domain_unlock (domain);
2406 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2407 if (!mono_error_ok (&error)) {
2409 mono_domain_unlock (domain);
2410 mono_error_raise_exception (&error);
2413 mp_key = copy_remote_class_key (domain, key);
2417 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2418 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2419 rc->interface_count = 1;
2420 rc->interfaces [0] = proxy_class;
2421 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2423 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2424 rc->interface_count = 0;
2425 rc->proxy_class = proxy_class;
2428 rc->default_vtable = NULL;
2429 rc->xdomain_vtable = NULL;
2430 rc->proxy_class_name = name;
2431 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2433 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2435 mono_domain_unlock (domain);
2440 * clone_remote_class:
2441 * Creates a copy of the remote_class, adding the provided class or interface
2443 static MonoRemoteClass*
2444 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2446 MonoRemoteClass *rc;
2447 gpointer* key, *mp_key;
2449 key = create_remote_class_key (remote_class, extra_class);
2450 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2456 mp_key = copy_remote_class_key (domain, key);
2460 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2462 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2463 rc->proxy_class = remote_class->proxy_class;
2464 rc->interface_count = remote_class->interface_count + 1;
2466 // Keep the list of interfaces sorted, since the hash key of
2467 // the remote class depends on this
2468 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2469 if (remote_class->interfaces [i] > extra_class && i == j)
2470 rc->interfaces [j++] = extra_class;
2471 rc->interfaces [j] = remote_class->interfaces [i];
2474 rc->interfaces [j] = extra_class;
2476 // Replace the old class. The interface array is the same
2477 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2478 rc->proxy_class = extra_class;
2479 rc->interface_count = remote_class->interface_count;
2480 if (rc->interface_count > 0)
2481 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2484 rc->default_vtable = NULL;
2485 rc->xdomain_vtable = NULL;
2486 rc->proxy_class_name = remote_class->proxy_class_name;
2488 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2494 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2496 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2497 mono_domain_lock (domain);
2498 if (rp->target_domain_id != -1) {
2499 if (remote_class->xdomain_vtable == NULL)
2500 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2501 mono_domain_unlock (domain);
2502 mono_loader_unlock ();
2503 return remote_class->xdomain_vtable;
2505 if (remote_class->default_vtable == NULL) {
2508 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2509 klass = mono_class_from_mono_type (type);
2510 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2511 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2513 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2516 mono_domain_unlock (domain);
2517 mono_loader_unlock ();
2518 return remote_class->default_vtable;
2522 * mono_upgrade_remote_class:
2523 * @domain: the application domain
2524 * @tproxy: the proxy whose remote class has to be upgraded.
2525 * @klass: class to which the remote class can be casted.
2527 * Updates the vtable of the remote class by adding the necessary method slots
2528 * and interface offsets so it can be safely casted to klass. klass can be a
2529 * class or an interface.
2532 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2534 MonoTransparentProxy *tproxy;
2535 MonoRemoteClass *remote_class;
2536 gboolean redo_vtable;
2538 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2539 mono_domain_lock (domain);
2541 tproxy = (MonoTransparentProxy*) proxy_object;
2542 remote_class = tproxy->remote_class;
2544 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2547 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2548 if (remote_class->interfaces [i] == klass)
2549 redo_vtable = FALSE;
2552 redo_vtable = (remote_class->proxy_class != klass);
2556 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2557 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2560 mono_domain_unlock (domain);
2561 mono_loader_unlock ();
2566 * mono_object_get_virtual_method:
2567 * @obj: object to operate on.
2570 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2571 * the instance of a callvirt of method.
2574 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2577 MonoMethod **vtable;
2579 MonoMethod *res = NULL;
2581 klass = mono_object_class (obj);
2582 if (klass == mono_defaults.transparent_proxy_class) {
2583 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2589 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2592 mono_class_setup_vtable (klass);
2593 vtable = klass->vtable;
2595 if (method->slot == -1) {
2596 /* method->slot might not be set for instances of generic methods */
2597 if (method->is_inflated) {
2598 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2599 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2602 g_assert_not_reached ();
2606 /* check method->slot is a valid index: perform isinstance? */
2607 if (method->slot != -1) {
2608 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2610 gboolean variance_used = FALSE;
2611 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2612 g_assert (iface_offset > 0);
2613 res = vtable [iface_offset + method->slot];
2616 res = vtable [method->slot];
2621 /* It may be an interface, abstract class method or generic method */
2622 if (!res || mono_method_signature (res)->generic_param_count)
2625 /* generic methods demand invoke_with_check */
2626 if (mono_method_signature (res)->generic_param_count)
2627 res = mono_marshal_get_remoting_invoke_with_check (res);
2630 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2631 res = mono_cominterop_get_invoke (res);
2634 res = mono_marshal_get_remoting_invoke (res);
2637 if (method->is_inflated) {
2638 /* Have to inflate the result */
2639 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2649 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2651 g_error ("runtime invoke called on uninitialized runtime");
2655 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2658 * mono_runtime_invoke:
2659 * @method: method to invoke
2660 * @obJ: object instance
2661 * @params: arguments to the method
2662 * @exc: exception information.
2664 * Invokes the method represented by @method on the object @obj.
2666 * obj is the 'this' pointer, it should be NULL for static
2667 * methods, a MonoObject* for object instances and a pointer to
2668 * the value type for value types.
2670 * The params array contains the arguments to the method with the
2671 * same convention: MonoObject* pointers for object instances and
2672 * pointers to the value type otherwise.
2674 * From unmanaged code you'll usually use the
2675 * mono_runtime_invoke() variant.
2677 * Note that this function doesn't handle virtual methods for
2678 * you, it will exec the exact method you pass: we still need to
2679 * expose a function to lookup the derived class implementation
2680 * of a virtual method (there are examples of this in the code,
2683 * You can pass NULL as the exc argument if you don't want to
2684 * catch exceptions, otherwise, *exc will be set to the exception
2685 * thrown, if any. if an exception is thrown, you can't use the
2686 * MonoObject* result from the function.
2688 * If the method returns a value type, it is boxed in an object
2692 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2696 if (mono_runtime_get_no_exec ())
2697 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2699 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2700 mono_profiler_method_start_invoke (method);
2702 result = default_mono_runtime_invoke (method, obj, params, exc);
2704 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2705 mono_profiler_method_end_invoke (method);
2711 * mono_method_get_unmanaged_thunk:
2712 * @method: method to generate a thunk for.
2714 * Returns an unmanaged->managed thunk that can be used to call
2715 * a managed method directly from C.
2717 * The thunk's C signature closely matches the managed signature:
2719 * C#: public bool Equals (object obj);
2720 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2721 * MonoObject*, MonoException**);
2723 * The 1st ("this") parameter must not be used with static methods:
2725 * C#: public static bool ReferenceEquals (object a, object b);
2726 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2729 * The last argument must be a non-null pointer of a MonoException* pointer.
2730 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2731 * exception has been thrown in managed code. Otherwise it will point
2732 * to the MonoException* caught by the thunk. In this case, the result of
2733 * the thunk is undefined:
2735 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2736 * MonoException *ex = NULL;
2737 * Equals func = mono_method_get_unmanaged_thunk (method);
2738 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2740 * // handle exception
2743 * The calling convention of the thunk matches the platform's default
2744 * convention. This means that under Windows, C declarations must
2745 * contain the __stdcall attribute:
2747 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2748 * MonoObject*, MonoException**);
2752 * Value type arguments and return values are treated as they were objects:
2754 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2755 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2757 * Arguments must be properly boxed upon trunk's invocation, while return
2758 * values must be unboxed.
2761 mono_method_get_unmanaged_thunk (MonoMethod *method)
2763 method = mono_marshal_get_thunk_invoke_wrapper (method);
2764 return mono_compile_method (method);
2768 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2772 /* object fields cannot be byref, so we don't need a
2774 gpointer *p = (gpointer*)dest;
2781 case MONO_TYPE_BOOLEAN:
2783 case MONO_TYPE_U1: {
2784 guint8 *p = (guint8*)dest;
2785 *p = value ? *(guint8*)value : 0;
2790 case MONO_TYPE_CHAR: {
2791 guint16 *p = (guint16*)dest;
2792 *p = value ? *(guint16*)value : 0;
2795 #if SIZEOF_VOID_P == 4
2800 case MONO_TYPE_U4: {
2801 gint32 *p = (gint32*)dest;
2802 *p = value ? *(gint32*)value : 0;
2805 #if SIZEOF_VOID_P == 8
2810 case MONO_TYPE_U8: {
2811 gint64 *p = (gint64*)dest;
2812 *p = value ? *(gint64*)value : 0;
2815 case MONO_TYPE_R4: {
2816 float *p = (float*)dest;
2817 *p = value ? *(float*)value : 0;
2820 case MONO_TYPE_R8: {
2821 double *p = (double*)dest;
2822 *p = value ? *(double*)value : 0;
2825 case MONO_TYPE_STRING:
2826 case MONO_TYPE_SZARRAY:
2827 case MONO_TYPE_CLASS:
2828 case MONO_TYPE_OBJECT:
2829 case MONO_TYPE_ARRAY:
2830 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2832 case MONO_TYPE_FNPTR:
2833 case MONO_TYPE_PTR: {
2834 gpointer *p = (gpointer*)dest;
2835 *p = deref_pointer? *(gpointer*)value: value;
2838 case MONO_TYPE_VALUETYPE:
2839 /* note that 't' and 'type->type' can be different */
2840 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2841 t = mono_class_enum_basetype (type->data.klass)->type;
2844 MonoClass *class = mono_class_from_mono_type (type);
2845 int size = mono_class_value_size (class, NULL);
2847 memset (dest, 0, size);
2849 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2852 case MONO_TYPE_GENERICINST:
2853 t = type->data.generic_class->container_class->byval_arg.type;
2856 g_warning ("got type %x", type->type);
2857 g_assert_not_reached ();
2862 * mono_field_set_value:
2863 * @obj: Instance object
2864 * @field: MonoClassField describing the field to set
2865 * @value: The value to be set
2867 * Sets the value of the field described by @field in the object instance @obj
2868 * to the value passed in @value. This method should only be used for instance
2869 * fields. For static fields, use mono_field_static_set_value.
2871 * The value must be on the native format of the field type.
2874 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2878 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2880 dest = (char*)obj + field->offset;
2881 set_value (field->type, dest, value, FALSE);
2885 * mono_field_static_set_value:
2886 * @field: MonoClassField describing the field to set
2887 * @value: The value to be set
2889 * Sets the value of the static field described by @field
2890 * to the value passed in @value.
2892 * The value must be on the native format of the field type.
2895 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2899 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2900 /* you cant set a constant! */
2901 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2903 if (field->offset == -1) {
2904 /* Special static */
2905 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2906 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2908 dest = (char*)vt->data + field->offset;
2910 set_value (field->type, dest, value, FALSE);
2913 /* Used by the debugger */
2915 mono_vtable_get_static_field_data (MonoVTable *vt)
2921 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2925 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2926 if (field->offset == -1) {
2927 /* Special static */
2928 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2929 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2931 src = (guint8*)vt->data + field->offset;
2934 src = (guint8*)obj + field->offset;
2941 * mono_field_get_value:
2942 * @obj: Object instance
2943 * @field: MonoClassField describing the field to fetch information from
2944 * @value: pointer to the location where the value will be stored
2946 * Use this routine to get the value of the field @field in the object
2949 * The pointer provided by value must be of the field type, for reference
2950 * types this is a MonoObject*, for value types its the actual pointer to
2955 * mono_field_get_value (obj, int_field, &i);
2958 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2964 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2966 src = (char*)obj + field->offset;
2967 set_value (field->type, value, src, TRUE);
2971 * mono_field_get_value_object:
2972 * @domain: domain where the object will be created (if boxing)
2973 * @field: MonoClassField describing the field to fetch information from
2974 * @obj: The object instance for the field.
2976 * Returns: a new MonoObject with the value from the given field. If the
2977 * field represents a value type, the value is boxed.
2981 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2985 MonoVTable *vtable = NULL;
2987 gboolean is_static = FALSE;
2988 gboolean is_ref = FALSE;
2989 gboolean is_literal = FALSE;
2991 switch (field->type->type) {
2992 case MONO_TYPE_STRING:
2993 case MONO_TYPE_OBJECT:
2994 case MONO_TYPE_CLASS:
2995 case MONO_TYPE_ARRAY:
2996 case MONO_TYPE_SZARRAY:
3001 case MONO_TYPE_BOOLEAN:
3004 case MONO_TYPE_CHAR:
3013 case MONO_TYPE_VALUETYPE:
3014 is_ref = field->type->byref;
3016 case MONO_TYPE_GENERICINST:
3017 is_ref = !mono_type_generic_inst_is_valuetype (field->type);
3020 g_error ("type 0x%x not handled in "
3021 "mono_field_get_value_object", field->type->type);
3025 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3028 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3032 vtable = mono_class_vtable (domain, field->parent);
3034 char *name = mono_type_get_full_name (field->parent);
3035 /*FIXME extend this to use the MonoError api*/
3036 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3040 if (!vtable->initialized)
3041 mono_runtime_class_init (vtable);
3049 get_default_field_value (domain, field, &o);
3050 } else if (is_static) {
3051 mono_field_static_get_value (vtable, field, &o);
3053 mono_field_get_value (obj, field, &o);
3058 /* boxed value type */
3059 klass = mono_class_from_mono_type (field->type);
3061 if (mono_class_is_nullable (klass))
3062 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3064 o = mono_object_new (domain, klass);
3065 v = ((gchar *) o) + sizeof (MonoObject);
3068 get_default_field_value (domain, field, v);
3069 } else if (is_static) {
3070 mono_field_static_get_value (vtable, field, v);
3072 mono_field_get_value (obj, field, v);
3079 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3082 const char *p = blob;
3083 mono_metadata_decode_blob_size (p, &p);
3086 case MONO_TYPE_BOOLEAN:
3089 *(guint8 *) value = *p;
3091 case MONO_TYPE_CHAR:
3094 *(guint16*) value = read16 (p);
3098 *(guint32*) value = read32 (p);
3102 *(guint64*) value = read64 (p);
3105 readr4 (p, (float*) value);
3108 readr8 (p, (double*) value);
3110 case MONO_TYPE_STRING:
3111 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3113 case MONO_TYPE_CLASS:
3114 *(gpointer*) value = NULL;
3118 g_warning ("type 0x%02x should not be in constant table", type);
3124 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3126 MonoTypeEnum def_type;
3129 data = mono_class_get_field_default_value (field, &def_type);
3130 mono_get_constant_value_from_blob (domain, def_type, data, value);
3134 * mono_field_static_get_value:
3135 * @vt: vtable to the object
3136 * @field: MonoClassField describing the field to fetch information from
3137 * @value: where the value is returned
3139 * Use this routine to get the value of the static field @field value.
3141 * The pointer provided by value must be of the field type, for reference
3142 * types this is a MonoObject*, for value types its the actual pointer to
3147 * mono_field_static_get_value (vt, int_field, &i);
3150 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3154 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3156 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3157 get_default_field_value (vt->domain, field, value);
3161 if (field->offset == -1) {
3162 /* Special static */
3163 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3164 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3166 src = (char*)vt->data + field->offset;
3168 set_value (field->type, value, src, TRUE);
3172 * mono_property_set_value:
3173 * @prop: MonoProperty to set
3174 * @obj: instance object on which to act
3175 * @params: parameters to pass to the propery
3176 * @exc: optional exception
3178 * Invokes the property's set method with the given arguments on the
3179 * object instance obj (or NULL for static properties).
3181 * You can pass NULL as the exc argument if you don't want to
3182 * catch exceptions, otherwise, *exc will be set to the exception
3183 * thrown, if any. if an exception is thrown, you can't use the
3184 * MonoObject* result from the function.
3187 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3189 default_mono_runtime_invoke (prop->set, obj, params, exc);
3193 * mono_property_get_value:
3194 * @prop: MonoProperty to fetch
3195 * @obj: instance object on which to act
3196 * @params: parameters to pass to the propery
3197 * @exc: optional exception
3199 * Invokes the property's get method with the given arguments on the
3200 * object instance obj (or NULL for static properties).
3202 * You can pass NULL as the exc argument if you don't want to
3203 * catch exceptions, otherwise, *exc will be set to the exception
3204 * thrown, if any. if an exception is thrown, you can't use the
3205 * MonoObject* result from the function.
3207 * Returns: the value from invoking the get method on the property.
3210 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3212 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3216 * mono_nullable_init:
3217 * @buf: The nullable structure to initialize.
3218 * @value: the value to initialize from
3219 * @klass: the type for the object
3221 * Initialize the nullable structure pointed to by @buf from @value which
3222 * should be a boxed value type. The size of @buf should be able to hold
3223 * as much data as the @klass->instance_size (which is the number of bytes
3224 * that will be copies).
3226 * Since Nullables have variable structure, we can not define a C
3227 * structure for them.
3230 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3232 MonoClass *param_class = klass->cast_class;
3234 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3235 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3237 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3239 if (param_class->has_references)
3240 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3242 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3244 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3249 * mono_nullable_box:
3250 * @buf: The buffer representing the data to be boxed
3251 * @klass: the type to box it as.
3253 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3257 mono_nullable_box (guint8 *buf, MonoClass *klass)
3259 MonoClass *param_class = klass->cast_class;
3261 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3262 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3264 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3265 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3266 if (param_class->has_references)
3267 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3269 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3277 * mono_get_delegate_invoke:
3278 * @klass: The delegate class
3280 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3283 mono_get_delegate_invoke (MonoClass *klass)
3287 /* This is called at runtime, so avoid the slower search in metadata */
3288 mono_class_setup_methods (klass);
3289 if (klass->exception_type)
3291 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3296 * mono_runtime_delegate_invoke:
3297 * @delegate: pointer to a delegate object.
3298 * @params: parameters for the delegate.
3299 * @exc: Pointer to the exception result.
3301 * Invokes the delegate method @delegate with the parameters provided.
3303 * You can pass NULL as the exc argument if you don't want to
3304 * catch exceptions, otherwise, *exc will be set to the exception
3305 * thrown, if any. if an exception is thrown, you can't use the
3306 * MonoObject* result from the function.
3309 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3313 im = mono_get_delegate_invoke (delegate->vtable->klass);
3316 return mono_runtime_invoke (im, delegate, params, exc);
3319 static char **main_args = NULL;
3320 static int num_main_args;
3323 * mono_runtime_get_main_args:
3325 * Returns: a MonoArray with the arguments passed to the main program
3328 mono_runtime_get_main_args (void)
3332 MonoDomain *domain = mono_domain_get ();
3337 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3339 for (i = 0; i < num_main_args; ++i)
3340 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3346 * mono_runtime_run_main:
3347 * @method: the method to start the application with (usually Main)
3348 * @argc: number of arguments from the command line
3349 * @argv: array of strings from the command line
3350 * @exc: excetption results
3352 * Execute a standard Main() method (argc/argv contains the
3353 * executable name). This method also sets the command line argument value
3354 * needed by System.Environment.
3359 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3363 MonoArray *args = NULL;
3364 MonoDomain *domain = mono_domain_get ();
3365 gchar *utf8_fullpath;
3367 g_assert (method != NULL);
3369 mono_thread_set_main (mono_thread_current ());
3371 main_args = g_new0 (char*, argc);
3372 num_main_args = argc;
3374 if (!g_path_is_absolute (argv [0])) {
3375 gchar *basename = g_path_get_basename (argv [0]);
3376 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3380 utf8_fullpath = mono_utf8_from_external (fullpath);
3381 if(utf8_fullpath == NULL) {
3382 /* Printing the arg text will cause glib to
3383 * whinge about "Invalid UTF-8", but at least
3384 * its relevant, and shows the problem text
3387 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3388 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3395 utf8_fullpath = mono_utf8_from_external (argv[0]);
3396 if(utf8_fullpath == NULL) {
3397 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3398 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3403 main_args [0] = utf8_fullpath;
3405 for (i = 1; i < argc; ++i) {
3408 utf8_arg=mono_utf8_from_external (argv[i]);
3409 if(utf8_arg==NULL) {
3410 /* Ditto the comment about Invalid UTF-8 here */
3411 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3412 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3416 main_args [i] = utf8_arg;
3420 if (mono_method_signature (method)->param_count) {
3421 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3422 for (i = 0; i < argc; ++i) {
3423 /* The encodings should all work, given that
3424 * we've checked all these args for the
3427 gchar *str = mono_utf8_from_external (argv [i]);
3428 MonoString *arg = mono_string_new (domain, str);
3429 mono_array_setref (args, i, arg);
3433 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3436 mono_assembly_set_main (method->klass->image->assembly);
3438 return mono_runtime_exec_main (method, args, exc);
3442 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3444 static MonoMethod *serialize_method;
3449 if (!serialize_method) {
3450 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3451 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3454 if (!serialize_method) {
3459 g_assert (!mono_object_class (obj)->marshalbyref);
3463 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3471 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3473 static MonoMethod *deserialize_method;
3478 if (!deserialize_method) {
3479 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3480 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3482 if (!deserialize_method) {
3489 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3497 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3499 static MonoMethod *get_proxy_method;
3501 MonoDomain *domain = mono_domain_get ();
3502 MonoRealProxy *real_proxy;
3503 MonoReflectionType *reflection_type;
3504 MonoTransparentProxy *transparent_proxy;
3506 if (!get_proxy_method)
3507 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3509 g_assert (obj->vtable->klass->marshalbyref);
3511 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3512 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3514 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3515 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3518 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3522 return (MonoObject*) transparent_proxy;
3526 * mono_object_xdomain_representation
3528 * @target_domain: a domain
3529 * @exc: pointer to a MonoObject*
3531 * Creates a representation of obj in the domain target_domain. This
3532 * is either a copy of obj arrived through via serialization and
3533 * deserialization or a proxy, depending on whether the object is
3534 * serializable or marshal by ref. obj must not be in target_domain.
3536 * If the object cannot be represented in target_domain, NULL is
3537 * returned and *exc is set to an appropriate exception.
3540 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3542 MonoObject *deserialized = NULL;
3543 gboolean failure = FALSE;
3547 if (mono_object_class (obj)->marshalbyref) {
3548 deserialized = make_transparent_proxy (obj, &failure, exc);
3550 MonoDomain *domain = mono_domain_get ();
3551 MonoObject *serialized;
3553 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3554 serialized = serialize_object (obj, &failure, exc);
3555 mono_domain_set_internal_with_options (target_domain, FALSE);
3557 deserialized = deserialize_object (serialized, &failure, exc);
3558 if (domain != target_domain)
3559 mono_domain_set_internal_with_options (domain, FALSE);
3562 return deserialized;
3565 /* Used in call_unhandled_exception_delegate */
3567 create_unhandled_exception_eventargs (MonoObject *exc)
3571 MonoMethod *method = NULL;
3572 MonoBoolean is_terminating = TRUE;
3575 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3578 mono_class_init (klass);
3580 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3581 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3585 args [1] = &is_terminating;
3587 obj = mono_object_new (mono_domain_get (), klass);
3588 mono_runtime_invoke (method, obj, args, NULL);
3593 /* Used in mono_unhandled_exception */
3595 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3596 MonoObject *e = NULL;
3598 MonoDomain *current_domain = mono_domain_get ();
3600 if (domain != current_domain)
3601 mono_domain_set_internal_with_options (domain, FALSE);
3603 g_assert (domain == mono_object_domain (domain->domain));
3605 if (mono_object_domain (exc) != domain) {
3606 MonoObject *serialization_exc;
3608 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3610 if (serialization_exc) {
3612 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3615 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3616 "System.Runtime.Serialization", "SerializationException",
3617 "Could not serialize unhandled exception.");
3621 g_assert (mono_object_domain (exc) == domain);
3623 pa [0] = domain->domain;
3624 pa [1] = create_unhandled_exception_eventargs (exc);
3625 mono_runtime_delegate_invoke (delegate, pa, &e);
3627 if (domain != current_domain)
3628 mono_domain_set_internal_with_options (current_domain, FALSE);
3632 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3633 if (!mono_error_ok (&error)) {
3634 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3635 mono_error_cleanup (&error);
3637 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3643 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3646 * mono_runtime_unhandled_exception_policy_set:
3647 * @policy: the new policy
3649 * This is a VM internal routine.
3651 * Sets the runtime policy for handling unhandled exceptions.
3654 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3655 runtime_unhandled_exception_policy = policy;
3659 * mono_runtime_unhandled_exception_policy_get:
3661 * This is a VM internal routine.
3663 * Gets the runtime policy for handling unhandled exceptions.
3665 MonoRuntimeUnhandledExceptionPolicy
3666 mono_runtime_unhandled_exception_policy_get (void) {
3667 return runtime_unhandled_exception_policy;
3671 * mono_unhandled_exception:
3672 * @exc: exception thrown
3674 * This is a VM internal routine.
3676 * We call this function when we detect an unhandled exception
3677 * in the default domain.
3679 * It invokes the * UnhandledException event in AppDomain or prints
3680 * a warning to the console
3683 mono_unhandled_exception (MonoObject *exc)
3685 MonoDomain *current_domain = mono_domain_get ();
3686 MonoDomain *root_domain = mono_get_root_domain ();
3687 MonoClassField *field;
3688 MonoObject *current_appdomain_delegate;
3689 MonoObject *root_appdomain_delegate;
3691 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3692 "UnhandledException");
3695 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3696 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3697 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3698 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3699 if (current_domain != root_domain) {
3700 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3702 current_appdomain_delegate = NULL;
3705 /* set exitcode only if we will abort the process */
3707 mono_environment_exitcode_set (1);
3708 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3709 mono_print_unhandled_exception (exc);
3711 if (root_appdomain_delegate) {
3712 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3714 if (current_appdomain_delegate) {
3715 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3722 * mono_runtime_exec_managed_code:
3723 * @domain: Application domain
3724 * @main_func: function to invoke from the execution thread
3725 * @main_args: parameter to the main_func
3727 * Launch a new thread to execute a function
3729 * main_func is called back from the thread with main_args as the
3730 * parameter. The callback function is expected to start Main()
3731 * eventually. This function then waits for all managed threads to
3733 * It is not necesseray anymore to execute managed code in a subthread,
3734 * so this function should not be used anymore by default: just
3735 * execute the code and then call mono_thread_manage ().
3738 mono_runtime_exec_managed_code (MonoDomain *domain,
3739 MonoMainThreadFunc main_func,
3742 mono_thread_create (domain, main_func, main_args);
3744 mono_thread_manage ();
3748 * Execute a standard Main() method (args doesn't contain the
3752 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3757 MonoCustomAttrInfo* cinfo;
3758 gboolean has_stathread_attribute;
3759 MonoInternalThread* thread = mono_thread_internal_current ();
3765 domain = mono_object_domain (args);
3766 if (!domain->entry_assembly) {
3768 MonoAssembly *assembly;
3770 assembly = method->klass->image->assembly;
3771 domain->entry_assembly = assembly;
3772 /* Domains created from another domain already have application_base and configuration_file set */
3773 if (domain->setup->application_base == NULL) {
3774 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3777 if (domain->setup->configuration_file == NULL) {
3778 str = g_strconcat (assembly->image->name, ".config", NULL);
3779 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3781 mono_set_private_bin_path_from_config (domain);
3785 cinfo = mono_custom_attrs_from_method (method);
3787 static MonoClass *stathread_attribute = NULL;
3788 if (!stathread_attribute)
3789 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3790 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3792 mono_custom_attrs_free (cinfo);
3794 has_stathread_attribute = FALSE;
3796 if (has_stathread_attribute) {
3797 thread->apartment_state = ThreadApartmentState_STA;
3799 thread->apartment_state = ThreadApartmentState_MTA;
3801 mono_thread_init_apartment_state ();
3803 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3805 /* FIXME: check signature of method */
3806 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3808 res = mono_runtime_invoke (method, NULL, pa, exc);
3810 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3814 mono_environment_exitcode_set (rval);
3816 mono_runtime_invoke (method, NULL, pa, exc);
3820 /* If the return type of Main is void, only
3821 * set the exitcode if an exception was thrown
3822 * (we don't want to blow away an
3823 * explicitly-set exit code)
3826 mono_environment_exitcode_set (rval);
3830 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3836 * mono_install_runtime_invoke:
3837 * @func: Function to install
3839 * This is a VM internal routine
3842 mono_install_runtime_invoke (MonoInvokeFunc func)
3844 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3849 * mono_runtime_invoke_array:
3850 * @method: method to invoke
3851 * @obJ: object instance
3852 * @params: arguments to the method
3853 * @exc: exception information.
3855 * Invokes the method represented by @method on the object @obj.
3857 * obj is the 'this' pointer, it should be NULL for static
3858 * methods, a MonoObject* for object instances and a pointer to
3859 * the value type for value types.
3861 * The params array contains the arguments to the method with the
3862 * same convention: MonoObject* pointers for object instances and
3863 * pointers to the value type otherwise. The _invoke_array
3864 * variant takes a C# object[] as the params argument (MonoArray
3865 * *params): in this case the value types are boxed inside the
3866 * respective reference representation.
3868 * From unmanaged code you'll usually use the
3869 * mono_runtime_invoke() variant.
3871 * Note that this function doesn't handle virtual methods for
3872 * you, it will exec the exact method you pass: we still need to
3873 * expose a function to lookup the derived class implementation
3874 * of a virtual method (there are examples of this in the code,
3877 * You can pass NULL as the exc argument if you don't want to
3878 * catch exceptions, otherwise, *exc will be set to the exception
3879 * thrown, if any. if an exception is thrown, you can't use the
3880 * MonoObject* result from the function.
3882 * If the method returns a value type, it is boxed in an object
3886 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3889 MonoMethodSignature *sig = mono_method_signature (method);
3890 gpointer *pa = NULL;
3893 gboolean has_byref_nullables = FALSE;
3895 if (NULL != params) {
3896 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3897 for (i = 0; i < mono_array_length (params); i++) {
3898 MonoType *t = sig->params [i];
3904 case MONO_TYPE_BOOLEAN:
3907 case MONO_TYPE_CHAR:
3916 case MONO_TYPE_VALUETYPE:
3917 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3918 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3919 pa [i] = mono_array_get (params, MonoObject*, i);
3921 has_byref_nullables = TRUE;
3923 /* MS seems to create the objects if a null is passed in */
3924 if (!mono_array_get (params, MonoObject*, i))
3925 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3929 * We can't pass the unboxed vtype byref to the callee, since
3930 * that would mean the callee would be able to modify boxed
3931 * primitive types. So we (and MS) make a copy of the boxed
3932 * object, pass that to the callee, and replace the original
3933 * boxed object in the arg array with the copy.
3935 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3936 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3937 mono_array_setref (params, i, copy);
3940 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3943 case MONO_TYPE_STRING:
3944 case MONO_TYPE_OBJECT:
3945 case MONO_TYPE_CLASS:
3946 case MONO_TYPE_ARRAY:
3947 case MONO_TYPE_SZARRAY:
3949 pa [i] = mono_array_addr (params, MonoObject*, i);
3950 // FIXME: I need to check this code path
3952 pa [i] = mono_array_get (params, MonoObject*, i);
3954 case MONO_TYPE_GENERICINST:
3956 t = &t->data.generic_class->container_class->this_arg;
3958 t = &t->data.generic_class->container_class->byval_arg;
3960 case MONO_TYPE_PTR: {
3963 /* The argument should be an IntPtr */
3964 arg = mono_array_get (params, MonoObject*, i);
3968 g_assert (arg->vtable->klass == mono_defaults.int_class);
3969 pa [i] = ((MonoIntPtr*)arg)->m_value;
3974 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3979 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3982 if (mono_class_is_nullable (method->klass)) {
3983 /* Need to create a boxed vtype instead */
3989 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3993 obj = mono_object_new (mono_domain_get (), method->klass);
3994 g_assert (obj); /*maybe we should raise a TLE instead?*/
3995 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3996 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3998 if (method->klass->valuetype)
3999 o = mono_object_unbox (obj);
4002 } else if (method->klass->valuetype) {
4003 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4006 mono_runtime_invoke (method, o, pa, exc);
4009 if (mono_class_is_nullable (method->klass)) {
4010 MonoObject *nullable;
4012 /* Convert the unboxed vtype into a Nullable structure */
4013 nullable = mono_object_new (mono_domain_get (), method->klass);
4015 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4016 obj = mono_object_unbox (nullable);
4019 /* obj must be already unboxed if needed */
4020 res = mono_runtime_invoke (method, obj, pa, exc);
4022 if (sig->ret->type == MONO_TYPE_PTR) {
4023 MonoClass *pointer_class;
4024 static MonoMethod *box_method;
4026 MonoObject *box_exc;
4029 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4030 * convert it to a Pointer object.
4032 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4034 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4036 g_assert (res->vtable->klass == mono_defaults.int_class);
4037 box_args [0] = ((MonoIntPtr*)res)->m_value;
4038 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4039 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4040 g_assert (!box_exc);
4043 if (has_byref_nullables) {
4045 * The runtime invoke wrapper already converted byref nullables back,
4046 * and stored them in pa, we just need to copy them back to the
4049 for (i = 0; i < mono_array_length (params); i++) {
4050 MonoType *t = sig->params [i];
4052 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4053 mono_array_setref (params, i, pa [i]);
4062 arith_overflow (void)
4064 mono_raise_exception (mono_get_exception_overflow ());
4068 * mono_object_allocate:
4069 * @size: number of bytes to allocate
4071 * This is a very simplistic routine until we have our GC-aware
4074 * Returns: an allocated object of size @size, or NULL on failure.
4076 static inline void *
4077 mono_object_allocate (size_t size, MonoVTable *vtable)
4080 mono_stats.new_object_count++;
4081 ALLOC_OBJECT (o, vtable, size);
4087 * mono_object_allocate_ptrfree:
4088 * @size: number of bytes to allocate
4090 * Note that the memory allocated is not zeroed.
4091 * Returns: an allocated object of size @size, or NULL on failure.
4093 static inline void *
4094 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4097 mono_stats.new_object_count++;
4098 ALLOC_PTRFREE (o, vtable, size);
4102 static inline void *
4103 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4106 ALLOC_TYPED (o, size, vtable);
4107 mono_stats.new_object_count++;
4114 * @klass: the class of the object that we want to create
4116 * Returns: a newly created object whose definition is
4117 * looked up using @klass. This will not invoke any constructors,
4118 * so the consumer of this routine has to invoke any constructors on
4119 * its own to initialize the object.
4121 * It returns NULL on failure.
4124 mono_object_new (MonoDomain *domain, MonoClass *klass)
4128 MONO_ARCH_SAVE_REGS;
4129 vtable = mono_class_vtable (domain, klass);
4132 return mono_object_new_specific (vtable);
4136 * mono_object_new_specific:
4137 * @vtable: the vtable of the object that we want to create
4139 * Returns: A newly created object with class and domain specified
4143 mono_object_new_specific (MonoVTable *vtable)
4147 MONO_ARCH_SAVE_REGS;
4149 /* check for is_com_object for COM Interop */
4150 if (vtable->remote || vtable->klass->is_com_object)
4153 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4156 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4159 mono_class_init (klass);
4161 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4163 vtable->domain->create_proxy_for_type_method = im;
4166 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4168 o = mono_runtime_invoke (im, NULL, pa, NULL);
4169 if (o != NULL) return o;
4172 return mono_object_new_alloc_specific (vtable);
4176 mono_object_new_alloc_specific (MonoVTable *vtable)
4180 if (!vtable->klass->has_references) {
4181 o = mono_object_new_ptrfree (vtable);
4182 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4183 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4185 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4186 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4188 if (G_UNLIKELY (vtable->klass->has_finalize))
4189 mono_object_register_finalizer (o);
4191 if (G_UNLIKELY (profile_allocs))
4192 mono_profiler_allocation (o, vtable->klass);
4197 mono_object_new_fast (MonoVTable *vtable)
4200 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4205 mono_object_new_ptrfree (MonoVTable *vtable)
4208 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4209 #if NEED_TO_ZERO_PTRFREE
4210 /* an inline memset is much faster for the common vcase of small objects
4211 * note we assume the allocated size is a multiple of sizeof (void*).
4213 if (vtable->klass->instance_size < 128) {
4215 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4216 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4222 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4229 mono_object_new_ptrfree_box (MonoVTable *vtable)
4232 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4233 /* the object will be boxed right away, no need to memzero it */
4238 * mono_class_get_allocation_ftn:
4240 * @for_box: the object will be used for boxing
4241 * @pass_size_in_words:
4243 * Return the allocation function appropriate for the given class.
4247 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4249 *pass_size_in_words = FALSE;
4251 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4252 profile_allocs = FALSE;
4254 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4255 return mono_object_new_specific;
4257 if (!vtable->klass->has_references) {
4258 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4260 return mono_object_new_ptrfree_box;
4261 return mono_object_new_ptrfree;
4264 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4266 return mono_object_new_fast;
4269 * FIXME: This is actually slower than mono_object_new_fast, because
4270 * of the overhead of parameter passing.
4273 *pass_size_in_words = TRUE;
4274 #ifdef GC_REDIRECT_TO_LOCAL
4275 return GC_local_gcj_fast_malloc;
4277 return GC_gcj_fast_malloc;
4282 return mono_object_new_specific;
4286 * mono_object_new_from_token:
4287 * @image: Context where the type_token is hosted
4288 * @token: a token of the type that we want to create
4290 * Returns: A newly created object whose definition is
4291 * looked up using @token in the @image image
4294 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4298 class = mono_class_get (image, token);
4300 return mono_object_new (domain, class);
4305 * mono_object_clone:
4306 * @obj: the object to clone
4308 * Returns: A newly created object who is a shallow copy of @obj
4311 mono_object_clone (MonoObject *obj)
4314 int size = obj->vtable->klass->instance_size;
4316 o = mono_object_allocate (size, obj->vtable);
4318 if (obj->vtable->klass->has_references) {
4319 mono_gc_wbarrier_object_copy (o, obj);
4321 int size = obj->vtable->klass->instance_size;
4322 /* do not copy the sync state */
4323 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4325 if (G_UNLIKELY (profile_allocs))
4326 mono_profiler_allocation (o, obj->vtable->klass);
4328 if (obj->vtable->klass->has_finalize)
4329 mono_object_register_finalizer (o);
4334 * mono_array_full_copy:
4335 * @src: source array to copy
4336 * @dest: destination array
4338 * Copies the content of one array to another with exactly the same type and size.
4341 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4344 MonoClass *klass = src->obj.vtable->klass;
4346 MONO_ARCH_SAVE_REGS;
4348 g_assert (klass == dest->obj.vtable->klass);
4350 size = mono_array_length (src);
4351 g_assert (size == mono_array_length (dest));
4352 size *= mono_array_element_size (klass);
4354 if (klass->element_class->valuetype) {
4355 if (klass->element_class->has_references)
4356 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4358 memcpy (&dest->vector, &src->vector, size);
4360 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4363 memcpy (&dest->vector, &src->vector, size);
4368 * mono_array_clone_in_domain:
4369 * @domain: the domain in which the array will be cloned into
4370 * @array: the array to clone
4372 * This routine returns a copy of the array that is hosted on the
4373 * specified MonoDomain.
4376 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4381 MonoClass *klass = array->obj.vtable->klass;
4383 MONO_ARCH_SAVE_REGS;
4385 if (array->bounds == NULL) {
4386 size = mono_array_length (array);
4387 o = mono_array_new_full (domain, klass, &size, NULL);
4389 size *= mono_array_element_size (klass);
4391 if (klass->element_class->valuetype) {
4392 if (klass->element_class->has_references)
4393 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4395 memcpy (&o->vector, &array->vector, size);
4397 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4400 memcpy (&o->vector, &array->vector, size);
4405 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4406 size = mono_array_element_size (klass);
4407 for (i = 0; i < klass->rank; ++i) {
4408 sizes [i] = array->bounds [i].length;
4409 size *= array->bounds [i].length;
4410 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4412 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4414 if (klass->element_class->valuetype) {
4415 if (klass->element_class->has_references)
4416 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4418 memcpy (&o->vector, &array->vector, size);
4420 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4423 memcpy (&o->vector, &array->vector, size);
4431 * @array: the array to clone
4433 * Returns: A newly created array who is a shallow copy of @array
4436 mono_array_clone (MonoArray *array)
4438 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4441 /* helper macros to check for overflow when calculating the size of arrays */
4442 #ifdef MONO_BIG_ARRAYS
4443 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4444 #define MYGUINT_MAX MYGUINT64_MAX
4445 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4446 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4447 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4448 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4449 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4451 #define MYGUINT32_MAX 4294967295U
4452 #define MYGUINT_MAX MYGUINT32_MAX
4453 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4454 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4455 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4456 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4457 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4461 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4465 byte_len = mono_array_element_size (class);
4466 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4469 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4471 byte_len += sizeof (MonoArray);
4479 * mono_array_new_full:
4480 * @domain: domain where the object is created
4481 * @array_class: array class
4482 * @lengths: lengths for each dimension in the array
4483 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4485 * This routine creates a new array objects with the given dimensions,
4486 * lower bounds and type.
4489 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4491 uintptr_t byte_len, len, bounds_size;
4494 MonoArrayBounds *bounds;
4498 if (!array_class->inited)
4499 mono_class_init (array_class);
4503 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4504 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4506 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4510 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4512 for (i = 0; i < array_class->rank; ++i) {
4513 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4515 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4516 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4521 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4522 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4526 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4527 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4528 byte_len = (byte_len + 3) & ~3;
4529 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4530 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4531 byte_len += bounds_size;
4534 * Following three lines almost taken from mono_object_new ():
4535 * they need to be kept in sync.
4537 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4538 #ifndef HAVE_SGEN_GC
4539 if (!array_class->has_references) {
4540 o = mono_object_allocate_ptrfree (byte_len, vtable);
4541 #if NEED_TO_ZERO_PTRFREE
4542 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4544 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4545 o = mono_object_allocate_spec (byte_len, vtable);
4547 o = mono_object_allocate (byte_len, vtable);
4550 array = (MonoArray*)o;
4551 array->max_length = len;
4554 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4555 array->bounds = bounds;
4559 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4561 o = mono_gc_alloc_vector (vtable, byte_len, len);
4562 array = (MonoArray*)o;
4563 mono_stats.new_object_count++;
4565 bounds = array->bounds;
4569 for (i = 0; i < array_class->rank; ++i) {
4570 bounds [i].length = lengths [i];
4572 bounds [i].lower_bound = lower_bounds [i];
4576 if (G_UNLIKELY (profile_allocs))
4577 mono_profiler_allocation (o, array_class);
4584 * @domain: domain where the object is created
4585 * @eclass: element class
4586 * @n: number of array elements
4588 * This routine creates a new szarray with @n elements of type @eclass.
4591 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4595 MONO_ARCH_SAVE_REGS;
4597 ac = mono_array_class_get (eclass, 1);
4600 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4604 * mono_array_new_specific:
4605 * @vtable: a vtable in the appropriate domain for an initialized class
4606 * @n: number of array elements
4608 * This routine is a fast alternative to mono_array_new() for code which
4609 * can be sure about the domain it operates in.
4612 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4618 MONO_ARCH_SAVE_REGS;
4620 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4625 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4626 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4629 #ifndef HAVE_SGEN_GC
4630 if (!vtable->klass->has_references) {
4631 o = mono_object_allocate_ptrfree (byte_len, vtable);
4632 #if NEED_TO_ZERO_PTRFREE
4633 ((MonoArray*)o)->bounds = NULL;
4634 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4636 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4637 o = mono_object_allocate_spec (byte_len, vtable);
4639 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4640 o = mono_object_allocate (byte_len, vtable);
4643 ao = (MonoArray *)o;
4646 o = mono_gc_alloc_vector (vtable, byte_len, n);
4648 mono_stats.new_object_count++;
4651 if (G_UNLIKELY (profile_allocs))
4652 mono_profiler_allocation (o, vtable->klass);
4658 * mono_string_new_utf16:
4659 * @text: a pointer to an utf16 string
4660 * @len: the length of the string
4662 * Returns: A newly created string object which contains @text.
4665 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4669 s = mono_string_new_size (domain, len);
4670 g_assert (s != NULL);
4672 memcpy (mono_string_chars (s), text, len * 2);
4678 * mono_string_new_size:
4679 * @text: a pointer to an utf16 string
4680 * @len: the length of the string
4682 * Returns: A newly created string object of @len
4685 mono_string_new_size (MonoDomain *domain, gint32 len)
4689 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4691 /* overflow ? can't fit it, can't allocate it! */
4693 mono_gc_out_of_memory (-1);
4695 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4698 #ifndef HAVE_SGEN_GC
4699 s = mono_object_allocate_ptrfree (size, vtable);
4703 s = mono_gc_alloc_string (vtable, size, len);
4705 #if NEED_TO_ZERO_PTRFREE
4708 if (G_UNLIKELY (profile_allocs))
4709 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4715 * mono_string_new_len:
4716 * @text: a pointer to an utf8 string
4717 * @length: number of bytes in @text to consider
4719 * Returns: A newly created string object which contains @text.
4722 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4724 GError *error = NULL;
4725 MonoString *o = NULL;
4727 glong items_written;
4729 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4732 o = mono_string_new_utf16 (domain, ut, items_written);
4734 g_error_free (error);
4743 * @text: a pointer to an utf8 string
4745 * Returns: A newly created string object which contains @text.
4748 mono_string_new (MonoDomain *domain, const char *text)
4750 GError *error = NULL;
4751 MonoString *o = NULL;
4753 glong items_written;
4758 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4761 o = mono_string_new_utf16 (domain, ut, items_written);
4763 g_error_free (error);
4766 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4771 MonoString *o = NULL;
4773 if (!g_utf8_validate (text, -1, &end))
4776 len = g_utf8_strlen (text, -1);
4777 o = mono_string_new_size (domain, len);
4778 str = mono_string_chars (o);
4780 while (text < end) {
4781 *str++ = g_utf8_get_char (text);
4782 text = g_utf8_next_char (text);
4789 * mono_string_new_wrapper:
4790 * @text: pointer to utf8 characters.
4792 * Helper function to create a string object from @text in the current domain.
4795 mono_string_new_wrapper (const char *text)
4797 MonoDomain *domain = mono_domain_get ();
4799 MONO_ARCH_SAVE_REGS;
4802 return mono_string_new (domain, text);
4809 * @class: the class of the value
4810 * @value: a pointer to the unboxed data
4812 * Returns: A newly created object which contains @value.
4815 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4821 g_assert (class->valuetype);
4822 if (mono_class_is_nullable (class))
4823 return mono_nullable_box (value, class);
4825 vtable = mono_class_vtable (domain, class);
4828 size = mono_class_instance_size (class);
4829 res = mono_object_new_alloc_specific (vtable);
4830 if (G_UNLIKELY (profile_allocs))
4831 mono_profiler_allocation (res, class);
4833 size = size - sizeof (MonoObject);
4836 g_assert (size == mono_class_value_size (class, NULL));
4837 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4839 #if NO_UNALIGNED_ACCESS
4840 memcpy ((char *)res + sizeof (MonoObject), value, size);
4844 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4847 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4850 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4853 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4856 memcpy ((char *)res + sizeof (MonoObject), value, size);
4860 if (class->has_finalize)
4861 mono_object_register_finalizer (res);
4867 * @dest: destination pointer
4868 * @src: source pointer
4869 * @klass: a valuetype class
4871 * Copy a valuetype from @src to @dest. This function must be used
4872 * when @klass contains references fields.
4875 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4877 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4881 * mono_value_copy_array:
4882 * @dest: destination array
4883 * @dest_idx: index in the @dest array
4884 * @src: source pointer
4885 * @count: number of items
4887 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4888 * This function must be used when @klass contains references fields.
4889 * Overlap is handled.
4892 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4894 int size = mono_array_element_size (dest->obj.vtable->klass);
4895 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4896 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4897 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4901 * mono_object_get_domain:
4902 * @obj: object to query
4904 * Returns: the MonoDomain where the object is hosted
4907 mono_object_get_domain (MonoObject *obj)
4909 return mono_object_domain (obj);
4913 * mono_object_get_class:
4914 * @obj: object to query
4916 * Returns: the MonOClass of the object.
4919 mono_object_get_class (MonoObject *obj)
4921 return mono_object_class (obj);
4924 * mono_object_get_size:
4925 * @o: object to query
4927 * Returns: the size, in bytes, of @o
4930 mono_object_get_size (MonoObject* o)
4932 MonoClass* klass = mono_object_class (o);
4933 if (klass == mono_defaults.string_class) {
4934 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4935 } else if (o->vtable->rank) {
4936 MonoArray *array = (MonoArray*)o;
4937 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4938 if (array->bounds) {
4941 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4945 return mono_class_instance_size (klass);
4950 * mono_object_unbox:
4951 * @obj: object to unbox
4953 * Returns: a pointer to the start of the valuetype boxed in this
4956 * This method will assert if the object passed is not a valuetype.
4959 mono_object_unbox (MonoObject *obj)
4961 /* add assert for valuetypes? */
4962 g_assert (obj->vtable->klass->valuetype);
4963 return ((char*)obj) + sizeof (MonoObject);
4967 * mono_object_isinst:
4969 * @klass: a pointer to a class
4971 * Returns: @obj if @obj is derived from @klass
4974 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4977 mono_class_init (klass);
4979 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
4980 return mono_object_isinst_mbyref (obj, klass);
4985 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4989 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4998 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4999 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5003 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5004 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5007 MonoClass *oklass = vt->klass;
5008 if ((oklass == mono_defaults.transparent_proxy_class))
5009 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5011 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5015 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5017 MonoDomain *domain = mono_domain_get ();
5019 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5020 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5021 MonoMethod *im = NULL;
5024 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5025 im = mono_object_get_virtual_method (rp, im);
5028 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5031 res = mono_runtime_invoke (im, rp, pa, NULL);
5033 if (*(MonoBoolean *) mono_object_unbox(res)) {
5034 /* Update the vtable of the remote type, so it can safely cast to this new type */
5035 mono_upgrade_remote_class (domain, obj, klass);
5044 * mono_object_castclass_mbyref:
5046 * @klass: a pointer to a class
5048 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5051 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5053 if (!obj) return NULL;
5054 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5056 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5058 "InvalidCastException"));
5063 MonoDomain *orig_domain;
5069 str_lookup (MonoDomain *domain, gpointer user_data)
5071 LDStrInfo *info = user_data;
5072 if (info->res || domain == info->orig_domain)
5074 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5080 mono_string_get_pinned (MonoString *str)
5084 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5085 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5086 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5087 news->length = mono_string_length (str);
5092 #define mono_string_get_pinned(str) (str)
5096 mono_string_is_interned_lookup (MonoString *str, int insert)
5098 MonoGHashTable *ldstr_table;
5102 domain = ((MonoObject *)str)->vtable->domain;
5103 ldstr_table = domain->ldstr_table;
5105 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5110 str = mono_string_get_pinned (str);
5111 mono_g_hash_table_insert (ldstr_table, str, str);
5115 LDStrInfo ldstr_info;
5116 ldstr_info.orig_domain = domain;
5117 ldstr_info.ins = str;
5118 ldstr_info.res = NULL;
5120 mono_domain_foreach (str_lookup, &ldstr_info);
5121 if (ldstr_info.res) {
5123 * the string was already interned in some other domain:
5124 * intern it in the current one as well.
5126 mono_g_hash_table_insert (ldstr_table, str, str);
5136 * mono_string_is_interned:
5137 * @o: String to probe
5139 * Returns whether the string has been interned.
5142 mono_string_is_interned (MonoString *o)
5144 return mono_string_is_interned_lookup (o, FALSE);
5148 * mono_string_intern:
5149 * @o: String to intern
5151 * Interns the string passed.
5152 * Returns: The interned string.
5155 mono_string_intern (MonoString *str)
5157 return mono_string_is_interned_lookup (str, TRUE);
5162 * @domain: the domain where the string will be used.
5163 * @image: a metadata context
5164 * @idx: index into the user string table.
5166 * Implementation for the ldstr opcode.
5167 * Returns: a loaded string from the @image/@idx combination.
5170 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5172 MONO_ARCH_SAVE_REGS;
5174 if (image->dynamic) {
5175 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5178 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5179 return NULL; /*FIXME we should probably be raising an exception here*/
5180 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5185 * mono_ldstr_metadata_sig
5186 * @domain: the domain for the string
5187 * @sig: the signature of a metadata string
5189 * Returns: a MonoString for a string stored in the metadata
5192 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5194 const char *str = sig;
5195 MonoString *o, *interned;
5198 len2 = mono_metadata_decode_blob_size (str, &str);
5201 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5202 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5205 guint16 *p2 = (guint16*)mono_string_chars (o);
5206 for (i = 0; i < len2; ++i) {
5207 *p2 = GUINT16_FROM_LE (*p2);
5213 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5215 /* o will get garbage collected */
5219 o = mono_string_get_pinned (o);
5220 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5227 * mono_string_to_utf8:
5228 * @s: a System.String
5230 * Returns the UTF8 representation for @s.
5231 * The resulting buffer needs to be freed with mono_free().
5233 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5236 mono_string_to_utf8 (MonoString *s)
5239 char *result = mono_string_to_utf8_checked (s, &error);
5241 if (!mono_error_ok (&error))
5242 mono_error_raise_exception (&error);
5247 * mono_string_to_utf8_checked:
5248 * @s: a System.String
5249 * @error: a MonoError.
5251 * Converts a MonoString to its UTF8 representation. May fail; check
5252 * @error to determine whether the conversion was successful.
5253 * The resulting buffer should be freed with mono_free().
5256 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5260 GError *gerror = NULL;
5262 mono_error_init (error);
5268 return g_strdup ("");
5270 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5272 mono_error_set_argument (error, "string", "%s", gerror->message);
5273 g_error_free (gerror);
5276 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5277 if (s->length > written) {
5278 /* allocate the total length and copy the part of the string that has been converted */
5279 char *as2 = g_malloc0 (s->length);
5280 memcpy (as2, as, written);
5289 * mono_string_to_utf16:
5292 * Return an null-terminated array of the utf-16 chars
5293 * contained in @s. The result must be freed with g_free().
5294 * This is a temporary helper until our string implementation
5295 * is reworked to always include the null terminating char.
5298 mono_string_to_utf16 (MonoString *s)
5305 as = g_malloc ((s->length * 2) + 2);
5306 as [(s->length * 2)] = '\0';
5307 as [(s->length * 2) + 1] = '\0';
5310 return (gunichar2 *)(as);
5313 memcpy (as, mono_string_chars(s), s->length * 2);
5314 return (gunichar2 *)(as);
5318 * mono_string_from_utf16:
5319 * @data: the UTF16 string (LPWSTR) to convert
5321 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5323 * Returns: a MonoString.
5326 mono_string_from_utf16 (gunichar2 *data)
5328 MonoDomain *domain = mono_domain_get ();
5334 while (data [len]) len++;
5336 return mono_string_new_utf16 (domain, data, len);
5341 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5347 r = mono_string_to_utf8_checked (s, error);
5348 if (!mono_error_ok (error))
5354 len = strlen (r) + 1;
5356 mp_s = mono_mempool_alloc (mp, len);
5358 mp_s = mono_image_alloc (image, len);
5360 memcpy (mp_s, r, len);
5368 * mono_string_to_utf8_image:
5369 * @s: a System.String
5371 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5374 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5376 return mono_string_to_utf8_internal (NULL, image, s, error);
5380 * mono_string_to_utf8_mp:
5381 * @s: a System.String
5383 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5386 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5388 return mono_string_to_utf8_internal (mp, NULL, s, error);
5392 default_ex_handler (MonoException *ex)
5394 MonoObject *o = (MonoObject*)ex;
5395 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5399 static MonoExceptionFunc ex_handler = default_ex_handler;
5402 * mono_install_handler:
5403 * @func: exception handler
5405 * This is an internal JIT routine used to install the handler for exceptions
5409 mono_install_handler (MonoExceptionFunc func)
5411 ex_handler = func? func: default_ex_handler;
5415 * mono_raise_exception:
5416 * @ex: exception object
5418 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5421 mono_raise_exception (MonoException *ex)
5424 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5425 * that will cause gcc to omit the function epilog, causing problems when
5426 * the JIT tries to walk the stack, since the return address on the stack
5427 * will point into the next function in the executable, not this one.
5430 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5431 MonoInternalThread *thread = mono_thread_internal_current ();
5432 g_assert (ex->object.vtable->domain == mono_domain_get ());
5433 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5440 * mono_wait_handle_new:
5441 * @domain: Domain where the object will be created
5442 * @handle: Handle for the wait handle
5444 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5447 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5449 MonoWaitHandle *res;
5450 gpointer params [1];
5451 static MonoMethod *handle_set;
5453 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5455 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5457 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5459 params [0] = &handle;
5460 mono_runtime_invoke (handle_set, res, params, NULL);
5466 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5468 static MonoClassField *f_os_handle;
5469 static MonoClassField *f_safe_handle;
5471 if (!f_os_handle && !f_safe_handle) {
5472 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5473 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5478 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5482 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5489 mono_runtime_capture_context (MonoDomain *domain)
5491 RuntimeInvokeFunction runtime_invoke;
5493 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5494 MonoMethod *method = mono_get_context_capture_method ();
5495 MonoMethod *wrapper;
5498 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5499 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5500 domain->capture_context_method = mono_compile_method (method);
5503 runtime_invoke = domain->capture_context_runtime_invoke;
5505 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5508 * mono_async_result_new:
5509 * @domain:domain where the object will be created.
5510 * @handle: wait handle.
5511 * @state: state to pass to AsyncResult
5512 * @data: C closure data.
5514 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5515 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5519 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5521 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5522 MonoObject *context = mono_runtime_capture_context (domain);
5523 /* we must capture the execution context from the original thread */
5525 MONO_OBJECT_SETREF (res, execution_context, context);
5526 /* note: result may be null if the flow is suppressed */
5530 MONO_OBJECT_SETREF (res, object_data, object_data);
5531 MONO_OBJECT_SETREF (res, async_state, state);
5533 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5535 res->sync_completed = FALSE;
5536 res->completed = FALSE;
5542 mono_message_init (MonoDomain *domain,
5543 MonoMethodMessage *this,
5544 MonoReflectionMethod *method,
5545 MonoArray *out_args)
5547 static MonoClass *object_array_klass;
5548 static MonoClass *byte_array_klass;
5549 static MonoClass *string_array_klass;
5550 MonoMethodSignature *sig = mono_method_signature (method->method);
5556 if (!object_array_klass) {
5559 klass = mono_array_class_get (mono_defaults.object_class, 1);
5562 mono_memory_barrier ();
5563 object_array_klass = klass;
5565 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5568 mono_memory_barrier ();
5569 byte_array_klass = klass;
5571 klass = mono_array_class_get (mono_defaults.string_class, 1);
5574 mono_memory_barrier ();
5575 string_array_klass = klass;
5578 MONO_OBJECT_SETREF (this, method, method);
5580 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5581 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5582 this->async_result = NULL;
5583 this->call_type = CallType_Sync;
5585 names = g_new (char *, sig->param_count);
5586 mono_method_get_param_names (method->method, (const char **) names);
5587 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5589 for (i = 0; i < sig->param_count; i++) {
5590 name = mono_string_new (domain, names [i]);
5591 mono_array_setref (this->names, i, name);
5595 for (i = 0, j = 0; i < sig->param_count; i++) {
5596 if (sig->params [i]->byref) {
5598 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5599 mono_array_setref (this->args, i, arg);
5603 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5607 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5610 mono_array_set (this->arg_types, guint8, i, arg_type);
5615 * mono_remoting_invoke:
5616 * @real_proxy: pointer to a RealProxy object
5617 * @msg: The MonoMethodMessage to execute
5618 * @exc: used to store exceptions
5619 * @out_args: used to store output arguments
5621 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5622 * IMessage interface and it is not trivial to extract results from there. So
5623 * we call an helper method PrivateInvoke instead of calling
5624 * RealProxy::Invoke() directly.
5626 * Returns: the result object.
5629 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5630 MonoObject **exc, MonoArray **out_args)
5632 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5635 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5638 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5640 real_proxy->vtable->domain->private_invoke_method = im;
5643 pa [0] = real_proxy;
5648 return mono_runtime_invoke (im, NULL, pa, exc);
5652 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5653 MonoObject **exc, MonoArray **out_args)
5655 static MonoClass *object_array_klass;
5658 MonoMethodSignature *sig;
5660 int i, j, outarg_count = 0;
5662 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5664 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5665 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5666 target = tp->rp->unwrapped_server;
5668 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5672 domain = mono_domain_get ();
5673 method = msg->method->method;
5674 sig = mono_method_signature (method);
5676 for (i = 0; i < sig->param_count; i++) {
5677 if (sig->params [i]->byref)
5681 if (!object_array_klass) {
5684 klass = mono_array_class_get (mono_defaults.object_class, 1);
5687 mono_memory_barrier ();
5688 object_array_klass = klass;
5691 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5692 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5695 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5697 for (i = 0, j = 0; i < sig->param_count; i++) {
5698 if (sig->params [i]->byref) {
5700 arg = mono_array_get (msg->args, gpointer, i);
5701 mono_array_setref (*out_args, j, arg);
5710 * mono_object_to_string:
5712 * @exc: Any exception thrown by ToString (). May be NULL.
5714 * Returns: the result of calling ToString () on an object.
5717 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5719 static MonoMethod *to_string = NULL;
5725 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5727 method = mono_object_get_virtual_method (obj, to_string);
5729 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5733 * mono_print_unhandled_exception:
5734 * @exc: The exception
5736 * Prints the unhandled exception.
5739 mono_print_unhandled_exception (MonoObject *exc)
5742 char *message = (char*)"";
5743 gboolean free_message = FALSE;
5746 str = mono_object_to_string (exc, NULL);
5748 message = mono_string_to_utf8_checked (str, &error);
5749 if (!mono_error_ok (&error)) {
5750 mono_error_cleanup (&error);
5751 message = (char *) "";
5753 free_message = TRUE;
5758 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5759 * exc->vtable->klass->name, message);
5761 g_printerr ("\nUnhandled Exception: %s\n", message);
5768 * mono_delegate_ctor:
5769 * @this: pointer to an uninitialized delegate object
5770 * @target: target object
5771 * @addr: pointer to native code
5774 * Initialize a delegate and sets a specific method, not the one
5775 * associated with addr. This is useful when sharing generic code.
5776 * In that case addr will most probably not be associated with the
5777 * correct instantiation of the method.
5780 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5782 MonoDelegate *delegate = (MonoDelegate *)this;
5789 delegate->method = method;
5791 class = this->vtable->klass;
5792 mono_stats.delegate_creations++;
5794 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5796 method = mono_marshal_get_remoting_invoke (method);
5797 delegate->method_ptr = mono_compile_method (method);
5798 MONO_OBJECT_SETREF (delegate, target, target);
5799 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5800 method = mono_marshal_get_unbox_wrapper (method);
5801 delegate->method_ptr = mono_compile_method (method);
5802 MONO_OBJECT_SETREF (delegate, target, target);
5804 delegate->method_ptr = addr;
5805 MONO_OBJECT_SETREF (delegate, target, target);
5808 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5812 * mono_delegate_ctor:
5813 * @this: pointer to an uninitialized delegate object
5814 * @target: target object
5815 * @addr: pointer to native code
5817 * This is used to initialize a delegate.
5820 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5822 MonoDomain *domain = mono_domain_get ();
5824 MonoMethod *method = NULL;
5828 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5829 method = ji->method;
5830 g_assert (!method->klass->generic_container);
5833 mono_delegate_ctor_with_method (this, target, addr, method);
5837 * mono_method_call_message_new:
5838 * @method: method to encapsulate
5839 * @params: parameters to the method
5840 * @invoke: optional, delegate invoke.
5841 * @cb: async callback delegate.
5842 * @state: state passed to the async callback.
5844 * Translates arguments pointers into a MonoMethodMessage.
5847 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5848 MonoDelegate **cb, MonoObject **state)
5850 MonoDomain *domain = mono_domain_get ();
5851 MonoMethodSignature *sig = mono_method_signature (method);
5852 MonoMethodMessage *msg;
5855 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5858 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5859 count = sig->param_count - 2;
5861 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5862 count = sig->param_count;
5865 for (i = 0; i < count; i++) {
5870 if (sig->params [i]->byref)
5871 vpos = *((gpointer *)params [i]);
5875 type = sig->params [i]->type;
5876 class = mono_class_from_mono_type (sig->params [i]);
5878 if (class->valuetype)
5879 arg = mono_value_box (domain, class, vpos);
5881 arg = *((MonoObject **)vpos);
5883 mono_array_setref (msg->args, i, arg);
5886 if (cb != NULL && state != NULL) {
5887 *cb = *((MonoDelegate **)params [i]);
5889 *state = *((MonoObject **)params [i]);
5896 * mono_method_return_message_restore:
5898 * Restore results from message based processing back to arguments pointers
5901 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5903 MonoMethodSignature *sig = mono_method_signature (method);
5904 int i, j, type, size, out_len;
5906 if (out_args == NULL)
5908 out_len = mono_array_length (out_args);
5912 for (i = 0, j = 0; i < sig->param_count; i++) {
5913 MonoType *pt = sig->params [i];
5918 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5920 arg = mono_array_get (out_args, gpointer, j);
5923 g_assert (type != MONO_TYPE_VOID);
5925 if (MONO_TYPE_IS_REFERENCE (pt)) {
5926 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5929 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5930 size = mono_class_value_size (class, NULL);
5931 if (class->has_references)
5932 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5934 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5936 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5937 memset (*((gpointer *)params [i]), 0, size);
5947 * mono_load_remote_field:
5948 * @this: pointer to an object
5949 * @klass: klass of the object containing @field
5950 * @field: the field to load
5951 * @res: a storage to store the result
5953 * This method is called by the runtime on attempts to load fields of
5954 * transparent proxy objects. @this points to such TP, @klass is the class of
5955 * the object containing @field. @res is a storage location which can be
5956 * used to store the result.
5958 * Returns: an address pointing to the value of field.
5961 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5963 static MonoMethod *getter = NULL;
5964 MonoDomain *domain = mono_domain_get ();
5965 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5966 MonoClass *field_class;
5967 MonoMethodMessage *msg;
5968 MonoArray *out_args;
5972 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5973 g_assert (res != NULL);
5975 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5976 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5981 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5985 field_class = mono_class_from_mono_type (field->type);
5987 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5988 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5989 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5991 full_name = mono_type_get_full_name (klass);
5992 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5993 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5996 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5998 if (exc) mono_raise_exception ((MonoException *)exc);
6000 if (mono_array_length (out_args) == 0)
6003 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6005 if (field_class->valuetype) {
6006 return ((char *)*res) + sizeof (MonoObject);
6012 * mono_load_remote_field_new:
6017 * Missing documentation.
6020 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6022 static MonoMethod *getter = NULL;
6023 MonoDomain *domain = mono_domain_get ();
6024 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6025 MonoClass *field_class;
6026 MonoMethodMessage *msg;
6027 MonoArray *out_args;
6028 MonoObject *exc, *res;
6031 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6033 field_class = mono_class_from_mono_type (field->type);
6035 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6037 if (field_class->valuetype) {
6038 res = mono_object_new (domain, field_class);
6039 val = ((gchar *) res) + sizeof (MonoObject);
6043 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6048 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6052 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6053 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6055 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6057 full_name = mono_type_get_full_name (klass);
6058 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6059 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6062 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6064 if (exc) mono_raise_exception ((MonoException *)exc);
6066 if (mono_array_length (out_args) == 0)
6069 res = mono_array_get (out_args, MonoObject *, 0);
6075 * mono_store_remote_field:
6076 * @this: pointer to an object
6077 * @klass: klass of the object containing @field
6078 * @field: the field to load
6079 * @val: the value/object to store
6081 * This method is called by the runtime on attempts to store fields of
6082 * transparent proxy objects. @this points to such TP, @klass is the class of
6083 * the object containing @field. @val is the new value to store in @field.
6086 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6088 static MonoMethod *setter = NULL;
6089 MonoDomain *domain = mono_domain_get ();
6090 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6091 MonoClass *field_class;
6092 MonoMethodMessage *msg;
6093 MonoArray *out_args;
6098 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6100 field_class = mono_class_from_mono_type (field->type);
6102 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6103 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6104 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6109 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6113 if (field_class->valuetype)
6114 arg = mono_value_box (domain, field_class, val);
6116 arg = *((MonoObject **)val);
6119 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6120 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6122 full_name = mono_type_get_full_name (klass);
6123 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6124 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6125 mono_array_setref (msg->args, 2, arg);
6128 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6130 if (exc) mono_raise_exception ((MonoException *)exc);
6134 * mono_store_remote_field_new:
6140 * Missing documentation
6143 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6145 static MonoMethod *setter = NULL;
6146 MonoDomain *domain = mono_domain_get ();
6147 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6148 MonoClass *field_class;
6149 MonoMethodMessage *msg;
6150 MonoArray *out_args;
6154 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6156 field_class = mono_class_from_mono_type (field->type);
6158 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6159 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6160 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6165 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6169 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6170 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6172 full_name = mono_type_get_full_name (klass);
6173 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6174 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6175 mono_array_setref (msg->args, 2, arg);
6178 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6180 if (exc) mono_raise_exception ((MonoException *)exc);
6184 * mono_create_ftnptr:
6186 * Given a function address, create a function descriptor for it.
6187 * This is only needed on some platforms.
6190 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6192 return callbacks.create_ftnptr (domain, addr);
6196 * mono_get_addr_from_ftnptr:
6198 * Given a pointer to a function descriptor, return the function address.
6199 * This is only needed on some platforms.
6202 mono_get_addr_from_ftnptr (gpointer descr)
6204 return callbacks.get_addr_from_ftnptr (descr);
6208 * mono_string_chars:
6211 * Returns a pointer to the UCS16 characters stored in the MonoString
6214 mono_string_chars (MonoString *s)
6220 * mono_string_length:
6223 * Returns the lenght in characters of the string
6226 mono_string_length (MonoString *s)
6232 * mono_array_length:
6233 * @array: a MonoArray*
6235 * Returns the total number of elements in the array. This works for
6236 * both vectors and multidimensional arrays.
6239 mono_array_length (MonoArray *array)
6241 return array->max_length;
6245 * mono_array_addr_with_size:
6246 * @array: a MonoArray*
6247 * @size: size of the array elements
6248 * @idx: index into the array
6250 * Returns the address of the @idx element in the array.
6253 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6255 return ((char*)(array)->vector) + size * idx;