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);
83 free_main_args (void);
86 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
89 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
90 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
91 static CRITICAL_SECTION ldstr_section;
93 static gboolean profile_allocs = TRUE;
96 mono_runtime_object_init (MonoObject *this)
98 MonoMethod *method = NULL;
99 MonoClass *klass = this->vtable->klass;
101 method = mono_class_get_method_from_name (klass, ".ctor", 0);
104 if (method->klass->valuetype)
105 this = mono_object_unbox (this);
106 mono_runtime_invoke (method, this, NULL, NULL);
109 /* The pseudo algorithm for type initialization from the spec
110 Note it doesn't say anything about domains - only threads.
112 2. If the type is initialized you are done.
113 2.1. If the type is not yet initialized, try to take an
115 2.2. If successful, record this thread as responsible for
116 initializing the type and proceed to step 2.3.
117 2.2.1. If not, see whether this thread or any thread
118 waiting for this thread to complete already holds the lock.
119 2.2.2. If so, return since blocking would create a deadlock. This thread
120 will now see an incompletely initialized state for the type,
121 but no deadlock will arise.
122 2.2.3 If not, block until the type is initialized then return.
123 2.3 Initialize the parent type and then all interfaces implemented
125 2.4 Execute the type initialization code for this type.
126 2.5 Mark the type as initialized, release the initialization lock,
127 awaken any threads waiting for this type to be initialized,
134 guint32 initializing_tid;
135 guint32 waiting_count;
137 CRITICAL_SECTION initialization_section;
138 } TypeInitializationLock;
140 /* for locking access to type_initialization_hash and blocked_thread_hash */
141 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
142 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
143 static CRITICAL_SECTION type_initialization_section;
145 /* from vtable to lock */
146 static GHashTable *type_initialization_hash;
148 /* from thread id to thread id being waited on */
149 static GHashTable *blocked_thread_hash;
152 static MonoThread *main_thread;
154 /* Functions supplied by the runtime */
155 static MonoRuntimeCallbacks callbacks;
158 * mono_thread_set_main:
159 * @thread: thread to set as the main thread
161 * This function can be used to instruct the runtime to treat @thread
162 * as the main thread, ie, the thread that would normally execute the Main()
163 * method. This basically means that at the end of @thread, the runtime will
164 * wait for the existing foreground threads to quit and other such details.
167 mono_thread_set_main (MonoThread *thread)
169 static gboolean registered = FALSE;
172 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
176 main_thread = thread;
180 mono_thread_get_main (void)
186 mono_type_initialization_init (void)
188 InitializeCriticalSection (&type_initialization_section);
189 type_initialization_hash = g_hash_table_new (NULL, NULL);
190 blocked_thread_hash = g_hash_table_new (NULL, NULL);
191 InitializeCriticalSection (&ldstr_section);
195 mono_type_initialization_cleanup (void)
198 /* This is causing race conditions with
199 * mono_release_type_locks
201 DeleteCriticalSection (&type_initialization_section);
202 g_hash_table_destroy (type_initialization_hash);
203 type_initialization_hash = NULL;
205 DeleteCriticalSection (&ldstr_section);
206 g_hash_table_destroy (blocked_thread_hash);
207 blocked_thread_hash = NULL;
213 * get_type_init_exception_for_vtable:
215 * Return the stored type initialization exception for VTABLE.
217 static MonoException*
218 get_type_init_exception_for_vtable (MonoVTable *vtable)
220 MonoDomain *domain = vtable->domain;
221 MonoClass *klass = vtable->klass;
225 g_assert (vtable->init_failed);
228 * If the initializing thread was rudely aborted, the exception is not stored
232 mono_domain_lock (domain);
233 if (domain->type_init_exception_hash)
234 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
235 mono_domain_unlock (domain);
238 if (klass->name_space && *klass->name_space)
239 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
241 full_name = g_strdup (klass->name);
242 ex = mono_get_exception_type_initialization (full_name, NULL);
249 * mono_runtime_class_init:
250 * @vtable: vtable that needs to be initialized
252 * This routine calls the class constructor for @vtable.
255 mono_runtime_class_init (MonoVTable *vtable)
257 mono_runtime_class_init_full (vtable, TRUE);
261 * mono_runtime_class_init_full:
262 * @vtable that neeeds to be initialized
263 * @raise_exception is TRUE, exceptions are raised intead of returned
267 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
270 MonoException *exc_to_throw;
271 MonoMethod *method = NULL;
277 if (vtable->initialized)
281 klass = vtable->klass;
283 if (!klass->image->checked_module_cctor) {
284 mono_image_check_for_module_cctor (klass->image);
285 if (klass->image->has_module_cctor) {
286 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
287 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
290 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
295 method = mono_class_get_cctor (klass);
298 MonoDomain *domain = vtable->domain;
299 TypeInitializationLock *lock;
300 guint32 tid = GetCurrentThreadId();
301 int do_initialization = 0;
302 MonoDomain *last_domain = NULL;
304 mono_type_initialization_lock ();
305 /* double check... */
306 if (vtable->initialized) {
307 mono_type_initialization_unlock ();
310 if (vtable->init_failed) {
311 mono_type_initialization_unlock ();
313 /* The type initialization already failed once, rethrow the same exception */
315 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
316 return get_type_init_exception_for_vtable (vtable);
318 lock = g_hash_table_lookup (type_initialization_hash, vtable);
320 /* This thread will get to do the initialization */
321 if (mono_domain_get () != domain) {
322 /* Transfer into the target domain */
323 last_domain = mono_domain_get ();
324 if (!mono_domain_set (domain, FALSE)) {
325 vtable->initialized = 1;
326 mono_type_initialization_unlock ();
328 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
329 return mono_get_exception_appdomain_unloaded ();
332 lock = g_malloc (sizeof(TypeInitializationLock));
333 InitializeCriticalSection (&lock->initialization_section);
334 lock->initializing_tid = tid;
335 lock->waiting_count = 1;
337 /* grab the vtable lock while this thread still owns type_initialization_section */
338 EnterCriticalSection (&lock->initialization_section);
339 g_hash_table_insert (type_initialization_hash, vtable, lock);
340 do_initialization = 1;
343 TypeInitializationLock *pending_lock;
345 if (lock->initializing_tid == tid || lock->done) {
346 mono_type_initialization_unlock ();
349 /* see if the thread doing the initialization is already blocked on this thread */
350 blocked = GUINT_TO_POINTER (lock->initializing_tid);
351 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
352 if (pending_lock->initializing_tid == tid) {
353 if (!pending_lock->done) {
354 mono_type_initialization_unlock ();
357 /* the thread doing the initialization is blocked on this thread,
358 but on a lock that has already been freed. It just hasn't got
363 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
365 ++lock->waiting_count;
366 /* record the fact that we are waiting on the initializing thread */
367 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
369 mono_type_initialization_unlock ();
371 if (do_initialization) {
372 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
374 /* If the initialization failed, mark the class as unusable. */
375 /* Avoid infinite loops */
377 (klass->image == mono_defaults.corlib &&
378 !strcmp (klass->name_space, "System") &&
379 !strcmp (klass->name, "TypeInitializationException")))) {
380 vtable->init_failed = 1;
382 if (klass->name_space && *klass->name_space)
383 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
385 full_name = g_strdup (klass->name);
386 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
390 * Store the exception object so it could be thrown on subsequent
393 mono_domain_lock (domain);
394 if (!domain->type_init_exception_hash)
395 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
396 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
397 mono_domain_unlock (domain);
401 mono_domain_set (last_domain, TRUE);
403 LeaveCriticalSection (&lock->initialization_section);
405 /* this just blocks until the initializing thread is done */
406 EnterCriticalSection (&lock->initialization_section);
407 LeaveCriticalSection (&lock->initialization_section);
410 mono_type_initialization_lock ();
411 if (lock->initializing_tid != tid)
412 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
413 --lock->waiting_count;
414 if (lock->waiting_count == 0) {
415 DeleteCriticalSection (&lock->initialization_section);
416 g_hash_table_remove (type_initialization_hash, vtable);
419 mono_memory_barrier ();
420 if (!vtable->init_failed)
421 vtable->initialized = 1;
422 mono_type_initialization_unlock ();
424 if (vtable->init_failed) {
425 /* Either we were the initializing thread or we waited for the initialization */
427 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
428 return get_type_init_exception_for_vtable (vtable);
431 vtable->initialized = 1;
438 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
440 MonoVTable *vtable = (MonoVTable*)key;
442 TypeInitializationLock *lock = (TypeInitializationLock*) value;
443 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
446 * Have to set this since it cannot be set by the normal code in
447 * mono_runtime_class_init (). In this case, the exception object is not stored,
448 * and get_type_init_exception_for_class () needs to be aware of this.
450 vtable->init_failed = 1;
451 LeaveCriticalSection (&lock->initialization_section);
452 --lock->waiting_count;
453 if (lock->waiting_count == 0) {
454 DeleteCriticalSection (&lock->initialization_section);
463 mono_release_type_locks (MonoInternalThread *thread)
465 mono_type_initialization_lock ();
466 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
467 mono_type_initialization_unlock ();
471 default_trampoline (MonoMethod *method)
477 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
479 g_assert_not_reached ();
485 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
487 g_error ("remoting not installed");
492 default_delegate_trampoline (MonoClass *klass)
494 g_assert_not_reached ();
498 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
499 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
500 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
501 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
502 static MonoImtThunkBuilder imt_thunk_builder = NULL;
503 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
504 #if (MONO_IMT_SIZE > 32)
505 #error "MONO_IMT_SIZE cannot be larger than 32"
509 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
511 memcpy (&callbacks, cbs, sizeof (*cbs));
514 MonoRuntimeCallbacks*
515 mono_get_runtime_callbacks (void)
521 mono_install_trampoline (MonoTrampoline func)
523 arch_create_jit_trampoline = func? func: default_trampoline;
527 mono_install_jump_trampoline (MonoJumpTrampoline func)
529 arch_create_jump_trampoline = func? func: default_jump_trampoline;
533 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
535 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
539 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
541 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
545 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
546 imt_thunk_builder = func;
549 static MonoCompileFunc default_mono_compile_method = NULL;
552 * mono_install_compile_method:
553 * @func: function to install
555 * This is a VM internal routine
558 mono_install_compile_method (MonoCompileFunc func)
560 default_mono_compile_method = func;
564 * mono_compile_method:
565 * @method: The method to compile.
567 * This JIT-compiles the method, and returns the pointer to the native code
571 mono_compile_method (MonoMethod *method)
573 if (!default_mono_compile_method) {
574 g_error ("compile method called on uninitialized runtime");
577 return default_mono_compile_method (method);
581 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
583 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
587 mono_runtime_create_delegate_trampoline (MonoClass *klass)
589 return arch_create_delegate_trampoline (klass);
592 static MonoFreeMethodFunc default_mono_free_method = NULL;
595 * mono_install_free_method:
596 * @func: pointer to the MonoFreeMethodFunc used to release a method
598 * This is an internal VM routine, it is used for the engines to
599 * register a handler to release the resources associated with a method.
601 * Methods are freed when no more references to the delegate that holds
605 mono_install_free_method (MonoFreeMethodFunc func)
607 default_mono_free_method = func;
611 * mono_runtime_free_method:
612 * @domain; domain where the method is hosted
613 * @method: method to release
615 * This routine is invoked to free the resources associated with
616 * a method that has been JIT compiled. This is used to discard
617 * methods that were used only temporarily (for example, used in marshalling)
621 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
623 if (default_mono_free_method != NULL)
624 default_mono_free_method (domain, method);
626 mono_method_clear_object (domain, method);
628 mono_free_method (method);
632 * The vtables in the root appdomain are assumed to be reachable by other
633 * roots, and we don't use typed allocation in the other domains.
636 /* The sync block is no longer a GC pointer */
637 #define GC_HEADER_BITMAP (0)
639 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
642 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
644 MonoClassField *field;
650 max_size = mono_class_data_size (class) / sizeof (gpointer);
652 max_size = class->instance_size / sizeof (gpointer);
653 if (max_size > size) {
654 g_assert (offset <= 0);
655 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
660 /*An Ephemeron cannot be marked by sgen*/
661 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
663 memset (bitmap, 0, size / 8);
668 for (p = class; p != NULL; p = p->parent) {
669 gpointer iter = NULL;
670 while ((field = mono_class_get_fields (p, &iter))) {
674 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
676 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
679 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
682 /* FIXME: should not happen, flag as type load error */
683 if (field->type->byref)
686 if (static_fields && field->offset == -1)
690 pos = field->offset / sizeof (gpointer);
693 type = mono_type_get_underlying_type (field->type);
694 switch (type->type) {
697 case MONO_TYPE_FNPTR:
699 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
704 if (class->image != mono_defaults.corlib)
707 case MONO_TYPE_STRING:
708 case MONO_TYPE_SZARRAY:
709 case MONO_TYPE_CLASS:
710 case MONO_TYPE_OBJECT:
711 case MONO_TYPE_ARRAY:
712 g_assert ((field->offset % sizeof(gpointer)) == 0);
714 g_assert (pos < size || pos <= max_size);
715 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
716 *max_set = MAX (*max_set, pos);
718 case MONO_TYPE_GENERICINST:
719 if (!mono_type_generic_inst_is_valuetype (type)) {
720 g_assert ((field->offset % sizeof(gpointer)) == 0);
722 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
723 *max_set = MAX (*max_set, pos);
728 case MONO_TYPE_VALUETYPE: {
729 MonoClass *fclass = mono_class_from_mono_type (field->type);
730 if (fclass->has_references) {
731 /* remove the object header */
732 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
746 case MONO_TYPE_BOOLEAN:
750 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
761 * mono_class_compute_bitmap:
763 * Mono internal function to compute a bitmap of reference fields in a class.
766 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
768 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
773 * similar to the above, but sets the bits in the bitmap for any non-ref field
774 * and ignores static fields
777 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
779 MonoClassField *field;
784 max_size = class->instance_size / sizeof (gpointer);
785 if (max_size >= size) {
786 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
789 for (p = class; p != NULL; p = p->parent) {
790 gpointer iter = NULL;
791 while ((field = mono_class_get_fields (p, &iter))) {
794 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
796 /* FIXME: should not happen, flag as type load error */
797 if (field->type->byref)
800 pos = field->offset / sizeof (gpointer);
803 type = mono_type_get_underlying_type (field->type);
804 switch (type->type) {
805 #if SIZEOF_VOID_P == 8
809 case MONO_TYPE_FNPTR:
814 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
815 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
816 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
819 #if SIZEOF_VOID_P == 4
823 case MONO_TYPE_FNPTR:
828 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
829 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
830 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
836 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
837 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
838 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
841 case MONO_TYPE_BOOLEAN:
844 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
846 case MONO_TYPE_STRING:
847 case MONO_TYPE_SZARRAY:
848 case MONO_TYPE_CLASS:
849 case MONO_TYPE_OBJECT:
850 case MONO_TYPE_ARRAY:
852 case MONO_TYPE_GENERICINST:
853 if (!mono_type_generic_inst_is_valuetype (type)) {
858 case MONO_TYPE_VALUETYPE: {
859 MonoClass *fclass = mono_class_from_mono_type (field->type);
860 /* remove the object header */
861 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
865 g_assert_not_reached ();
874 * mono_class_insecure_overlapping:
875 * check if a class with explicit layout has references and non-references
876 * fields overlapping.
878 * Returns: TRUE if it is insecure to load the type.
881 mono_class_insecure_overlapping (MonoClass *klass)
885 gsize default_bitmap [4] = {0};
887 gsize default_nrbitmap [4] = {0};
888 int i, insecure = FALSE;
891 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
892 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
894 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
895 int idx = i % (sizeof (bitmap [0]) * 8);
896 if (bitmap [idx] & nrbitmap [idx]) {
901 if (bitmap != default_bitmap)
903 if (nrbitmap != default_nrbitmap)
906 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
914 mono_string_alloc (int length)
916 return mono_string_new_size (mono_domain_get (), length);
920 mono_class_compute_gc_descriptor (MonoClass *class)
924 gsize default_bitmap [4] = {0};
925 static gboolean gcj_inited = FALSE;
930 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
931 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
932 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
933 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
935 #ifdef HAVE_GC_GCJ_MALLOC
937 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
941 #ifdef GC_REDIRECT_TO_LOCAL
942 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
943 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
945 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
946 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
951 mono_loader_unlock ();
955 mono_class_init (class);
957 if (class->gc_descr_inited)
960 class->gc_descr_inited = TRUE;
961 class->gc_descr = GC_NO_DESCRIPTOR;
963 bitmap = default_bitmap;
964 if (class == mono_defaults.string_class) {
965 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
966 } else if (class->rank) {
967 mono_class_compute_gc_descriptor (class->element_class);
968 if (!class->element_class->valuetype) {
970 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
971 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
972 class->name_space, class->name);*/
974 /* remove the object header */
975 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
976 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
977 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
978 class->name_space, class->name);*/
979 if (bitmap != default_bitmap)
983 /*static int count = 0;
986 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
987 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
989 if (class->gc_descr == GC_NO_DESCRIPTOR)
990 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
992 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
993 if (bitmap != default_bitmap)
999 * field_is_special_static:
1000 * @fklass: The MonoClass to look up.
1001 * @field: The MonoClassField describing the field.
1003 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1004 * SPECIAL_STATIC_NONE otherwise.
1007 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1009 MonoCustomAttrInfo *ainfo;
1011 ainfo = mono_custom_attrs_from_field (fklass, field);
1014 for (i = 0; i < ainfo->num_attrs; ++i) {
1015 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1016 if (klass->image == mono_defaults.corlib) {
1017 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1018 mono_custom_attrs_free (ainfo);
1019 return SPECIAL_STATIC_THREAD;
1021 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1022 mono_custom_attrs_free (ainfo);
1023 return SPECIAL_STATIC_CONTEXT;
1027 mono_custom_attrs_free (ainfo);
1028 return SPECIAL_STATIC_NONE;
1031 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1032 #define mix(a,b,c) { \
1033 a -= c; a ^= rot(c, 4); c += b; \
1034 b -= a; b ^= rot(a, 6); a += c; \
1035 c -= b; c ^= rot(b, 8); b += a; \
1036 a -= c; a ^= rot(c,16); c += b; \
1037 b -= a; b ^= rot(a,19); a += c; \
1038 c -= b; c ^= rot(b, 4); b += a; \
1040 #define final(a,b,c) { \
1041 c ^= b; c -= rot(b,14); \
1042 a ^= c; a -= rot(c,11); \
1043 b ^= a; b -= rot(a,25); \
1044 c ^= b; c -= rot(b,16); \
1045 a ^= c; a -= rot(c,4); \
1046 b ^= a; b -= rot(a,14); \
1047 c ^= b; c -= rot(b,24); \
1051 * mono_method_get_imt_slot:
1053 * The IMT slot is embedded into AOTed code, so this must return the same value
1054 * for the same method across all executions. This means:
1055 * - pointers shouldn't be used as hash values.
1056 * - mono_metadata_str_hash () should be used for hashing strings.
1059 mono_method_get_imt_slot (MonoMethod *method)
1061 MonoMethodSignature *sig;
1063 guint32 *hashes_start, *hashes;
1067 /* This can be used to stress tests the collision code */
1071 * We do this to simplify generic sharing. It will hurt
1072 * performance in cases where a class implements two different
1073 * instantiations of the same generic interface.
1074 * The code in build_imt_slots () depends on this.
1076 if (method->is_inflated)
1077 method = ((MonoMethodInflated*)method)->declaring;
1079 sig = mono_method_signature (method);
1080 hashes_count = sig->param_count + 4;
1081 hashes_start = malloc (hashes_count * sizeof (guint32));
1082 hashes = hashes_start;
1084 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1085 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1086 method->klass->name_space, method->klass->name, method->name);
1087 g_assert_not_reached ();
1090 /* Initialize hashes */
1091 hashes [0] = mono_metadata_str_hash (method->klass->name);
1092 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1093 hashes [2] = mono_metadata_str_hash (method->name);
1094 hashes [3] = mono_metadata_type_hash (sig->ret);
1095 for (i = 0; i < sig->param_count; i++) {
1096 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1099 /* Setup internal state */
1100 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1102 /* Handle most of the hashes */
1103 while (hashes_count > 3) {
1112 /* Handle the last 3 hashes (all the case statements fall through) */
1113 switch (hashes_count) {
1114 case 3 : c += hashes [2];
1115 case 2 : b += hashes [1];
1116 case 1 : a += hashes [0];
1118 case 0: /* nothing left to add */
1122 free (hashes_start);
1123 /* Report the result */
1124 return c % MONO_IMT_SIZE;
1133 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1134 guint32 imt_slot = mono_method_get_imt_slot (method);
1135 MonoImtBuilderEntry *entry;
1137 if (slot_num >= 0 && imt_slot != slot_num) {
1138 /* we build just a single imt slot and this is not it */
1142 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1143 entry->key = method;
1144 entry->value.vtable_slot = vtable_slot;
1145 entry->next = imt_builder [imt_slot];
1146 if (imt_builder [imt_slot] != NULL) {
1147 entry->children = imt_builder [imt_slot]->children + 1;
1148 if (entry->children == 1) {
1149 mono_stats.imt_slots_with_collisions++;
1150 *imt_collisions_bitmap |= (1 << imt_slot);
1153 entry->children = 0;
1154 mono_stats.imt_used_slots++;
1156 imt_builder [imt_slot] = entry;
1159 char *method_name = mono_method_full_name (method, TRUE);
1160 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1161 method, method_name, imt_slot, vtable_slot, entry->children);
1162 g_free (method_name);
1169 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1171 MonoMethod *method = e->key;
1172 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1176 method->klass->name_space,
1177 method->klass->name,
1180 printf (" * %s: NULL\n", message);
1186 compare_imt_builder_entries (const void *p1, const void *p2) {
1187 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1188 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1190 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1194 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1196 int count = end - start;
1197 int chunk_start = out_array->len;
1200 for (i = start; i < end; ++i) {
1201 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1202 item->key = sorted_array [i]->key;
1203 item->value = sorted_array [i]->value;
1204 item->has_target_code = sorted_array [i]->has_target_code;
1205 item->is_equals = TRUE;
1207 item->check_target_idx = out_array->len + 1;
1209 item->check_target_idx = 0;
1210 g_ptr_array_add (out_array, item);
1213 int middle = start + count / 2;
1214 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1216 item->key = sorted_array [middle]->key;
1217 item->is_equals = FALSE;
1218 g_ptr_array_add (out_array, item);
1219 imt_emit_ir (sorted_array, start, middle, out_array);
1220 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1226 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1227 int number_of_entries = entries->children + 1;
1228 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1229 GPtrArray *result = g_ptr_array_new ();
1230 MonoImtBuilderEntry *current_entry;
1233 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1234 sorted_array [i] = current_entry;
1236 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1238 /*for (i = 0; i < number_of_entries; i++) {
1239 print_imt_entry (" sorted array:", sorted_array [i], i);
1242 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1244 free (sorted_array);
1249 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1251 if (imt_builder_entry != NULL) {
1252 if (imt_builder_entry->children == 0 && !fail_tramp) {
1253 /* No collision, return the vtable slot contents */
1254 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1256 /* Collision, build the thunk */
1257 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1260 result = imt_thunk_builder (vtable, domain,
1261 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1262 for (i = 0; i < imt_ir->len; ++i)
1263 g_free (g_ptr_array_index (imt_ir, i));
1264 g_ptr_array_free (imt_ir, TRUE);
1276 static MonoImtBuilderEntry*
1277 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1280 * LOCKING: requires the loader and domain locks.
1284 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1288 guint32 imt_collisions_bitmap = 0;
1289 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1290 int method_count = 0;
1291 gboolean record_method_count_for_max_collisions = FALSE;
1292 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1295 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1297 for (i = 0; i < klass->interface_offsets_count; ++i) {
1298 MonoClass *iface = klass->interfaces_packed [i];
1299 int interface_offset = klass->interface_offsets_packed [i];
1300 int method_slot_in_interface, vt_slot;
1302 if (mono_class_has_variant_generic_params (iface))
1303 has_variant_iface = TRUE;
1305 vt_slot = interface_offset;
1306 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1309 if (slot_num >= 0 && iface->is_inflated) {
1311 * The imt slot of the method is the same as for its declaring method,
1312 * see the comment in mono_method_get_imt_slot (), so we can
1313 * avoid inflating methods which will be discarded by
1314 * add_imt_builder_entry anyway.
1316 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1317 if (mono_method_get_imt_slot (method) != slot_num) {
1322 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1323 if (method->is_generic) {
1324 has_generic_virtual = TRUE;
1329 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1330 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1335 if (extra_interfaces) {
1336 int interface_offset = klass->vtable_size;
1338 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1339 MonoClass* iface = list_item->data;
1340 int method_slot_in_interface;
1341 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1342 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1343 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1345 interface_offset += iface->method.count;
1348 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1349 /* overwrite the imt slot only if we're building all the entries or if
1350 * we're building this specific one
1352 if (slot_num < 0 || i == slot_num) {
1353 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1356 if (imt_builder [i]) {
1357 MonoImtBuilderEntry *entry;
1359 /* Link entries with imt_builder [i] */
1360 for (entry = entries; entry->next; entry = entry->next) {
1362 MonoMethod *method = (MonoMethod*)entry->key;
1363 char *method_name = mono_method_full_name (method, TRUE);
1364 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1365 g_free (method_name);
1368 entry->next = imt_builder [i];
1369 entries->children += imt_builder [i]->children + 1;
1371 imt_builder [i] = entries;
1374 if (has_generic_virtual || has_variant_iface) {
1376 * There might be collisions later when the the thunk is expanded.
1378 imt_collisions_bitmap |= (1 << i);
1381 * The IMT thunk might be called with an instance of one of the
1382 * generic virtual methods, so has to fallback to the IMT trampoline.
1384 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1386 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1389 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1393 if (imt_builder [i] != NULL) {
1394 int methods_in_slot = imt_builder [i]->children + 1;
1395 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1396 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1397 record_method_count_for_max_collisions = TRUE;
1399 method_count += methods_in_slot;
1403 mono_stats.imt_number_of_methods += method_count;
1404 if (record_method_count_for_max_collisions) {
1405 mono_stats.imt_method_count_when_max_collisions = method_count;
1408 for (i = 0; i < MONO_IMT_SIZE; i++) {
1409 MonoImtBuilderEntry* entry = imt_builder [i];
1410 while (entry != NULL) {
1411 MonoImtBuilderEntry* next = entry->next;
1417 /* we OR the bitmap since we may build just a single imt slot at a time */
1418 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1422 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1423 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1427 * mono_vtable_build_imt_slot:
1428 * @vtable: virtual object table struct
1429 * @imt_slot: slot in the IMT table
1431 * Fill the given @imt_slot in the IMT table of @vtable with
1432 * a trampoline or a thunk for the case of collisions.
1433 * This is part of the internal mono API.
1435 * LOCKING: Take the domain lock.
1438 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1440 gpointer *imt = (gpointer*)vtable;
1441 imt -= MONO_IMT_SIZE;
1442 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1444 /* no support for extra interfaces: the proxy objects will need
1445 * to build the complete IMT
1446 * Update and heck needs to ahppen inside the proper domain lock, as all
1447 * the changes made to a MonoVTable.
1449 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1450 mono_domain_lock (vtable->domain);
1451 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1452 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1453 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1454 mono_domain_unlock (vtable->domain);
1455 mono_loader_unlock ();
1460 * The first two free list entries both belong to the wait list: The
1461 * first entry is the pointer to the head of the list and the second
1462 * entry points to the last element. That way appending and removing
1463 * the first element are both O(1) operations.
1465 #ifdef MONO_SMALL_CONFIG
1466 #define NUM_FREE_LISTS 6
1468 #define NUM_FREE_LISTS 12
1470 #define FIRST_FREE_LIST_SIZE 64
1471 #define MAX_WAIT_LENGTH 50
1472 #define THUNK_THRESHOLD 10
1475 * LOCKING: The domain lock must be held.
1478 init_thunk_free_lists (MonoDomain *domain)
1480 if (domain->thunk_free_lists)
1482 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1486 list_index_for_size (int item_size)
1489 int size = FIRST_FREE_LIST_SIZE;
1491 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1500 * mono_method_alloc_generic_virtual_thunk:
1502 * @size: size in bytes
1504 * Allocs size bytes to be used for the code of a generic virtual
1505 * thunk. It's either allocated from the domain's code manager or
1506 * reused from a previously invalidated piece.
1508 * LOCKING: The domain lock must be held.
1511 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1513 static gboolean inited = FALSE;
1514 static int generic_virtual_thunks_size = 0;
1518 MonoThunkFreeList **l;
1520 init_thunk_free_lists (domain);
1522 size += sizeof (guint32);
1523 if (size < sizeof (MonoThunkFreeList))
1524 size = sizeof (MonoThunkFreeList);
1526 i = list_index_for_size (size);
1527 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1528 if ((*l)->size >= size) {
1529 MonoThunkFreeList *item = *l;
1531 return ((guint32*)item) + 1;
1535 /* no suitable item found - search lists of larger sizes */
1536 while (++i < NUM_FREE_LISTS) {
1537 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1540 g_assert (item->size > size);
1541 domain->thunk_free_lists [i] = item->next;
1542 return ((guint32*)item) + 1;
1545 /* still nothing found - allocate it */
1547 mono_counters_register ("Generic virtual thunk bytes",
1548 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1551 generic_virtual_thunks_size += size;
1553 p = mono_domain_code_reserve (domain, size);
1556 mono_domain_lock (domain);
1557 if (!domain->generic_virtual_thunks)
1558 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1559 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1560 mono_domain_unlock (domain);
1566 * LOCKING: The domain lock must be held.
1569 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1572 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1573 gboolean found = FALSE;
1575 mono_domain_lock (domain);
1576 if (!domain->generic_virtual_thunks)
1577 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1578 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1580 mono_domain_unlock (domain);
1583 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1585 init_thunk_free_lists (domain);
1587 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1588 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1589 int length = item->length;
1592 /* unlink the first item from the wait list */
1593 domain->thunk_free_lists [0] = item->next;
1594 domain->thunk_free_lists [0]->length = length - 1;
1596 i = list_index_for_size (item->size);
1598 /* put it in the free list */
1599 item->next = domain->thunk_free_lists [i];
1600 domain->thunk_free_lists [i] = item;
1604 if (domain->thunk_free_lists [1]) {
1605 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1606 domain->thunk_free_lists [0]->length++;
1608 g_assert (!domain->thunk_free_lists [0]);
1610 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1611 domain->thunk_free_lists [0]->length = 1;
1615 typedef struct _GenericVirtualCase {
1619 struct _GenericVirtualCase *next;
1620 } GenericVirtualCase;
1623 * get_generic_virtual_entries:
1625 * Return IMT entries for the generic virtual method instances and
1626 * variant interface methods for vtable slot
1629 static MonoImtBuilderEntry*
1630 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1632 GenericVirtualCase *list;
1633 MonoImtBuilderEntry *entries;
1635 mono_domain_lock (domain);
1636 if (!domain->generic_virtual_cases)
1637 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1639 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1642 for (; list; list = list->next) {
1643 MonoImtBuilderEntry *entry;
1645 if (list->count < THUNK_THRESHOLD)
1648 entry = g_new0 (MonoImtBuilderEntry, 1);
1649 entry->key = list->method;
1650 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1651 entry->has_target_code = 1;
1653 entry->children = entries->children + 1;
1654 entry->next = entries;
1658 mono_domain_unlock (domain);
1660 /* FIXME: Leaking memory ? */
1665 * mono_method_add_generic_virtual_invocation:
1667 * @vtable_slot: pointer to the vtable slot
1668 * @method: the inflated generic virtual method
1669 * @code: the method's code
1671 * Registers a call via unmanaged code to a generic virtual method
1672 * instantiation or variant interface method. If the number of calls reaches a threshold
1673 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1674 * virtual method thunk.
1677 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1678 gpointer *vtable_slot,
1679 MonoMethod *method, gpointer code)
1681 static gboolean inited = FALSE;
1682 static int num_added = 0;
1684 GenericVirtualCase *gvc, *list;
1685 MonoImtBuilderEntry *entries;
1689 mono_domain_lock (domain);
1690 if (!domain->generic_virtual_cases)
1691 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1693 /* Check whether the case was already added */
1694 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1697 if (gvc->method == method)
1702 /* If not found, make a new one */
1704 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1705 gvc->method = method;
1708 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1713 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1719 if (++gvc->count == THUNK_THRESHOLD) {
1720 gpointer *old_thunk = *vtable_slot;
1721 gpointer vtable_trampoline = NULL;
1722 gpointer imt_trampoline = NULL;
1724 if ((gpointer)vtable_slot < (gpointer)vtable) {
1725 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1726 int imt_slot = MONO_IMT_SIZE + displacement;
1728 /* Force the rebuild of the thunk at the next call */
1729 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1730 *vtable_slot = imt_trampoline;
1732 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1734 entries = get_generic_virtual_entries (domain, vtable_slot);
1736 sorted = imt_sort_slot_entries (entries);
1738 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1742 MonoImtBuilderEntry *next = entries->next;
1747 for (i = 0; i < sorted->len; ++i)
1748 g_free (g_ptr_array_index (sorted, i));
1749 g_ptr_array_free (sorted, TRUE);
1752 #ifndef __native_client__
1753 /* We don't re-use any thunks as there is a lot of overhead */
1754 /* to deleting and re-using code in Native Client. */
1755 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1756 invalidate_generic_virtual_thunk (domain, old_thunk);
1760 mono_domain_unlock (domain);
1763 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1766 * mono_class_vtable:
1767 * @domain: the application domain
1768 * @class: the class to initialize
1770 * VTables are domain specific because we create domain specific code, and
1771 * they contain the domain specific static class data.
1772 * On failure, NULL is returned, and class->exception_type is set.
1775 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1777 return mono_class_vtable_full (domain, class, FALSE);
1781 * mono_class_vtable_full:
1782 * @domain: the application domain
1783 * @class: the class to initialize
1784 * @raise_on_error if an exception should be raised on failure or not
1786 * VTables are domain specific because we create domain specific code, and
1787 * they contain the domain specific static class data.
1790 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1792 MonoClassRuntimeInfo *runtime_info;
1796 if (class->exception_type) {
1798 mono_raise_exception (mono_class_get_exception_for_failure (class));
1802 /* this check can be inlined in jitted code, too */
1803 runtime_info = class->runtime_info;
1804 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1805 return runtime_info->domain_vtables [domain->domain_id];
1806 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1810 * mono_class_try_get_vtable:
1811 * @domain: the application domain
1812 * @class: the class to initialize
1814 * This function tries to get the associated vtable from @class if
1815 * it was already created.
1818 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1820 MonoClassRuntimeInfo *runtime_info;
1824 runtime_info = class->runtime_info;
1825 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1826 return runtime_info->domain_vtables [domain->domain_id];
1831 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1834 MonoClassRuntimeInfo *runtime_info, *old_info;
1835 MonoClassField *field;
1838 int imt_table_bytes = 0;
1839 guint32 vtable_size, class_size;
1842 gpointer *interface_offsets;
1844 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1845 mono_domain_lock (domain);
1846 runtime_info = class->runtime_info;
1847 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1848 mono_domain_unlock (domain);
1849 mono_loader_unlock ();
1850 return runtime_info->domain_vtables [domain->domain_id];
1852 if (!class->inited || class->exception_type) {
1853 if (!mono_class_init (class) || class->exception_type) {
1854 mono_domain_unlock (domain);
1855 mono_loader_unlock ();
1857 mono_raise_exception (mono_class_get_exception_for_failure (class));
1862 /* Array types require that their element type be valid*/
1863 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1864 MonoClass *element_class = class->element_class;
1865 if (!element_class->inited)
1866 mono_class_init (element_class);
1868 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1869 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1870 mono_class_setup_vtable (element_class);
1872 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1873 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1874 if (class->exception_type == MONO_EXCEPTION_NONE)
1875 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1876 mono_domain_unlock (domain);
1877 mono_loader_unlock ();
1879 mono_raise_exception (mono_class_get_exception_for_failure (class));
1885 * For some classes, mono_class_init () already computed class->vtable_size, and
1886 * that is all that is needed because of the vtable trampolines.
1888 if (!class->vtable_size)
1889 mono_class_setup_vtable (class);
1891 if (class->generic_class && !class->vtable)
1892 mono_class_check_vtable_constraints (class, NULL);
1894 /* Initialize klass->has_finalize */
1895 mono_class_has_finalizer (class);
1897 if (class->exception_type) {
1898 mono_domain_unlock (domain);
1899 mono_loader_unlock ();
1901 mono_raise_exception (mono_class_get_exception_for_failure (class));
1906 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1907 if (class->interface_offsets_count) {
1908 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1909 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1910 mono_stats.imt_number_of_tables++;
1911 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1914 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1915 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1918 mono_stats.used_class_count++;
1919 mono_stats.class_vtable_size += vtable_size;
1920 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1923 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1925 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1927 vt->rank = class->rank;
1928 vt->domain = domain;
1930 mono_class_compute_gc_descriptor (class);
1932 * We can't use typed allocation in the non-root domains, since the
1933 * collector needs the GC descriptor stored in the vtable even after
1934 * the mempool containing the vtable is destroyed when the domain is
1935 * unloaded. An alternative might be to allocate vtables in the GC
1936 * heap, but this does not seem to work (it leads to crashes inside
1937 * libgc). If that approach is tried, two gc descriptors need to be
1938 * allocated for each class: one for the root domain, and one for all
1939 * other domains. The second descriptor should contain a bit for the
1940 * vtable field in MonoObject, since we can no longer assume the
1941 * vtable is reachable by other roots after the appdomain is unloaded.
1943 #ifdef HAVE_BOEHM_GC
1944 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1945 vt->gc_descr = GC_NO_DESCRIPTOR;
1948 vt->gc_descr = class->gc_descr;
1950 if ((class_size = mono_class_data_size (class))) {
1951 if (class->has_static_refs) {
1952 gpointer statics_gc_descr;
1954 gsize default_bitmap [4] = {0};
1957 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1958 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1959 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1960 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1961 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1962 if (bitmap != default_bitmap)
1965 vt->data = mono_domain_alloc0 (domain, class_size);
1967 mono_stats.class_static_data_size += class_size;
1972 while ((field = mono_class_get_fields (class, &iter))) {
1973 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1975 if (mono_field_is_deleted (field))
1977 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1978 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1979 if (special_static != SPECIAL_STATIC_NONE) {
1980 guint32 size, offset;
1982 gsize default_bitmap [4] = {0};
1986 if (mono_type_is_reference (field->type)) {
1987 default_bitmap [0] = 1;
1989 bitmap = default_bitmap;
1990 } else if (mono_type_is_struct (field->type)) {
1991 fclass = mono_class_from_mono_type (field->type);
1992 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1994 default_bitmap [0] = 0;
1996 bitmap = default_bitmap;
1998 size = mono_type_size (field->type, &align);
1999 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
2000 if (!domain->special_static_fields)
2001 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2002 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2003 if (bitmap != default_bitmap)
2006 * This marks the field as special static to speed up the
2007 * checks in mono_field_static_get/set_value ().
2013 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2014 MonoClass *fklass = mono_class_from_mono_type (field->type);
2015 const char *data = mono_field_get_data (field);
2017 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2018 t = (char*)vt->data + field->offset;
2019 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2022 if (fklass->valuetype) {
2023 memcpy (t, data, mono_class_value_size (fklass, NULL));
2025 /* it's a pointer type: add check */
2026 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2033 vt->max_interface_id = class->max_interface_id;
2034 vt->interface_bitmap = class->interface_bitmap;
2036 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2037 // class->name, class->interface_offsets_count);
2039 if (! ARCH_USE_IMT) {
2040 /* initialize interface offsets */
2041 for (i = 0; i < class->interface_offsets_count; ++i) {
2042 int interface_id = class->interfaces_packed [i]->interface_id;
2043 int slot = class->interface_offsets_packed [i];
2044 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2048 /* class_vtable_array keeps an array of created vtables
2050 g_ptr_array_add (domain->class_vtable_array, vt);
2051 /* class->runtime_info is protected by the loader lock, both when
2052 * it it enlarged and when it is stored info.
2055 old_info = class->runtime_info;
2056 if (old_info && old_info->max_domain >= domain->domain_id) {
2057 /* someone already created a large enough runtime info */
2058 mono_memory_barrier ();
2059 old_info->domain_vtables [domain->domain_id] = vt;
2061 int new_size = domain->domain_id;
2063 new_size = MAX (new_size, old_info->max_domain);
2065 /* make the new size a power of two */
2067 while (new_size > i)
2070 /* this is a bounded memory retention issue: may want to
2071 * handle it differently when we'll have a rcu-like system.
2073 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2074 runtime_info->max_domain = new_size - 1;
2075 /* copy the stuff from the older info */
2077 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2079 runtime_info->domain_vtables [domain->domain_id] = vt;
2081 mono_memory_barrier ();
2082 class->runtime_info = runtime_info;
2085 /* Initialize vtable */
2086 if (callbacks.get_vtable_trampoline) {
2087 // This also covers the AOT case
2088 for (i = 0; i < class->vtable_size; ++i) {
2089 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2092 mono_class_setup_vtable (class);
2094 for (i = 0; i < class->vtable_size; ++i) {
2097 if ((cm = class->vtable [i]))
2098 vt->vtable [i] = arch_create_jit_trampoline (cm);
2102 if (ARCH_USE_IMT && imt_table_bytes) {
2103 /* Now that the vtable is full, we can actually fill up the IMT */
2104 if (callbacks.get_imt_trampoline) {
2105 /* lazy construction of the IMT entries enabled */
2106 for (i = 0; i < MONO_IMT_SIZE; ++i)
2107 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2109 build_imt (class, vt, domain, interface_offsets, NULL);
2113 mono_domain_unlock (domain);
2114 mono_loader_unlock ();
2116 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2117 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2118 mono_raise_exception (mono_class_get_exception_for_failure (class));
2120 /* make sure the parent is initialized */
2121 /*FIXME shouldn't this fail the current type?*/
2123 mono_class_vtable_full (domain, class->parent, raise_on_error);
2125 /*FIXME check for OOM*/
2126 vt->type = mono_type_get_object (domain, &class->byval_arg);
2127 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2128 /* This is unregistered in
2129 unregister_vtable_reflection_type() in
2131 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2132 if (class->contextbound)
2141 * mono_class_proxy_vtable:
2142 * @domain: the application domain
2143 * @remove_class: the remote class
2145 * Creates a vtable for transparent proxies. It is basically
2146 * a copy of the real vtable of the class wrapped in @remote_class,
2147 * but all function pointers invoke the remoting functions, and
2148 * vtable->klass points to the transparent proxy class, and not to @class.
2151 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2154 MonoVTable *vt, *pvt;
2155 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2157 GSList *extra_interfaces = NULL;
2158 MonoClass *class = remote_class->proxy_class;
2159 gpointer *interface_offsets;
2163 #ifdef COMPRESSED_INTERFACE_BITMAP
2167 vt = mono_class_vtable (domain, class);
2168 g_assert (vt); /*FIXME property handle failure*/
2169 max_interface_id = vt->max_interface_id;
2171 /* Calculate vtable space for extra interfaces */
2172 for (j = 0; j < remote_class->interface_count; j++) {
2173 MonoClass* iclass = remote_class->interfaces[j];
2177 /*FIXME test for interfaces with variant generic arguments*/
2178 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2179 continue; /* interface implemented by the class */
2180 if (g_slist_find (extra_interfaces, iclass))
2183 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2185 method_count = mono_class_num_methods (iclass);
2187 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2188 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2190 for (i = 0; i < ifaces->len; ++i) {
2191 MonoClass *ic = g_ptr_array_index (ifaces, i);
2192 /*FIXME test for interfaces with variant generic arguments*/
2193 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2194 continue; /* interface implemented by the class */
2195 if (g_slist_find (extra_interfaces, ic))
2197 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2198 method_count += mono_class_num_methods (ic);
2200 g_ptr_array_free (ifaces, TRUE);
2203 extra_interface_vtsize += method_count * sizeof (gpointer);
2204 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2208 mono_stats.imt_number_of_tables++;
2209 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2210 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2211 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2213 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2214 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2217 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2219 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2221 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2223 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2224 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2226 pvt->klass = mono_defaults.transparent_proxy_class;
2227 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2228 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2230 /* initialize vtable */
2231 mono_class_setup_vtable (class);
2232 for (i = 0; i < class->vtable_size; ++i) {
2235 if ((cm = class->vtable [i]))
2236 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2238 pvt->vtable [i] = NULL;
2241 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2242 /* create trampolines for abstract methods */
2243 for (k = class; k; k = k->parent) {
2245 gpointer iter = NULL;
2246 while ((m = mono_class_get_methods (k, &iter)))
2247 if (!pvt->vtable [m->slot])
2248 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2252 pvt->max_interface_id = max_interface_id;
2253 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2254 #ifdef COMPRESSED_INTERFACE_BITMAP
2255 bitmap = g_malloc0 (bsize);
2257 bitmap = mono_domain_alloc0 (domain, bsize);
2260 if (! ARCH_USE_IMT) {
2261 /* initialize interface offsets */
2262 for (i = 0; i < class->interface_offsets_count; ++i) {
2263 int interface_id = class->interfaces_packed [i]->interface_id;
2264 int slot = class->interface_offsets_packed [i];
2265 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2268 for (i = 0; i < class->interface_offsets_count; ++i) {
2269 int interface_id = class->interfaces_packed [i]->interface_id;
2270 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2273 if (extra_interfaces) {
2274 int slot = class->vtable_size;
2280 /* Create trampolines for the methods of the interfaces */
2281 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2282 interf = list_item->data;
2284 if (! ARCH_USE_IMT) {
2285 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2287 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2291 while ((cm = mono_class_get_methods (interf, &iter)))
2292 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2294 slot += mono_class_num_methods (interf);
2296 if (! ARCH_USE_IMT) {
2297 g_slist_free (extra_interfaces);
2302 /* Now that the vtable is full, we can actually fill up the IMT */
2303 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2304 if (extra_interfaces) {
2305 g_slist_free (extra_interfaces);
2309 #ifdef COMPRESSED_INTERFACE_BITMAP
2310 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2311 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2312 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2315 pvt->interface_bitmap = bitmap;
2321 * mono_class_field_is_special_static:
2323 * Returns whether @field is a thread/context static field.
2326 mono_class_field_is_special_static (MonoClassField *field)
2328 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2330 if (mono_field_is_deleted (field))
2332 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2333 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2340 * mono_class_field_get_special_static_type:
2341 * @field: The MonoClassField describing the field.
2343 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2344 * SPECIAL_STATIC_NONE otherwise.
2347 mono_class_field_get_special_static_type (MonoClassField *field)
2349 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2350 return SPECIAL_STATIC_NONE;
2351 if (mono_field_is_deleted (field))
2352 return SPECIAL_STATIC_NONE;
2353 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2354 return field_is_special_static (field->parent, field);
2355 return SPECIAL_STATIC_NONE;
2359 * mono_class_has_special_static_fields:
2361 * Returns whenever @klass has any thread/context static fields.
2364 mono_class_has_special_static_fields (MonoClass *klass)
2366 MonoClassField *field;
2370 while ((field = mono_class_get_fields (klass, &iter))) {
2371 g_assert (field->parent == klass);
2372 if (mono_class_field_is_special_static (field))
2380 * create_remote_class_key:
2381 * Creates an array of pointers that can be used as a hash key for a remote class.
2382 * The first element of the array is the number of pointers.
2385 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2390 if (remote_class == NULL) {
2391 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2392 key = g_malloc (sizeof(gpointer) * 3);
2393 key [0] = GINT_TO_POINTER (2);
2394 key [1] = mono_defaults.marshalbyrefobject_class;
2395 key [2] = extra_class;
2397 key = g_malloc (sizeof(gpointer) * 2);
2398 key [0] = GINT_TO_POINTER (1);
2399 key [1] = extra_class;
2402 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2403 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2404 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2405 key [1] = remote_class->proxy_class;
2407 // Keep the list of interfaces sorted
2408 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2409 if (extra_class && remote_class->interfaces [i] > extra_class) {
2410 key [j++] = extra_class;
2413 key [j] = remote_class->interfaces [i];
2416 key [j] = extra_class;
2418 // Replace the old class. The interface list is the same
2419 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2420 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2421 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2422 for (i = 0; i < remote_class->interface_count; i++)
2423 key [2 + i] = remote_class->interfaces [i];
2431 * copy_remote_class_key:
2433 * Make a copy of KEY in the domain and return the copy.
2436 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2438 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2439 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2441 memcpy (mp_key, key, key_size);
2447 * mono_remote_class:
2448 * @domain: the application domain
2449 * @class_name: name of the remote class
2451 * Creates and initializes a MonoRemoteClass object for a remote type.
2453 * Can raise an exception on failure.
2456 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2459 MonoRemoteClass *rc;
2460 gpointer* key, *mp_key;
2463 key = create_remote_class_key (NULL, proxy_class);
2465 mono_domain_lock (domain);
2466 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2470 mono_domain_unlock (domain);
2474 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2475 if (!mono_error_ok (&error)) {
2477 mono_domain_unlock (domain);
2478 mono_error_raise_exception (&error);
2481 mp_key = copy_remote_class_key (domain, key);
2485 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2486 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2487 rc->interface_count = 1;
2488 rc->interfaces [0] = proxy_class;
2489 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2491 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2492 rc->interface_count = 0;
2493 rc->proxy_class = proxy_class;
2496 rc->default_vtable = NULL;
2497 rc->xdomain_vtable = NULL;
2498 rc->proxy_class_name = name;
2499 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2501 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2503 mono_domain_unlock (domain);
2508 * clone_remote_class:
2509 * Creates a copy of the remote_class, adding the provided class or interface
2511 static MonoRemoteClass*
2512 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2514 MonoRemoteClass *rc;
2515 gpointer* key, *mp_key;
2517 key = create_remote_class_key (remote_class, extra_class);
2518 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2524 mp_key = copy_remote_class_key (domain, key);
2528 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2530 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2531 rc->proxy_class = remote_class->proxy_class;
2532 rc->interface_count = remote_class->interface_count + 1;
2534 // Keep the list of interfaces sorted, since the hash key of
2535 // the remote class depends on this
2536 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2537 if (remote_class->interfaces [i] > extra_class && i == j)
2538 rc->interfaces [j++] = extra_class;
2539 rc->interfaces [j] = remote_class->interfaces [i];
2542 rc->interfaces [j] = extra_class;
2544 // Replace the old class. The interface array is the same
2545 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2546 rc->proxy_class = extra_class;
2547 rc->interface_count = remote_class->interface_count;
2548 if (rc->interface_count > 0)
2549 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2552 rc->default_vtable = NULL;
2553 rc->xdomain_vtable = NULL;
2554 rc->proxy_class_name = remote_class->proxy_class_name;
2556 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2562 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2564 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2565 mono_domain_lock (domain);
2566 if (rp->target_domain_id != -1) {
2567 if (remote_class->xdomain_vtable == NULL)
2568 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2569 mono_domain_unlock (domain);
2570 mono_loader_unlock ();
2571 return remote_class->xdomain_vtable;
2573 if (remote_class->default_vtable == NULL) {
2576 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2577 klass = mono_class_from_mono_type (type);
2578 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2579 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2581 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2584 mono_domain_unlock (domain);
2585 mono_loader_unlock ();
2586 return remote_class->default_vtable;
2590 * mono_upgrade_remote_class:
2591 * @domain: the application domain
2592 * @tproxy: the proxy whose remote class has to be upgraded.
2593 * @klass: class to which the remote class can be casted.
2595 * Updates the vtable of the remote class by adding the necessary method slots
2596 * and interface offsets so it can be safely casted to klass. klass can be a
2597 * class or an interface.
2600 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2602 MonoTransparentProxy *tproxy;
2603 MonoRemoteClass *remote_class;
2604 gboolean redo_vtable;
2606 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2607 mono_domain_lock (domain);
2609 tproxy = (MonoTransparentProxy*) proxy_object;
2610 remote_class = tproxy->remote_class;
2612 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2615 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2616 if (remote_class->interfaces [i] == klass)
2617 redo_vtable = FALSE;
2620 redo_vtable = (remote_class->proxy_class != klass);
2624 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2625 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2628 mono_domain_unlock (domain);
2629 mono_loader_unlock ();
2634 * mono_object_get_virtual_method:
2635 * @obj: object to operate on.
2638 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2639 * the instance of a callvirt of method.
2642 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2645 MonoMethod **vtable;
2647 MonoMethod *res = NULL;
2649 klass = mono_object_class (obj);
2650 if (klass == mono_defaults.transparent_proxy_class) {
2651 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2657 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2660 mono_class_setup_vtable (klass);
2661 vtable = klass->vtable;
2663 if (method->slot == -1) {
2664 /* method->slot might not be set for instances of generic methods */
2665 if (method->is_inflated) {
2666 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2667 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2670 g_assert_not_reached ();
2674 /* check method->slot is a valid index: perform isinstance? */
2675 if (method->slot != -1) {
2676 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2678 gboolean variance_used = FALSE;
2679 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2680 g_assert (iface_offset > 0);
2681 res = vtable [iface_offset + method->slot];
2684 res = vtable [method->slot];
2689 /* It may be an interface, abstract class method or generic method */
2690 if (!res || mono_method_signature (res)->generic_param_count)
2693 /* generic methods demand invoke_with_check */
2694 if (mono_method_signature (res)->generic_param_count)
2695 res = mono_marshal_get_remoting_invoke_with_check (res);
2698 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2699 res = mono_cominterop_get_invoke (res);
2702 res = mono_marshal_get_remoting_invoke (res);
2705 if (method->is_inflated) {
2706 /* Have to inflate the result */
2707 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2717 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2719 g_error ("runtime invoke called on uninitialized runtime");
2723 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2726 * mono_runtime_invoke:
2727 * @method: method to invoke
2728 * @obJ: object instance
2729 * @params: arguments to the method
2730 * @exc: exception information.
2732 * Invokes the method represented by @method on the object @obj.
2734 * obj is the 'this' pointer, it should be NULL for static
2735 * methods, a MonoObject* for object instances and a pointer to
2736 * the value type for value types.
2738 * The params array contains the arguments to the method with the
2739 * same convention: MonoObject* pointers for object instances and
2740 * pointers to the value type otherwise.
2742 * From unmanaged code you'll usually use the
2743 * mono_runtime_invoke() variant.
2745 * Note that this function doesn't handle virtual methods for
2746 * you, it will exec the exact method you pass: we still need to
2747 * expose a function to lookup the derived class implementation
2748 * of a virtual method (there are examples of this in the code,
2751 * You can pass NULL as the exc argument if you don't want to
2752 * catch exceptions, otherwise, *exc will be set to the exception
2753 * thrown, if any. if an exception is thrown, you can't use the
2754 * MonoObject* result from the function.
2756 * If the method returns a value type, it is boxed in an object
2760 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2764 if (mono_runtime_get_no_exec ())
2765 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2767 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2768 mono_profiler_method_start_invoke (method);
2770 result = default_mono_runtime_invoke (method, obj, params, exc);
2772 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2773 mono_profiler_method_end_invoke (method);
2779 * mono_method_get_unmanaged_thunk:
2780 * @method: method to generate a thunk for.
2782 * Returns an unmanaged->managed thunk that can be used to call
2783 * a managed method directly from C.
2785 * The thunk's C signature closely matches the managed signature:
2787 * C#: public bool Equals (object obj);
2788 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2789 * MonoObject*, MonoException**);
2791 * The 1st ("this") parameter must not be used with static methods:
2793 * C#: public static bool ReferenceEquals (object a, object b);
2794 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2797 * The last argument must be a non-null pointer of a MonoException* pointer.
2798 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2799 * exception has been thrown in managed code. Otherwise it will point
2800 * to the MonoException* caught by the thunk. In this case, the result of
2801 * the thunk is undefined:
2803 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2804 * MonoException *ex = NULL;
2805 * Equals func = mono_method_get_unmanaged_thunk (method);
2806 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2808 * // handle exception
2811 * The calling convention of the thunk matches the platform's default
2812 * convention. This means that under Windows, C declarations must
2813 * contain the __stdcall attribute:
2815 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2816 * MonoObject*, MonoException**);
2820 * Value type arguments and return values are treated as they were objects:
2822 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2823 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2825 * Arguments must be properly boxed upon trunk's invocation, while return
2826 * values must be unboxed.
2829 mono_method_get_unmanaged_thunk (MonoMethod *method)
2831 method = mono_marshal_get_thunk_invoke_wrapper (method);
2832 return mono_compile_method (method);
2836 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2840 /* object fields cannot be byref, so we don't need a
2842 gpointer *p = (gpointer*)dest;
2849 case MONO_TYPE_BOOLEAN:
2851 case MONO_TYPE_U1: {
2852 guint8 *p = (guint8*)dest;
2853 *p = value ? *(guint8*)value : 0;
2858 case MONO_TYPE_CHAR: {
2859 guint16 *p = (guint16*)dest;
2860 *p = value ? *(guint16*)value : 0;
2863 #if SIZEOF_VOID_P == 4
2868 case MONO_TYPE_U4: {
2869 gint32 *p = (gint32*)dest;
2870 *p = value ? *(gint32*)value : 0;
2873 #if SIZEOF_VOID_P == 8
2878 case MONO_TYPE_U8: {
2879 gint64 *p = (gint64*)dest;
2880 *p = value ? *(gint64*)value : 0;
2883 case MONO_TYPE_R4: {
2884 float *p = (float*)dest;
2885 *p = value ? *(float*)value : 0;
2888 case MONO_TYPE_R8: {
2889 double *p = (double*)dest;
2890 *p = value ? *(double*)value : 0;
2893 case MONO_TYPE_STRING:
2894 case MONO_TYPE_SZARRAY:
2895 case MONO_TYPE_CLASS:
2896 case MONO_TYPE_OBJECT:
2897 case MONO_TYPE_ARRAY:
2898 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2900 case MONO_TYPE_FNPTR:
2901 case MONO_TYPE_PTR: {
2902 gpointer *p = (gpointer*)dest;
2903 *p = deref_pointer? *(gpointer*)value: value;
2906 case MONO_TYPE_VALUETYPE:
2907 /* note that 't' and 'type->type' can be different */
2908 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2909 t = mono_class_enum_basetype (type->data.klass)->type;
2912 MonoClass *class = mono_class_from_mono_type (type);
2913 int size = mono_class_value_size (class, NULL);
2915 memset (dest, 0, size);
2917 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2920 case MONO_TYPE_GENERICINST:
2921 t = type->data.generic_class->container_class->byval_arg.type;
2924 g_warning ("got type %x", type->type);
2925 g_assert_not_reached ();
2930 * mono_field_set_value:
2931 * @obj: Instance object
2932 * @field: MonoClassField describing the field to set
2933 * @value: The value to be set
2935 * Sets the value of the field described by @field in the object instance @obj
2936 * to the value passed in @value. This method should only be used for instance
2937 * fields. For static fields, use mono_field_static_set_value.
2939 * The value must be on the native format of the field type.
2942 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2946 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2948 dest = (char*)obj + field->offset;
2949 set_value (field->type, dest, value, FALSE);
2953 * mono_field_static_set_value:
2954 * @field: MonoClassField describing the field to set
2955 * @value: The value to be set
2957 * Sets the value of the static field described by @field
2958 * to the value passed in @value.
2960 * The value must be on the native format of the field type.
2963 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2967 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2968 /* you cant set a constant! */
2969 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2971 if (field->offset == -1) {
2972 /* Special static */
2975 mono_domain_lock (vt->domain);
2976 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2977 mono_domain_unlock (vt->domain);
2978 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2980 dest = (char*)vt->data + field->offset;
2982 set_value (field->type, dest, value, FALSE);
2985 /* Used by the debugger */
2987 mono_vtable_get_static_field_data (MonoVTable *vt)
2993 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2997 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2998 if (field->offset == -1) {
2999 /* Special static */
3002 mono_domain_lock (vt->domain);
3003 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3004 mono_domain_unlock (vt->domain);
3005 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3007 src = (guint8*)vt->data + field->offset;
3010 src = (guint8*)obj + field->offset;
3017 * mono_field_get_value:
3018 * @obj: Object instance
3019 * @field: MonoClassField describing the field to fetch information from
3020 * @value: pointer to the location where the value will be stored
3022 * Use this routine to get the value of the field @field in the object
3025 * The pointer provided by value must be of the field type, for reference
3026 * types this is a MonoObject*, for value types its the actual pointer to
3031 * mono_field_get_value (obj, int_field, &i);
3034 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3040 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3042 src = (char*)obj + field->offset;
3043 set_value (field->type, value, src, TRUE);
3047 * mono_field_get_value_object:
3048 * @domain: domain where the object will be created (if boxing)
3049 * @field: MonoClassField describing the field to fetch information from
3050 * @obj: The object instance for the field.
3052 * Returns: a new MonoObject with the value from the given field. If the
3053 * field represents a value type, the value is boxed.
3057 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3061 MonoVTable *vtable = NULL;
3063 gboolean is_static = FALSE;
3064 gboolean is_ref = FALSE;
3065 gboolean is_literal = FALSE;
3066 gboolean is_ptr = FALSE;
3068 MonoType *type = mono_field_get_type_checked (field, &error);
3070 if (!mono_error_ok (&error))
3071 mono_error_raise_exception (&error);
3073 switch (type->type) {
3074 case MONO_TYPE_STRING:
3075 case MONO_TYPE_OBJECT:
3076 case MONO_TYPE_CLASS:
3077 case MONO_TYPE_ARRAY:
3078 case MONO_TYPE_SZARRAY:
3083 case MONO_TYPE_BOOLEAN:
3086 case MONO_TYPE_CHAR:
3095 case MONO_TYPE_VALUETYPE:
3096 is_ref = type->byref;
3098 case MONO_TYPE_GENERICINST:
3099 is_ref = !mono_type_generic_inst_is_valuetype (type);
3105 g_error ("type 0x%x not handled in "
3106 "mono_field_get_value_object", type->type);
3110 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3113 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3117 vtable = mono_class_vtable (domain, field->parent);
3119 char *name = mono_type_get_full_name (field->parent);
3120 /*FIXME extend this to use the MonoError api*/
3121 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3125 if (!vtable->initialized)
3126 mono_runtime_class_init (vtable);
3134 get_default_field_value (domain, field, &o);
3135 } else if (is_static) {
3136 mono_field_static_get_value (vtable, field, &o);
3138 mono_field_get_value (obj, field, &o);
3144 static MonoMethod *m;
3150 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3151 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3157 get_default_field_value (domain, field, v);
3158 } else if (is_static) {
3159 mono_field_static_get_value (vtable, field, v);
3161 mono_field_get_value (obj, field, v);
3164 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3166 args [1] = mono_type_get_object (mono_domain_get (), type);
3168 return mono_runtime_invoke (m, NULL, args, NULL);
3171 /* boxed value type */
3172 klass = mono_class_from_mono_type (type);
3174 if (mono_class_is_nullable (klass))
3175 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3177 o = mono_object_new (domain, klass);
3178 v = ((gchar *) o) + sizeof (MonoObject);
3181 get_default_field_value (domain, field, v);
3182 } else if (is_static) {
3183 mono_field_static_get_value (vtable, field, v);
3185 mono_field_get_value (obj, field, v);
3192 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3195 const char *p = blob;
3196 mono_metadata_decode_blob_size (p, &p);
3199 case MONO_TYPE_BOOLEAN:
3202 *(guint8 *) value = *p;
3204 case MONO_TYPE_CHAR:
3207 *(guint16*) value = read16 (p);
3211 *(guint32*) value = read32 (p);
3215 *(guint64*) value = read64 (p);
3218 readr4 (p, (float*) value);
3221 readr8 (p, (double*) value);
3223 case MONO_TYPE_STRING:
3224 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3226 case MONO_TYPE_CLASS:
3227 *(gpointer*) value = NULL;
3231 g_warning ("type 0x%02x should not be in constant table", type);
3237 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3239 MonoTypeEnum def_type;
3242 data = mono_class_get_field_default_value (field, &def_type);
3243 mono_get_constant_value_from_blob (domain, def_type, data, value);
3247 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3251 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3253 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3254 get_default_field_value (vt->domain, field, value);
3258 if (field->offset == -1) {
3259 /* Special static */
3260 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3261 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3263 src = (char*)vt->data + field->offset;
3265 set_value (field->type, value, src, TRUE);
3269 * mono_field_static_get_value:
3270 * @vt: vtable to the object
3271 * @field: MonoClassField describing the field to fetch information from
3272 * @value: where the value is returned
3274 * Use this routine to get the value of the static field @field value.
3276 * The pointer provided by value must be of the field type, for reference
3277 * types this is a MonoObject*, for value types its the actual pointer to
3282 * mono_field_static_get_value (vt, int_field, &i);
3285 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3287 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3291 * mono_property_set_value:
3292 * @prop: MonoProperty to set
3293 * @obj: instance object on which to act
3294 * @params: parameters to pass to the propery
3295 * @exc: optional exception
3297 * Invokes the property's set method with the given arguments on the
3298 * object instance obj (or NULL for static properties).
3300 * You can pass NULL as the exc argument if you don't want to
3301 * catch exceptions, otherwise, *exc will be set to the exception
3302 * thrown, if any. if an exception is thrown, you can't use the
3303 * MonoObject* result from the function.
3306 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3308 default_mono_runtime_invoke (prop->set, obj, params, exc);
3312 * mono_property_get_value:
3313 * @prop: MonoProperty to fetch
3314 * @obj: instance object on which to act
3315 * @params: parameters to pass to the propery
3316 * @exc: optional exception
3318 * Invokes the property's get method with the given arguments on the
3319 * object instance obj (or NULL for static properties).
3321 * You can pass NULL as the exc argument if you don't want to
3322 * catch exceptions, otherwise, *exc will be set to the exception
3323 * thrown, if any. if an exception is thrown, you can't use the
3324 * MonoObject* result from the function.
3326 * Returns: the value from invoking the get method on the property.
3329 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3331 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3335 * mono_nullable_init:
3336 * @buf: The nullable structure to initialize.
3337 * @value: the value to initialize from
3338 * @klass: the type for the object
3340 * Initialize the nullable structure pointed to by @buf from @value which
3341 * should be a boxed value type. The size of @buf should be able to hold
3342 * as much data as the @klass->instance_size (which is the number of bytes
3343 * that will be copies).
3345 * Since Nullables have variable structure, we can not define a C
3346 * structure for them.
3349 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3351 MonoClass *param_class = klass->cast_class;
3353 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3354 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3356 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3358 if (param_class->has_references)
3359 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3361 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3363 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3368 * mono_nullable_box:
3369 * @buf: The buffer representing the data to be boxed
3370 * @klass: the type to box it as.
3372 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3376 mono_nullable_box (guint8 *buf, MonoClass *klass)
3378 MonoClass *param_class = klass->cast_class;
3380 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3381 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3383 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3384 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3385 if (param_class->has_references)
3386 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3388 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3396 * mono_get_delegate_invoke:
3397 * @klass: The delegate class
3399 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3402 mono_get_delegate_invoke (MonoClass *klass)
3406 /* This is called at runtime, so avoid the slower search in metadata */
3407 mono_class_setup_methods (klass);
3408 if (klass->exception_type)
3410 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3415 * mono_runtime_delegate_invoke:
3416 * @delegate: pointer to a delegate object.
3417 * @params: parameters for the delegate.
3418 * @exc: Pointer to the exception result.
3420 * Invokes the delegate method @delegate with the parameters provided.
3422 * You can pass NULL as the exc argument if you don't want to
3423 * catch exceptions, otherwise, *exc will be set to the exception
3424 * thrown, if any. if an exception is thrown, you can't use the
3425 * MonoObject* result from the function.
3428 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3432 im = mono_get_delegate_invoke (delegate->vtable->klass);
3435 return mono_runtime_invoke (im, delegate, params, exc);
3438 static char **main_args = NULL;
3439 static int num_main_args;
3442 * mono_runtime_get_main_args:
3444 * Returns: a MonoArray with the arguments passed to the main program
3447 mono_runtime_get_main_args (void)
3451 MonoDomain *domain = mono_domain_get ();
3456 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3458 for (i = 0; i < num_main_args; ++i)
3459 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3465 free_main_args (void)
3469 for (i = 0; i < num_main_args; ++i)
3470 g_free (main_args [i]);
3475 * mono_runtime_run_main:
3476 * @method: the method to start the application with (usually Main)
3477 * @argc: number of arguments from the command line
3478 * @argv: array of strings from the command line
3479 * @exc: excetption results
3481 * Execute a standard Main() method (argc/argv contains the
3482 * executable name). This method also sets the command line argument value
3483 * needed by System.Environment.
3488 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3492 MonoArray *args = NULL;
3493 MonoDomain *domain = mono_domain_get ();
3494 gchar *utf8_fullpath;
3495 MonoMethodSignature *sig;
3497 g_assert (method != NULL);
3499 mono_thread_set_main (mono_thread_current ());
3501 main_args = g_new0 (char*, argc);
3502 num_main_args = argc;
3504 if (!g_path_is_absolute (argv [0])) {
3505 gchar *basename = g_path_get_basename (argv [0]);
3506 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3510 utf8_fullpath = mono_utf8_from_external (fullpath);
3511 if(utf8_fullpath == NULL) {
3512 /* Printing the arg text will cause glib to
3513 * whinge about "Invalid UTF-8", but at least
3514 * its relevant, and shows the problem text
3517 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3518 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3525 utf8_fullpath = mono_utf8_from_external (argv[0]);
3526 if(utf8_fullpath == NULL) {
3527 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3528 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3533 main_args [0] = utf8_fullpath;
3535 for (i = 1; i < argc; ++i) {
3538 utf8_arg=mono_utf8_from_external (argv[i]);
3539 if(utf8_arg==NULL) {
3540 /* Ditto the comment about Invalid UTF-8 here */
3541 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3542 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3546 main_args [i] = utf8_arg;
3551 sig = mono_method_signature (method);
3553 g_print ("Unable to load Main method.\n");
3557 if (sig->param_count) {
3558 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3559 for (i = 0; i < argc; ++i) {
3560 /* The encodings should all work, given that
3561 * we've checked all these args for the
3564 gchar *str = mono_utf8_from_external (argv [i]);
3565 MonoString *arg = mono_string_new (domain, str);
3566 mono_array_setref (args, i, arg);
3570 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3573 mono_assembly_set_main (method->klass->image->assembly);
3575 return mono_runtime_exec_main (method, args, exc);
3579 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3581 static MonoMethod *serialize_method;
3586 if (!serialize_method) {
3587 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3588 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3591 if (!serialize_method) {
3596 g_assert (!mono_object_class (obj)->marshalbyref);
3600 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3608 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3610 static MonoMethod *deserialize_method;
3615 if (!deserialize_method) {
3616 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3617 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3619 if (!deserialize_method) {
3626 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3634 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3636 static MonoMethod *get_proxy_method;
3638 MonoDomain *domain = mono_domain_get ();
3639 MonoRealProxy *real_proxy;
3640 MonoReflectionType *reflection_type;
3641 MonoTransparentProxy *transparent_proxy;
3643 if (!get_proxy_method)
3644 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3646 g_assert (obj->vtable->klass->marshalbyref);
3648 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3649 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3651 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3652 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3655 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3659 return (MonoObject*) transparent_proxy;
3663 * mono_object_xdomain_representation
3665 * @target_domain: a domain
3666 * @exc: pointer to a MonoObject*
3668 * Creates a representation of obj in the domain target_domain. This
3669 * is either a copy of obj arrived through via serialization and
3670 * deserialization or a proxy, depending on whether the object is
3671 * serializable or marshal by ref. obj must not be in target_domain.
3673 * If the object cannot be represented in target_domain, NULL is
3674 * returned and *exc is set to an appropriate exception.
3677 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3679 MonoObject *deserialized = NULL;
3680 gboolean failure = FALSE;
3684 if (mono_object_class (obj)->marshalbyref) {
3685 deserialized = make_transparent_proxy (obj, &failure, exc);
3687 MonoDomain *domain = mono_domain_get ();
3688 MonoObject *serialized;
3690 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3691 serialized = serialize_object (obj, &failure, exc);
3692 mono_domain_set_internal_with_options (target_domain, FALSE);
3694 deserialized = deserialize_object (serialized, &failure, exc);
3695 if (domain != target_domain)
3696 mono_domain_set_internal_with_options (domain, FALSE);
3699 return deserialized;
3702 /* Used in call_unhandled_exception_delegate */
3704 create_unhandled_exception_eventargs (MonoObject *exc)
3708 MonoMethod *method = NULL;
3709 MonoBoolean is_terminating = TRUE;
3712 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3715 mono_class_init (klass);
3717 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3718 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3722 args [1] = &is_terminating;
3724 obj = mono_object_new (mono_domain_get (), klass);
3725 mono_runtime_invoke (method, obj, args, NULL);
3730 /* Used in mono_unhandled_exception */
3732 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3733 MonoObject *e = NULL;
3735 MonoDomain *current_domain = mono_domain_get ();
3737 if (domain != current_domain)
3738 mono_domain_set_internal_with_options (domain, FALSE);
3740 g_assert (domain == mono_object_domain (domain->domain));
3742 if (mono_object_domain (exc) != domain) {
3743 MonoObject *serialization_exc;
3745 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3747 if (serialization_exc) {
3749 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3752 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3753 "System.Runtime.Serialization", "SerializationException",
3754 "Could not serialize unhandled exception.");
3758 g_assert (mono_object_domain (exc) == domain);
3760 pa [0] = domain->domain;
3761 pa [1] = create_unhandled_exception_eventargs (exc);
3762 mono_runtime_delegate_invoke (delegate, pa, &e);
3764 if (domain != current_domain)
3765 mono_domain_set_internal_with_options (current_domain, FALSE);
3769 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3770 if (!mono_error_ok (&error)) {
3771 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3772 mono_error_cleanup (&error);
3774 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3780 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3783 * mono_runtime_unhandled_exception_policy_set:
3784 * @policy: the new policy
3786 * This is a VM internal routine.
3788 * Sets the runtime policy for handling unhandled exceptions.
3791 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3792 runtime_unhandled_exception_policy = policy;
3796 * mono_runtime_unhandled_exception_policy_get:
3798 * This is a VM internal routine.
3800 * Gets the runtime policy for handling unhandled exceptions.
3802 MonoRuntimeUnhandledExceptionPolicy
3803 mono_runtime_unhandled_exception_policy_get (void) {
3804 return runtime_unhandled_exception_policy;
3808 * mono_unhandled_exception:
3809 * @exc: exception thrown
3811 * This is a VM internal routine.
3813 * We call this function when we detect an unhandled exception
3814 * in the default domain.
3816 * It invokes the * UnhandledException event in AppDomain or prints
3817 * a warning to the console
3820 mono_unhandled_exception (MonoObject *exc)
3822 MonoDomain *current_domain = mono_domain_get ();
3823 MonoDomain *root_domain = mono_get_root_domain ();
3824 MonoClassField *field;
3825 MonoObject *current_appdomain_delegate;
3826 MonoObject *root_appdomain_delegate;
3828 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3829 "UnhandledException");
3832 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3833 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3834 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3835 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3836 if (current_domain != root_domain) {
3837 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3839 current_appdomain_delegate = NULL;
3842 /* set exitcode only if we will abort the process */
3844 mono_environment_exitcode_set (1);
3845 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3846 mono_print_unhandled_exception (exc);
3848 if (root_appdomain_delegate) {
3849 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3851 if (current_appdomain_delegate) {
3852 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3859 * mono_runtime_exec_managed_code:
3860 * @domain: Application domain
3861 * @main_func: function to invoke from the execution thread
3862 * @main_args: parameter to the main_func
3864 * Launch a new thread to execute a function
3866 * main_func is called back from the thread with main_args as the
3867 * parameter. The callback function is expected to start Main()
3868 * eventually. This function then waits for all managed threads to
3870 * It is not necesseray anymore to execute managed code in a subthread,
3871 * so this function should not be used anymore by default: just
3872 * execute the code and then call mono_thread_manage ().
3875 mono_runtime_exec_managed_code (MonoDomain *domain,
3876 MonoMainThreadFunc main_func,
3879 mono_thread_create (domain, main_func, main_args);
3881 mono_thread_manage ();
3885 * Execute a standard Main() method (args doesn't contain the
3889 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3894 MonoCustomAttrInfo* cinfo;
3895 gboolean has_stathread_attribute;
3896 MonoInternalThread* thread = mono_thread_internal_current ();
3902 domain = mono_object_domain (args);
3903 if (!domain->entry_assembly) {
3905 MonoAssembly *assembly;
3907 assembly = method->klass->image->assembly;
3908 domain->entry_assembly = assembly;
3909 /* Domains created from another domain already have application_base and configuration_file set */
3910 if (domain->setup->application_base == NULL) {
3911 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3914 if (domain->setup->configuration_file == NULL) {
3915 str = g_strconcat (assembly->image->name, ".config", NULL);
3916 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3918 mono_set_private_bin_path_from_config (domain);
3922 cinfo = mono_custom_attrs_from_method (method);
3924 static MonoClass *stathread_attribute = NULL;
3925 if (!stathread_attribute)
3926 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3927 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3929 mono_custom_attrs_free (cinfo);
3931 has_stathread_attribute = FALSE;
3933 if (has_stathread_attribute) {
3934 thread->apartment_state = ThreadApartmentState_STA;
3936 thread->apartment_state = ThreadApartmentState_MTA;
3938 mono_thread_init_apartment_state ();
3940 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3942 /* FIXME: check signature of method */
3943 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3945 res = mono_runtime_invoke (method, NULL, pa, exc);
3947 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3951 mono_environment_exitcode_set (rval);
3953 mono_runtime_invoke (method, NULL, pa, exc);
3957 /* If the return type of Main is void, only
3958 * set the exitcode if an exception was thrown
3959 * (we don't want to blow away an
3960 * explicitly-set exit code)
3963 mono_environment_exitcode_set (rval);
3967 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3973 * mono_install_runtime_invoke:
3974 * @func: Function to install
3976 * This is a VM internal routine
3979 mono_install_runtime_invoke (MonoInvokeFunc func)
3981 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3986 * mono_runtime_invoke_array:
3987 * @method: method to invoke
3988 * @obJ: object instance
3989 * @params: arguments to the method
3990 * @exc: exception information.
3992 * Invokes the method represented by @method on the object @obj.
3994 * obj is the 'this' pointer, it should be NULL for static
3995 * methods, a MonoObject* for object instances and a pointer to
3996 * the value type for value types.
3998 * The params array contains the arguments to the method with the
3999 * same convention: MonoObject* pointers for object instances and
4000 * pointers to the value type otherwise. The _invoke_array
4001 * variant takes a C# object[] as the params argument (MonoArray
4002 * *params): in this case the value types are boxed inside the
4003 * respective reference representation.
4005 * From unmanaged code you'll usually use the
4006 * mono_runtime_invoke() variant.
4008 * Note that this function doesn't handle virtual methods for
4009 * you, it will exec the exact method you pass: we still need to
4010 * expose a function to lookup the derived class implementation
4011 * of a virtual method (there are examples of this in the code,
4014 * You can pass NULL as the exc argument if you don't want to
4015 * catch exceptions, otherwise, *exc will be set to the exception
4016 * thrown, if any. if an exception is thrown, you can't use the
4017 * MonoObject* result from the function.
4019 * If the method returns a value type, it is boxed in an object
4023 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4026 MonoMethodSignature *sig = mono_method_signature (method);
4027 gpointer *pa = NULL;
4030 gboolean has_byref_nullables = FALSE;
4032 if (NULL != params) {
4033 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4034 for (i = 0; i < mono_array_length (params); i++) {
4035 MonoType *t = sig->params [i];
4041 case MONO_TYPE_BOOLEAN:
4044 case MONO_TYPE_CHAR:
4053 case MONO_TYPE_VALUETYPE:
4054 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4055 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4056 pa [i] = mono_array_get (params, MonoObject*, i);
4058 has_byref_nullables = TRUE;
4060 /* MS seems to create the objects if a null is passed in */
4061 if (!mono_array_get (params, MonoObject*, i))
4062 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4066 * We can't pass the unboxed vtype byref to the callee, since
4067 * that would mean the callee would be able to modify boxed
4068 * primitive types. So we (and MS) make a copy of the boxed
4069 * object, pass that to the callee, and replace the original
4070 * boxed object in the arg array with the copy.
4072 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4073 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4074 mono_array_setref (params, i, copy);
4077 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4080 case MONO_TYPE_STRING:
4081 case MONO_TYPE_OBJECT:
4082 case MONO_TYPE_CLASS:
4083 case MONO_TYPE_ARRAY:
4084 case MONO_TYPE_SZARRAY:
4086 pa [i] = mono_array_addr (params, MonoObject*, i);
4087 // FIXME: I need to check this code path
4089 pa [i] = mono_array_get (params, MonoObject*, i);
4091 case MONO_TYPE_GENERICINST:
4093 t = &t->data.generic_class->container_class->this_arg;
4095 t = &t->data.generic_class->container_class->byval_arg;
4097 case MONO_TYPE_PTR: {
4100 /* The argument should be an IntPtr */
4101 arg = mono_array_get (params, MonoObject*, i);
4105 g_assert (arg->vtable->klass == mono_defaults.int_class);
4106 pa [i] = ((MonoIntPtr*)arg)->m_value;
4111 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4116 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4119 if (mono_class_is_nullable (method->klass)) {
4120 /* Need to create a boxed vtype instead */
4126 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4130 obj = mono_object_new (mono_domain_get (), method->klass);
4131 g_assert (obj); /*maybe we should raise a TLE instead?*/
4132 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4133 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4135 if (method->klass->valuetype)
4136 o = mono_object_unbox (obj);
4139 } else if (method->klass->valuetype) {
4140 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4143 mono_runtime_invoke (method, o, pa, exc);
4146 if (mono_class_is_nullable (method->klass)) {
4147 MonoObject *nullable;
4149 /* Convert the unboxed vtype into a Nullable structure */
4150 nullable = mono_object_new (mono_domain_get (), method->klass);
4152 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4153 obj = mono_object_unbox (nullable);
4156 /* obj must be already unboxed if needed */
4157 res = mono_runtime_invoke (method, obj, pa, exc);
4159 if (sig->ret->type == MONO_TYPE_PTR) {
4160 MonoClass *pointer_class;
4161 static MonoMethod *box_method;
4163 MonoObject *box_exc;
4166 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4167 * convert it to a Pointer object.
4169 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4171 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4173 g_assert (res->vtable->klass == mono_defaults.int_class);
4174 box_args [0] = ((MonoIntPtr*)res)->m_value;
4175 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4176 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4177 g_assert (!box_exc);
4180 if (has_byref_nullables) {
4182 * The runtime invoke wrapper already converted byref nullables back,
4183 * and stored them in pa, we just need to copy them back to the
4186 for (i = 0; i < mono_array_length (params); i++) {
4187 MonoType *t = sig->params [i];
4189 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4190 mono_array_setref (params, i, pa [i]);
4199 arith_overflow (void)
4201 mono_raise_exception (mono_get_exception_overflow ());
4205 * mono_object_allocate:
4206 * @size: number of bytes to allocate
4208 * This is a very simplistic routine until we have our GC-aware
4211 * Returns: an allocated object of size @size, or NULL on failure.
4213 static inline void *
4214 mono_object_allocate (size_t size, MonoVTable *vtable)
4217 mono_stats.new_object_count++;
4218 ALLOC_OBJECT (o, vtable, size);
4224 * mono_object_allocate_ptrfree:
4225 * @size: number of bytes to allocate
4227 * Note that the memory allocated is not zeroed.
4228 * Returns: an allocated object of size @size, or NULL on failure.
4230 static inline void *
4231 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4234 mono_stats.new_object_count++;
4235 ALLOC_PTRFREE (o, vtable, size);
4239 static inline void *
4240 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4243 ALLOC_TYPED (o, size, vtable);
4244 mono_stats.new_object_count++;
4251 * @klass: the class of the object that we want to create
4253 * Returns: a newly created object whose definition is
4254 * looked up using @klass. This will not invoke any constructors,
4255 * so the consumer of this routine has to invoke any constructors on
4256 * its own to initialize the object.
4258 * It returns NULL on failure.
4261 mono_object_new (MonoDomain *domain, MonoClass *klass)
4265 MONO_ARCH_SAVE_REGS;
4266 vtable = mono_class_vtable (domain, klass);
4269 return mono_object_new_specific (vtable);
4273 * mono_object_new_pinned:
4275 * Same as mono_object_new, but the returned object will be pinned.
4276 * For SGEN, these objects will only be freed at appdomain unload.
4279 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4283 MONO_ARCH_SAVE_REGS;
4284 vtable = mono_class_vtable (domain, klass);
4289 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4291 return mono_object_new_specific (vtable);
4296 * mono_object_new_specific:
4297 * @vtable: the vtable of the object that we want to create
4299 * Returns: A newly created object with class and domain specified
4303 mono_object_new_specific (MonoVTable *vtable)
4307 MONO_ARCH_SAVE_REGS;
4309 /* check for is_com_object for COM Interop */
4310 if (vtable->remote || vtable->klass->is_com_object)
4313 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4316 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4319 mono_class_init (klass);
4321 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4323 vtable->domain->create_proxy_for_type_method = im;
4326 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4328 o = mono_runtime_invoke (im, NULL, pa, NULL);
4329 if (o != NULL) return o;
4332 return mono_object_new_alloc_specific (vtable);
4336 mono_object_new_alloc_specific (MonoVTable *vtable)
4340 if (!vtable->klass->has_references) {
4341 o = mono_object_new_ptrfree (vtable);
4342 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4343 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4345 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4346 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4348 if (G_UNLIKELY (vtable->klass->has_finalize))
4349 mono_object_register_finalizer (o);
4351 if (G_UNLIKELY (profile_allocs))
4352 mono_profiler_allocation (o, vtable->klass);
4357 mono_object_new_fast (MonoVTable *vtable)
4360 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4365 mono_object_new_ptrfree (MonoVTable *vtable)
4368 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4369 #if NEED_TO_ZERO_PTRFREE
4370 /* an inline memset is much faster for the common vcase of small objects
4371 * note we assume the allocated size is a multiple of sizeof (void*).
4373 if (vtable->klass->instance_size < 128) {
4375 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4376 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4382 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4389 mono_object_new_ptrfree_box (MonoVTable *vtable)
4392 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4393 /* the object will be boxed right away, no need to memzero it */
4398 * mono_class_get_allocation_ftn:
4400 * @for_box: the object will be used for boxing
4401 * @pass_size_in_words:
4403 * Return the allocation function appropriate for the given class.
4407 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4409 *pass_size_in_words = FALSE;
4411 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4412 profile_allocs = FALSE;
4414 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4415 return mono_object_new_specific;
4417 if (!vtable->klass->has_references) {
4418 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4420 return mono_object_new_ptrfree_box;
4421 return mono_object_new_ptrfree;
4424 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4426 return mono_object_new_fast;
4429 * FIXME: This is actually slower than mono_object_new_fast, because
4430 * of the overhead of parameter passing.
4433 *pass_size_in_words = TRUE;
4434 #ifdef GC_REDIRECT_TO_LOCAL
4435 return GC_local_gcj_fast_malloc;
4437 return GC_gcj_fast_malloc;
4442 return mono_object_new_specific;
4446 * mono_object_new_from_token:
4447 * @image: Context where the type_token is hosted
4448 * @token: a token of the type that we want to create
4450 * Returns: A newly created object whose definition is
4451 * looked up using @token in the @image image
4454 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4458 class = mono_class_get (image, token);
4460 return mono_object_new (domain, class);
4465 * mono_object_clone:
4466 * @obj: the object to clone
4468 * Returns: A newly created object who is a shallow copy of @obj
4471 mono_object_clone (MonoObject *obj)
4474 int size = obj->vtable->klass->instance_size;
4476 o = mono_object_allocate (size, obj->vtable);
4478 if (obj->vtable->klass->has_references) {
4479 mono_gc_wbarrier_object_copy (o, obj);
4481 int size = obj->vtable->klass->instance_size;
4482 /* do not copy the sync state */
4483 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4485 if (G_UNLIKELY (profile_allocs))
4486 mono_profiler_allocation (o, obj->vtable->klass);
4488 if (obj->vtable->klass->has_finalize)
4489 mono_object_register_finalizer (o);
4494 * mono_array_full_copy:
4495 * @src: source array to copy
4496 * @dest: destination array
4498 * Copies the content of one array to another with exactly the same type and size.
4501 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4504 MonoClass *klass = src->obj.vtable->klass;
4506 MONO_ARCH_SAVE_REGS;
4508 g_assert (klass == dest->obj.vtable->klass);
4510 size = mono_array_length (src);
4511 g_assert (size == mono_array_length (dest));
4512 size *= mono_array_element_size (klass);
4514 if (klass->element_class->valuetype) {
4515 if (klass->element_class->has_references)
4516 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4518 memcpy (&dest->vector, &src->vector, size);
4520 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4523 memcpy (&dest->vector, &src->vector, size);
4528 * mono_array_clone_in_domain:
4529 * @domain: the domain in which the array will be cloned into
4530 * @array: the array to clone
4532 * This routine returns a copy of the array that is hosted on the
4533 * specified MonoDomain.
4536 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4541 MonoClass *klass = array->obj.vtable->klass;
4543 MONO_ARCH_SAVE_REGS;
4545 if (array->bounds == NULL) {
4546 size = mono_array_length (array);
4547 o = mono_array_new_full (domain, klass, &size, NULL);
4549 size *= mono_array_element_size (klass);
4551 if (klass->element_class->valuetype) {
4552 if (klass->element_class->has_references)
4553 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4555 memcpy (&o->vector, &array->vector, size);
4557 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4560 memcpy (&o->vector, &array->vector, size);
4565 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4566 size = mono_array_element_size (klass);
4567 for (i = 0; i < klass->rank; ++i) {
4568 sizes [i] = array->bounds [i].length;
4569 size *= array->bounds [i].length;
4570 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4572 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4574 if (klass->element_class->valuetype) {
4575 if (klass->element_class->has_references)
4576 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4578 memcpy (&o->vector, &array->vector, size);
4580 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4583 memcpy (&o->vector, &array->vector, size);
4591 * @array: the array to clone
4593 * Returns: A newly created array who is a shallow copy of @array
4596 mono_array_clone (MonoArray *array)
4598 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4601 /* helper macros to check for overflow when calculating the size of arrays */
4602 #ifdef MONO_BIG_ARRAYS
4603 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4604 #define MYGUINT_MAX MYGUINT64_MAX
4605 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4606 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4607 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4608 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4609 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4611 #define MYGUINT32_MAX 4294967295U
4612 #define MYGUINT_MAX MYGUINT32_MAX
4613 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4614 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4615 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4616 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4617 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4621 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4625 byte_len = mono_array_element_size (class);
4626 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4629 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4631 byte_len += sizeof (MonoArray);
4639 * mono_array_new_full:
4640 * @domain: domain where the object is created
4641 * @array_class: array class
4642 * @lengths: lengths for each dimension in the array
4643 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4645 * This routine creates a new array objects with the given dimensions,
4646 * lower bounds and type.
4649 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4651 uintptr_t byte_len, len, bounds_size;
4654 MonoArrayBounds *bounds;
4658 if (!array_class->inited)
4659 mono_class_init (array_class);
4663 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4664 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4666 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4670 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4672 for (i = 0; i < array_class->rank; ++i) {
4673 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4675 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4676 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4681 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4682 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4686 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4687 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4688 byte_len = (byte_len + 3) & ~3;
4689 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4690 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4691 byte_len += bounds_size;
4694 * Following three lines almost taken from mono_object_new ():
4695 * they need to be kept in sync.
4697 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4698 #ifndef HAVE_SGEN_GC
4699 if (!array_class->has_references) {
4700 o = mono_object_allocate_ptrfree (byte_len, vtable);
4701 #if NEED_TO_ZERO_PTRFREE
4702 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4704 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4705 o = mono_object_allocate_spec (byte_len, vtable);
4707 o = mono_object_allocate (byte_len, vtable);
4710 array = (MonoArray*)o;
4711 array->max_length = len;
4714 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4715 array->bounds = bounds;
4719 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4721 o = mono_gc_alloc_vector (vtable, byte_len, len);
4722 array = (MonoArray*)o;
4723 mono_stats.new_object_count++;
4725 bounds = array->bounds;
4729 for (i = 0; i < array_class->rank; ++i) {
4730 bounds [i].length = lengths [i];
4732 bounds [i].lower_bound = lower_bounds [i];
4736 if (G_UNLIKELY (profile_allocs))
4737 mono_profiler_allocation (o, array_class);
4744 * @domain: domain where the object is created
4745 * @eclass: element class
4746 * @n: number of array elements
4748 * This routine creates a new szarray with @n elements of type @eclass.
4751 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4755 MONO_ARCH_SAVE_REGS;
4757 ac = mono_array_class_get (eclass, 1);
4760 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4764 * mono_array_new_specific:
4765 * @vtable: a vtable in the appropriate domain for an initialized class
4766 * @n: number of array elements
4768 * This routine is a fast alternative to mono_array_new() for code which
4769 * can be sure about the domain it operates in.
4772 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4778 MONO_ARCH_SAVE_REGS;
4780 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4785 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4786 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4789 #ifndef HAVE_SGEN_GC
4790 if (!vtable->klass->has_references) {
4791 o = mono_object_allocate_ptrfree (byte_len, vtable);
4792 #if NEED_TO_ZERO_PTRFREE
4793 ((MonoArray*)o)->bounds = NULL;
4794 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4796 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4797 o = mono_object_allocate_spec (byte_len, vtable);
4799 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4800 o = mono_object_allocate (byte_len, vtable);
4803 ao = (MonoArray *)o;
4806 o = mono_gc_alloc_vector (vtable, byte_len, n);
4808 mono_stats.new_object_count++;
4811 if (G_UNLIKELY (profile_allocs))
4812 mono_profiler_allocation (o, vtable->klass);
4818 * mono_string_new_utf16:
4819 * @text: a pointer to an utf16 string
4820 * @len: the length of the string
4822 * Returns: A newly created string object which contains @text.
4825 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4829 s = mono_string_new_size (domain, len);
4830 g_assert (s != NULL);
4832 memcpy (mono_string_chars (s), text, len * 2);
4838 * mono_string_new_size:
4839 * @text: a pointer to an utf16 string
4840 * @len: the length of the string
4842 * Returns: A newly created string object of @len
4845 mono_string_new_size (MonoDomain *domain, gint32 len)
4849 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4851 /* overflow ? can't fit it, can't allocate it! */
4853 mono_gc_out_of_memory (-1);
4855 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4858 #ifndef HAVE_SGEN_GC
4859 s = mono_object_allocate_ptrfree (size, vtable);
4863 s = mono_gc_alloc_string (vtable, size, len);
4865 #if NEED_TO_ZERO_PTRFREE
4868 if (G_UNLIKELY (profile_allocs))
4869 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4875 * mono_string_new_len:
4876 * @text: a pointer to an utf8 string
4877 * @length: number of bytes in @text to consider
4879 * Returns: A newly created string object which contains @text.
4882 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4884 GError *error = NULL;
4885 MonoString *o = NULL;
4887 glong items_written;
4889 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4892 o = mono_string_new_utf16 (domain, ut, items_written);
4894 g_error_free (error);
4903 * @text: a pointer to an utf8 string
4905 * Returns: A newly created string object which contains @text.
4908 mono_string_new (MonoDomain *domain, const char *text)
4910 GError *error = NULL;
4911 MonoString *o = NULL;
4913 glong items_written;
4918 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4921 o = mono_string_new_utf16 (domain, ut, items_written);
4923 g_error_free (error);
4926 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4931 MonoString *o = NULL;
4933 if (!g_utf8_validate (text, -1, &end))
4936 len = g_utf8_strlen (text, -1);
4937 o = mono_string_new_size (domain, len);
4938 str = mono_string_chars (o);
4940 while (text < end) {
4941 *str++ = g_utf8_get_char (text);
4942 text = g_utf8_next_char (text);
4949 * mono_string_new_wrapper:
4950 * @text: pointer to utf8 characters.
4952 * Helper function to create a string object from @text in the current domain.
4955 mono_string_new_wrapper (const char *text)
4957 MonoDomain *domain = mono_domain_get ();
4959 MONO_ARCH_SAVE_REGS;
4962 return mono_string_new (domain, text);
4969 * @class: the class of the value
4970 * @value: a pointer to the unboxed data
4972 * Returns: A newly created object which contains @value.
4975 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4981 g_assert (class->valuetype);
4982 if (mono_class_is_nullable (class))
4983 return mono_nullable_box (value, class);
4985 vtable = mono_class_vtable (domain, class);
4988 size = mono_class_instance_size (class);
4989 res = mono_object_new_alloc_specific (vtable);
4990 if (G_UNLIKELY (profile_allocs))
4991 mono_profiler_allocation (res, class);
4993 size = size - sizeof (MonoObject);
4996 g_assert (size == mono_class_value_size (class, NULL));
4997 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4999 #if NO_UNALIGNED_ACCESS
5000 memcpy ((char *)res + sizeof (MonoObject), value, size);
5004 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5007 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5010 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5013 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5016 memcpy ((char *)res + sizeof (MonoObject), value, size);
5020 if (class->has_finalize)
5021 mono_object_register_finalizer (res);
5027 * @dest: destination pointer
5028 * @src: source pointer
5029 * @klass: a valuetype class
5031 * Copy a valuetype from @src to @dest. This function must be used
5032 * when @klass contains references fields.
5035 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5037 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5041 * mono_value_copy_array:
5042 * @dest: destination array
5043 * @dest_idx: index in the @dest array
5044 * @src: source pointer
5045 * @count: number of items
5047 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5048 * This function must be used when @klass contains references fields.
5049 * Overlap is handled.
5052 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5054 int size = mono_array_element_size (dest->obj.vtable->klass);
5055 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5056 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5057 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5061 * mono_object_get_domain:
5062 * @obj: object to query
5064 * Returns: the MonoDomain where the object is hosted
5067 mono_object_get_domain (MonoObject *obj)
5069 return mono_object_domain (obj);
5073 * mono_object_get_class:
5074 * @obj: object to query
5076 * Returns: the MonOClass of the object.
5079 mono_object_get_class (MonoObject *obj)
5081 return mono_object_class (obj);
5084 * mono_object_get_size:
5085 * @o: object to query
5087 * Returns: the size, in bytes, of @o
5090 mono_object_get_size (MonoObject* o)
5092 MonoClass* klass = mono_object_class (o);
5093 if (klass == mono_defaults.string_class) {
5094 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5095 } else if (o->vtable->rank) {
5096 MonoArray *array = (MonoArray*)o;
5097 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5098 if (array->bounds) {
5101 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5105 return mono_class_instance_size (klass);
5110 * mono_object_unbox:
5111 * @obj: object to unbox
5113 * Returns: a pointer to the start of the valuetype boxed in this
5116 * This method will assert if the object passed is not a valuetype.
5119 mono_object_unbox (MonoObject *obj)
5121 /* add assert for valuetypes? */
5122 g_assert (obj->vtable->klass->valuetype);
5123 return ((char*)obj) + sizeof (MonoObject);
5127 * mono_object_isinst:
5129 * @klass: a pointer to a class
5131 * Returns: @obj if @obj is derived from @klass
5134 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5137 mono_class_init (klass);
5139 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5140 return mono_object_isinst_mbyref (obj, klass);
5145 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5149 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5158 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5159 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5163 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5164 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5167 MonoClass *oklass = vt->klass;
5168 if ((oklass == mono_defaults.transparent_proxy_class))
5169 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5171 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5175 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5177 MonoDomain *domain = mono_domain_get ();
5179 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5180 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5181 MonoMethod *im = NULL;
5184 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5185 im = mono_object_get_virtual_method (rp, im);
5188 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5191 res = mono_runtime_invoke (im, rp, pa, NULL);
5193 if (*(MonoBoolean *) mono_object_unbox(res)) {
5194 /* Update the vtable of the remote type, so it can safely cast to this new type */
5195 mono_upgrade_remote_class (domain, obj, klass);
5204 * mono_object_castclass_mbyref:
5206 * @klass: a pointer to a class
5208 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5211 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5213 if (!obj) return NULL;
5214 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5216 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5218 "InvalidCastException"));
5223 MonoDomain *orig_domain;
5229 str_lookup (MonoDomain *domain, gpointer user_data)
5231 LDStrInfo *info = user_data;
5232 if (info->res || domain == info->orig_domain)
5234 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5240 mono_string_get_pinned (MonoString *str)
5244 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5245 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5247 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5248 news->length = mono_string_length (str);
5254 #define mono_string_get_pinned(str) (str)
5258 mono_string_is_interned_lookup (MonoString *str, int insert)
5260 MonoGHashTable *ldstr_table;
5264 domain = ((MonoObject *)str)->vtable->domain;
5265 ldstr_table = domain->ldstr_table;
5267 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5272 str = mono_string_get_pinned (str);
5274 mono_g_hash_table_insert (ldstr_table, str, str);
5278 LDStrInfo ldstr_info;
5279 ldstr_info.orig_domain = domain;
5280 ldstr_info.ins = str;
5281 ldstr_info.res = NULL;
5283 mono_domain_foreach (str_lookup, &ldstr_info);
5284 if (ldstr_info.res) {
5286 * the string was already interned in some other domain:
5287 * intern it in the current one as well.
5289 mono_g_hash_table_insert (ldstr_table, str, str);
5299 * mono_string_is_interned:
5300 * @o: String to probe
5302 * Returns whether the string has been interned.
5305 mono_string_is_interned (MonoString *o)
5307 return mono_string_is_interned_lookup (o, FALSE);
5311 * mono_string_intern:
5312 * @o: String to intern
5314 * Interns the string passed.
5315 * Returns: The interned string.
5318 mono_string_intern (MonoString *str)
5320 return mono_string_is_interned_lookup (str, TRUE);
5325 * @domain: the domain where the string will be used.
5326 * @image: a metadata context
5327 * @idx: index into the user string table.
5329 * Implementation for the ldstr opcode.
5330 * Returns: a loaded string from the @image/@idx combination.
5333 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5335 MONO_ARCH_SAVE_REGS;
5337 if (image->dynamic) {
5338 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5341 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5342 return NULL; /*FIXME we should probably be raising an exception here*/
5343 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5348 * mono_ldstr_metadata_sig
5349 * @domain: the domain for the string
5350 * @sig: the signature of a metadata string
5352 * Returns: a MonoString for a string stored in the metadata
5355 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5357 const char *str = sig;
5358 MonoString *o, *interned;
5361 len2 = mono_metadata_decode_blob_size (str, &str);
5364 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5365 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5368 guint16 *p2 = (guint16*)mono_string_chars (o);
5369 for (i = 0; i < len2; ++i) {
5370 *p2 = GUINT16_FROM_LE (*p2);
5376 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5378 /* o will get garbage collected */
5382 o = mono_string_get_pinned (o);
5384 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5391 * mono_string_to_utf8:
5392 * @s: a System.String
5394 * Returns the UTF8 representation for @s.
5395 * The resulting buffer needs to be freed with mono_free().
5397 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5400 mono_string_to_utf8 (MonoString *s)
5403 char *result = mono_string_to_utf8_checked (s, &error);
5405 if (!mono_error_ok (&error))
5406 mono_error_raise_exception (&error);
5411 * mono_string_to_utf8_checked:
5412 * @s: a System.String
5413 * @error: a MonoError.
5415 * Converts a MonoString to its UTF8 representation. May fail; check
5416 * @error to determine whether the conversion was successful.
5417 * The resulting buffer should be freed with mono_free().
5420 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5424 GError *gerror = NULL;
5426 mono_error_init (error);
5432 return g_strdup ("");
5434 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5436 mono_error_set_argument (error, "string", "%s", gerror->message);
5437 g_error_free (gerror);
5440 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5441 if (s->length > written) {
5442 /* allocate the total length and copy the part of the string that has been converted */
5443 char *as2 = g_malloc0 (s->length);
5444 memcpy (as2, as, written);
5453 * mono_string_to_utf8_ignore:
5456 * Converts a MonoString to its UTF8 representation. Will ignore
5457 * invalid surrogate pairs.
5458 * The resulting buffer should be freed with mono_free().
5462 mono_string_to_utf8_ignore (MonoString *s)
5471 return g_strdup ("");
5473 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5475 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5476 if (s->length > written) {
5477 /* allocate the total length and copy the part of the string that has been converted */
5478 char *as2 = g_malloc0 (s->length);
5479 memcpy (as2, as, written);
5488 * mono_string_to_utf8_image_ignore:
5489 * @s: a System.String
5491 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5494 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5496 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5500 * mono_string_to_utf8_mp_ignore:
5501 * @s: a System.String
5503 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5506 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5508 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5513 * mono_string_to_utf16:
5516 * Return an null-terminated array of the utf-16 chars
5517 * contained in @s. The result must be freed with g_free().
5518 * This is a temporary helper until our string implementation
5519 * is reworked to always include the null terminating char.
5522 mono_string_to_utf16 (MonoString *s)
5529 as = g_malloc ((s->length * 2) + 2);
5530 as [(s->length * 2)] = '\0';
5531 as [(s->length * 2) + 1] = '\0';
5534 return (gunichar2 *)(as);
5537 memcpy (as, mono_string_chars(s), s->length * 2);
5538 return (gunichar2 *)(as);
5542 * mono_string_from_utf16:
5543 * @data: the UTF16 string (LPWSTR) to convert
5545 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5547 * Returns: a MonoString.
5550 mono_string_from_utf16 (gunichar2 *data)
5552 MonoDomain *domain = mono_domain_get ();
5558 while (data [len]) len++;
5560 return mono_string_new_utf16 (domain, data, len);
5565 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5572 r = mono_string_to_utf8_ignore (s);
5574 r = mono_string_to_utf8_checked (s, error);
5575 if (!mono_error_ok (error))
5582 len = strlen (r) + 1;
5584 mp_s = mono_mempool_alloc (mp, len);
5586 mp_s = mono_image_alloc (image, len);
5588 memcpy (mp_s, r, len);
5596 * mono_string_to_utf8_image:
5597 * @s: a System.String
5599 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5602 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5604 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5608 * mono_string_to_utf8_mp:
5609 * @s: a System.String
5611 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5614 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5616 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5620 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5623 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5625 eh_callbacks = *cbs;
5628 MonoRuntimeExceptionHandlingCallbacks *
5629 mono_get_eh_callbacks (void)
5631 return &eh_callbacks;
5635 * mono_raise_exception:
5636 * @ex: exception object
5638 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5641 mono_raise_exception (MonoException *ex)
5644 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5645 * that will cause gcc to omit the function epilog, causing problems when
5646 * the JIT tries to walk the stack, since the return address on the stack
5647 * will point into the next function in the executable, not this one.
5650 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5651 MonoInternalThread *thread = mono_thread_internal_current ();
5652 g_assert (ex->object.vtable->domain == mono_domain_get ());
5653 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5656 eh_callbacks.mono_raise_exception (ex);
5660 * mono_wait_handle_new:
5661 * @domain: Domain where the object will be created
5662 * @handle: Handle for the wait handle
5664 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5667 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5669 MonoWaitHandle *res;
5670 gpointer params [1];
5671 static MonoMethod *handle_set;
5673 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5675 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5677 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5679 params [0] = &handle;
5680 mono_runtime_invoke (handle_set, res, params, NULL);
5686 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5688 static MonoClassField *f_os_handle;
5689 static MonoClassField *f_safe_handle;
5691 if (!f_os_handle && !f_safe_handle) {
5692 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5693 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5698 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5702 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5709 mono_runtime_capture_context (MonoDomain *domain)
5711 RuntimeInvokeFunction runtime_invoke;
5713 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5714 MonoMethod *method = mono_get_context_capture_method ();
5715 MonoMethod *wrapper;
5718 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5719 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5720 domain->capture_context_method = mono_compile_method (method);
5723 runtime_invoke = domain->capture_context_runtime_invoke;
5725 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5728 * mono_async_result_new:
5729 * @domain:domain where the object will be created.
5730 * @handle: wait handle.
5731 * @state: state to pass to AsyncResult
5732 * @data: C closure data.
5734 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5735 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5739 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5741 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5742 MonoObject *context = mono_runtime_capture_context (domain);
5743 /* we must capture the execution context from the original thread */
5745 MONO_OBJECT_SETREF (res, execution_context, context);
5746 /* note: result may be null if the flow is suppressed */
5750 MONO_OBJECT_SETREF (res, object_data, object_data);
5751 MONO_OBJECT_SETREF (res, async_state, state);
5753 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5755 res->sync_completed = FALSE;
5756 res->completed = FALSE;
5762 mono_message_init (MonoDomain *domain,
5763 MonoMethodMessage *this,
5764 MonoReflectionMethod *method,
5765 MonoArray *out_args)
5767 static MonoClass *object_array_klass;
5768 static MonoClass *byte_array_klass;
5769 static MonoClass *string_array_klass;
5770 MonoMethodSignature *sig = mono_method_signature (method->method);
5776 if (!object_array_klass) {
5779 klass = mono_array_class_get (mono_defaults.object_class, 1);
5782 mono_memory_barrier ();
5783 object_array_klass = klass;
5785 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5788 mono_memory_barrier ();
5789 byte_array_klass = klass;
5791 klass = mono_array_class_get (mono_defaults.string_class, 1);
5794 mono_memory_barrier ();
5795 string_array_klass = klass;
5798 MONO_OBJECT_SETREF (this, method, method);
5800 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5801 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5802 this->async_result = NULL;
5803 this->call_type = CallType_Sync;
5805 names = g_new (char *, sig->param_count);
5806 mono_method_get_param_names (method->method, (const char **) names);
5807 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5809 for (i = 0; i < sig->param_count; i++) {
5810 name = mono_string_new (domain, names [i]);
5811 mono_array_setref (this->names, i, name);
5815 for (i = 0, j = 0; i < sig->param_count; i++) {
5816 if (sig->params [i]->byref) {
5818 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5819 mono_array_setref (this->args, i, arg);
5823 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5827 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5830 mono_array_set (this->arg_types, guint8, i, arg_type);
5835 * mono_remoting_invoke:
5836 * @real_proxy: pointer to a RealProxy object
5837 * @msg: The MonoMethodMessage to execute
5838 * @exc: used to store exceptions
5839 * @out_args: used to store output arguments
5841 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5842 * IMessage interface and it is not trivial to extract results from there. So
5843 * we call an helper method PrivateInvoke instead of calling
5844 * RealProxy::Invoke() directly.
5846 * Returns: the result object.
5849 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5850 MonoObject **exc, MonoArray **out_args)
5852 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5855 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5858 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5860 real_proxy->vtable->domain->private_invoke_method = im;
5863 pa [0] = real_proxy;
5868 return mono_runtime_invoke (im, NULL, pa, exc);
5872 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5873 MonoObject **exc, MonoArray **out_args)
5875 static MonoClass *object_array_klass;
5878 MonoMethodSignature *sig;
5880 int i, j, outarg_count = 0;
5882 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5884 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5885 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5886 target = tp->rp->unwrapped_server;
5888 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5892 domain = mono_domain_get ();
5893 method = msg->method->method;
5894 sig = mono_method_signature (method);
5896 for (i = 0; i < sig->param_count; i++) {
5897 if (sig->params [i]->byref)
5901 if (!object_array_klass) {
5904 klass = mono_array_class_get (mono_defaults.object_class, 1);
5907 mono_memory_barrier ();
5908 object_array_klass = klass;
5911 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5912 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5915 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5917 for (i = 0, j = 0; i < sig->param_count; i++) {
5918 if (sig->params [i]->byref) {
5920 arg = mono_array_get (msg->args, gpointer, i);
5921 mono_array_setref (*out_args, j, arg);
5930 * mono_object_to_string:
5932 * @exc: Any exception thrown by ToString (). May be NULL.
5934 * Returns: the result of calling ToString () on an object.
5937 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5939 static MonoMethod *to_string = NULL;
5945 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5947 method = mono_object_get_virtual_method (obj, to_string);
5949 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5953 * mono_print_unhandled_exception:
5954 * @exc: The exception
5956 * Prints the unhandled exception.
5959 mono_print_unhandled_exception (MonoObject *exc)
5962 char *message = (char*)"";
5963 gboolean free_message = FALSE;
5966 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5967 message = g_strdup ("OutOfMemoryException");
5969 str = mono_object_to_string (exc, NULL);
5971 message = mono_string_to_utf8_checked (str, &error);
5972 if (!mono_error_ok (&error)) {
5973 mono_error_cleanup (&error);
5974 message = (char *) "";
5976 free_message = TRUE;
5982 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5983 * exc->vtable->klass->name, message);
5985 g_printerr ("\nUnhandled Exception: %s\n", message);
5992 * mono_delegate_ctor:
5993 * @this: pointer to an uninitialized delegate object
5994 * @target: target object
5995 * @addr: pointer to native code
5998 * Initialize a delegate and sets a specific method, not the one
5999 * associated with addr. This is useful when sharing generic code.
6000 * In that case addr will most probably not be associated with the
6001 * correct instantiation of the method.
6004 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6006 MonoDelegate *delegate = (MonoDelegate *)this;
6013 delegate->method = method;
6015 class = this->vtable->klass;
6016 mono_stats.delegate_creations++;
6018 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6020 method = mono_marshal_get_remoting_invoke (method);
6021 delegate->method_ptr = mono_compile_method (method);
6022 MONO_OBJECT_SETREF (delegate, target, target);
6023 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6024 method = mono_marshal_get_unbox_wrapper (method);
6025 delegate->method_ptr = mono_compile_method (method);
6026 MONO_OBJECT_SETREF (delegate, target, target);
6028 delegate->method_ptr = addr;
6029 MONO_OBJECT_SETREF (delegate, target, target);
6032 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
6036 * mono_delegate_ctor:
6037 * @this: pointer to an uninitialized delegate object
6038 * @target: target object
6039 * @addr: pointer to native code
6041 * This is used to initialize a delegate.
6044 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6046 MonoDomain *domain = mono_domain_get ();
6048 MonoMethod *method = NULL;
6052 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
6053 method = ji->method;
6054 g_assert (!method->klass->generic_container);
6057 mono_delegate_ctor_with_method (this, target, addr, method);
6061 * mono_method_call_message_new:
6062 * @method: method to encapsulate
6063 * @params: parameters to the method
6064 * @invoke: optional, delegate invoke.
6065 * @cb: async callback delegate.
6066 * @state: state passed to the async callback.
6068 * Translates arguments pointers into a MonoMethodMessage.
6071 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6072 MonoDelegate **cb, MonoObject **state)
6074 MonoDomain *domain = mono_domain_get ();
6075 MonoMethodSignature *sig = mono_method_signature (method);
6076 MonoMethodMessage *msg;
6079 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6082 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6083 count = sig->param_count - 2;
6085 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6086 count = sig->param_count;
6089 for (i = 0; i < count; i++) {
6094 if (sig->params [i]->byref)
6095 vpos = *((gpointer *)params [i]);
6099 type = sig->params [i]->type;
6100 class = mono_class_from_mono_type (sig->params [i]);
6102 if (class->valuetype)
6103 arg = mono_value_box (domain, class, vpos);
6105 arg = *((MonoObject **)vpos);
6107 mono_array_setref (msg->args, i, arg);
6110 if (cb != NULL && state != NULL) {
6111 *cb = *((MonoDelegate **)params [i]);
6113 *state = *((MonoObject **)params [i]);
6120 * mono_method_return_message_restore:
6122 * Restore results from message based processing back to arguments pointers
6125 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6127 MonoMethodSignature *sig = mono_method_signature (method);
6128 int i, j, type, size, out_len;
6130 if (out_args == NULL)
6132 out_len = mono_array_length (out_args);
6136 for (i = 0, j = 0; i < sig->param_count; i++) {
6137 MonoType *pt = sig->params [i];
6142 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6144 arg = mono_array_get (out_args, gpointer, j);
6147 g_assert (type != MONO_TYPE_VOID);
6149 if (MONO_TYPE_IS_REFERENCE (pt)) {
6150 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6153 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6154 size = mono_class_value_size (class, NULL);
6155 if (class->has_references)
6156 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6158 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6160 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6161 memset (*((gpointer *)params [i]), 0, size);
6171 * mono_load_remote_field:
6172 * @this: pointer to an object
6173 * @klass: klass of the object containing @field
6174 * @field: the field to load
6175 * @res: a storage to store the result
6177 * This method is called by the runtime on attempts to load fields of
6178 * transparent proxy objects. @this points to such TP, @klass is the class of
6179 * the object containing @field. @res is a storage location which can be
6180 * used to store the result.
6182 * Returns: an address pointing to the value of field.
6185 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6187 static MonoMethod *getter = NULL;
6188 MonoDomain *domain = mono_domain_get ();
6189 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6190 MonoClass *field_class;
6191 MonoMethodMessage *msg;
6192 MonoArray *out_args;
6196 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6197 g_assert (res != NULL);
6199 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6200 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6205 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6209 field_class = mono_class_from_mono_type (field->type);
6211 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6212 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6213 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6215 full_name = mono_type_get_full_name (klass);
6216 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6217 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6220 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6222 if (exc) mono_raise_exception ((MonoException *)exc);
6224 if (mono_array_length (out_args) == 0)
6227 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6229 if (field_class->valuetype) {
6230 return ((char *)*res) + sizeof (MonoObject);
6236 * mono_load_remote_field_new:
6241 * Missing documentation.
6244 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6246 static MonoMethod *getter = NULL;
6247 MonoDomain *domain = mono_domain_get ();
6248 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6249 MonoClass *field_class;
6250 MonoMethodMessage *msg;
6251 MonoArray *out_args;
6252 MonoObject *exc, *res;
6255 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6257 field_class = mono_class_from_mono_type (field->type);
6259 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6261 if (field_class->valuetype) {
6262 res = mono_object_new (domain, field_class);
6263 val = ((gchar *) res) + sizeof (MonoObject);
6267 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6272 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6276 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6277 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6279 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6281 full_name = mono_type_get_full_name (klass);
6282 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6283 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6286 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6288 if (exc) mono_raise_exception ((MonoException *)exc);
6290 if (mono_array_length (out_args) == 0)
6293 res = mono_array_get (out_args, MonoObject *, 0);
6299 * mono_store_remote_field:
6300 * @this: pointer to an object
6301 * @klass: klass of the object containing @field
6302 * @field: the field to load
6303 * @val: the value/object to store
6305 * This method is called by the runtime on attempts to store fields of
6306 * transparent proxy objects. @this points to such TP, @klass is the class of
6307 * the object containing @field. @val is the new value to store in @field.
6310 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6312 static MonoMethod *setter = NULL;
6313 MonoDomain *domain = mono_domain_get ();
6314 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6315 MonoClass *field_class;
6316 MonoMethodMessage *msg;
6317 MonoArray *out_args;
6322 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6324 field_class = mono_class_from_mono_type (field->type);
6326 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6327 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6328 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6333 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6337 if (field_class->valuetype)
6338 arg = mono_value_box (domain, field_class, val);
6340 arg = *((MonoObject **)val);
6343 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6344 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6346 full_name = mono_type_get_full_name (klass);
6347 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6348 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6349 mono_array_setref (msg->args, 2, arg);
6352 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6354 if (exc) mono_raise_exception ((MonoException *)exc);
6358 * mono_store_remote_field_new:
6364 * Missing documentation
6367 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6369 static MonoMethod *setter = NULL;
6370 MonoDomain *domain = mono_domain_get ();
6371 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6372 MonoClass *field_class;
6373 MonoMethodMessage *msg;
6374 MonoArray *out_args;
6378 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6380 field_class = mono_class_from_mono_type (field->type);
6382 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6383 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6384 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6389 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6393 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6394 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6396 full_name = mono_type_get_full_name (klass);
6397 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6398 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6399 mono_array_setref (msg->args, 2, arg);
6402 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6404 if (exc) mono_raise_exception ((MonoException *)exc);
6408 * mono_create_ftnptr:
6410 * Given a function address, create a function descriptor for it.
6411 * This is only needed on some platforms.
6414 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6416 return callbacks.create_ftnptr (domain, addr);
6420 * mono_get_addr_from_ftnptr:
6422 * Given a pointer to a function descriptor, return the function address.
6423 * This is only needed on some platforms.
6426 mono_get_addr_from_ftnptr (gpointer descr)
6428 return callbacks.get_addr_from_ftnptr (descr);
6432 * mono_string_chars:
6435 * Returns a pointer to the UCS16 characters stored in the MonoString
6438 mono_string_chars (MonoString *s)
6444 * mono_string_length:
6447 * Returns the lenght in characters of the string
6450 mono_string_length (MonoString *s)
6456 * mono_array_length:
6457 * @array: a MonoArray*
6459 * Returns the total number of elements in the array. This works for
6460 * both vectors and multidimensional arrays.
6463 mono_array_length (MonoArray *array)
6465 return array->max_length;
6469 * mono_array_addr_with_size:
6470 * @array: a MonoArray*
6471 * @size: size of the array elements
6472 * @idx: index into the array
6474 * Returns the address of the @idx element in the array.
6477 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6479 return ((char*)(array)->vector) + size * idx;