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 if (!vtable->init_failed)
420 vtable->initialized = 1;
421 mono_type_initialization_unlock ();
423 if (vtable->init_failed) {
424 /* Either we were the initializing thread or we waited for the initialization */
426 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
427 return get_type_init_exception_for_vtable (vtable);
430 vtable->initialized = 1;
437 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
439 MonoVTable *vtable = (MonoVTable*)key;
441 TypeInitializationLock *lock = (TypeInitializationLock*) value;
442 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
445 * Have to set this since it cannot be set by the normal code in
446 * mono_runtime_class_init (). In this case, the exception object is not stored,
447 * and get_type_init_exception_for_class () needs to be aware of this.
449 vtable->init_failed = 1;
450 LeaveCriticalSection (&lock->initialization_section);
451 --lock->waiting_count;
452 if (lock->waiting_count == 0) {
453 DeleteCriticalSection (&lock->initialization_section);
462 mono_release_type_locks (MonoInternalThread *thread)
464 mono_type_initialization_lock ();
465 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
466 mono_type_initialization_unlock ();
470 default_trampoline (MonoMethod *method)
476 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
478 g_assert_not_reached ();
484 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
486 g_error ("remoting not installed");
491 default_delegate_trampoline (MonoClass *klass)
493 g_assert_not_reached ();
497 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
498 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
499 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
500 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
501 static MonoImtThunkBuilder imt_thunk_builder = NULL;
502 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
503 #if (MONO_IMT_SIZE > 32)
504 #error "MONO_IMT_SIZE cannot be larger than 32"
508 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
510 memcpy (&callbacks, cbs, sizeof (*cbs));
513 MonoRuntimeCallbacks*
514 mono_get_runtime_callbacks (void)
520 mono_install_trampoline (MonoTrampoline func)
522 arch_create_jit_trampoline = func? func: default_trampoline;
526 mono_install_jump_trampoline (MonoJumpTrampoline func)
528 arch_create_jump_trampoline = func? func: default_jump_trampoline;
532 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
534 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
538 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
540 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
544 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
545 imt_thunk_builder = func;
548 static MonoCompileFunc default_mono_compile_method = NULL;
551 * mono_install_compile_method:
552 * @func: function to install
554 * This is a VM internal routine
557 mono_install_compile_method (MonoCompileFunc func)
559 default_mono_compile_method = func;
563 * mono_compile_method:
564 * @method: The method to compile.
566 * This JIT-compiles the method, and returns the pointer to the native code
570 mono_compile_method (MonoMethod *method)
572 if (!default_mono_compile_method) {
573 g_error ("compile method called on uninitialized runtime");
576 return default_mono_compile_method (method);
580 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
582 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
586 mono_runtime_create_delegate_trampoline (MonoClass *klass)
588 return arch_create_delegate_trampoline (klass);
591 static MonoFreeMethodFunc default_mono_free_method = NULL;
594 * mono_install_free_method:
595 * @func: pointer to the MonoFreeMethodFunc used to release a method
597 * This is an internal VM routine, it is used for the engines to
598 * register a handler to release the resources associated with a method.
600 * Methods are freed when no more references to the delegate that holds
604 mono_install_free_method (MonoFreeMethodFunc func)
606 default_mono_free_method = func;
610 * mono_runtime_free_method:
611 * @domain; domain where the method is hosted
612 * @method: method to release
614 * This routine is invoked to free the resources associated with
615 * a method that has been JIT compiled. This is used to discard
616 * methods that were used only temporarily (for example, used in marshalling)
620 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
622 if (default_mono_free_method != NULL)
623 default_mono_free_method (domain, method);
625 mono_method_clear_object (domain, method);
627 mono_free_method (method);
631 * The vtables in the root appdomain are assumed to be reachable by other
632 * roots, and we don't use typed allocation in the other domains.
635 /* The sync block is no longer a GC pointer */
636 #define GC_HEADER_BITMAP (0)
638 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
641 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
643 MonoClassField *field;
649 max_size = mono_class_data_size (class) / sizeof (gpointer);
651 max_size = class->instance_size / sizeof (gpointer);
652 if (max_size > size) {
653 g_assert (offset <= 0);
654 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
659 /*An Ephemeron cannot be marked by sgen*/
660 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
662 memset (bitmap, 0, size / 8);
667 for (p = class; p != NULL; p = p->parent) {
668 gpointer iter = NULL;
669 while ((field = mono_class_get_fields (p, &iter))) {
673 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
675 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
678 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
681 /* FIXME: should not happen, flag as type load error */
682 if (field->type->byref)
685 if (static_fields && field->offset == -1)
689 pos = field->offset / sizeof (gpointer);
692 type = mono_type_get_underlying_type (field->type);
693 switch (type->type) {
696 case MONO_TYPE_FNPTR:
698 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
703 if (class->image != mono_defaults.corlib)
706 case MONO_TYPE_STRING:
707 case MONO_TYPE_SZARRAY:
708 case MONO_TYPE_CLASS:
709 case MONO_TYPE_OBJECT:
710 case MONO_TYPE_ARRAY:
711 g_assert ((field->offset % sizeof(gpointer)) == 0);
713 g_assert (pos < size || pos <= max_size);
714 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
715 *max_set = MAX (*max_set, pos);
717 case MONO_TYPE_GENERICINST:
718 if (!mono_type_generic_inst_is_valuetype (type)) {
719 g_assert ((field->offset % sizeof(gpointer)) == 0);
721 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
722 *max_set = MAX (*max_set, pos);
727 case MONO_TYPE_VALUETYPE: {
728 MonoClass *fclass = mono_class_from_mono_type (field->type);
729 if (fclass->has_references) {
730 /* remove the object header */
731 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
745 case MONO_TYPE_BOOLEAN:
749 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 * similar to the above, but sets the bits in the bitmap for any non-ref field
762 * and ignores static fields
765 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
767 MonoClassField *field;
772 max_size = class->instance_size / sizeof (gpointer);
773 if (max_size >= size) {
774 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
777 for (p = class; p != NULL; p = p->parent) {
778 gpointer iter = NULL;
779 while ((field = mono_class_get_fields (p, &iter))) {
782 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
784 /* FIXME: should not happen, flag as type load error */
785 if (field->type->byref)
788 pos = field->offset / sizeof (gpointer);
791 type = mono_type_get_underlying_type (field->type);
792 switch (type->type) {
793 #if SIZEOF_VOID_P == 8
797 case MONO_TYPE_FNPTR:
802 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
803 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
804 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
807 #if SIZEOF_VOID_P == 4
811 case MONO_TYPE_FNPTR:
816 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
817 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
818 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
824 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
825 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
826 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
829 case MONO_TYPE_BOOLEAN:
832 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
834 case MONO_TYPE_STRING:
835 case MONO_TYPE_SZARRAY:
836 case MONO_TYPE_CLASS:
837 case MONO_TYPE_OBJECT:
838 case MONO_TYPE_ARRAY:
840 case MONO_TYPE_GENERICINST:
841 if (!mono_type_generic_inst_is_valuetype (type)) {
846 case MONO_TYPE_VALUETYPE: {
847 MonoClass *fclass = mono_class_from_mono_type (field->type);
848 /* remove the object header */
849 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
853 g_assert_not_reached ();
862 * mono_class_insecure_overlapping:
863 * check if a class with explicit layout has references and non-references
864 * fields overlapping.
866 * Returns: TRUE if it is insecure to load the type.
869 mono_class_insecure_overlapping (MonoClass *klass)
873 gsize default_bitmap [4] = {0};
875 gsize default_nrbitmap [4] = {0};
876 int i, insecure = FALSE;
879 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
880 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
882 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
883 int idx = i % (sizeof (bitmap [0]) * 8);
884 if (bitmap [idx] & nrbitmap [idx]) {
889 if (bitmap != default_bitmap)
891 if (nrbitmap != default_nrbitmap)
894 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
902 mono_string_alloc (int length)
904 return mono_string_new_size (mono_domain_get (), length);
908 mono_class_compute_gc_descriptor (MonoClass *class)
912 gsize default_bitmap [4] = {0};
913 static gboolean gcj_inited = FALSE;
918 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
919 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
920 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
921 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
923 #ifdef HAVE_GC_GCJ_MALLOC
925 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
929 #ifdef GC_REDIRECT_TO_LOCAL
930 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
931 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
933 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
934 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
939 mono_loader_unlock ();
943 mono_class_init (class);
945 if (class->gc_descr_inited)
948 class->gc_descr_inited = TRUE;
949 class->gc_descr = GC_NO_DESCRIPTOR;
951 bitmap = default_bitmap;
952 if (class == mono_defaults.string_class) {
953 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
954 } else if (class->rank) {
955 mono_class_compute_gc_descriptor (class->element_class);
956 if (!class->element_class->valuetype) {
958 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
959 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
960 class->name_space, class->name);*/
962 /* remove the object header */
963 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
964 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
965 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
966 class->name_space, class->name);*/
967 if (bitmap != default_bitmap)
971 /*static int count = 0;
974 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
975 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
977 if (class->gc_descr == GC_NO_DESCRIPTOR)
978 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
980 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
981 if (bitmap != default_bitmap)
987 * field_is_special_static:
988 * @fklass: The MonoClass to look up.
989 * @field: The MonoClassField describing the field.
991 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
992 * SPECIAL_STATIC_NONE otherwise.
995 field_is_special_static (MonoClass *fklass, MonoClassField *field)
997 MonoCustomAttrInfo *ainfo;
999 ainfo = mono_custom_attrs_from_field (fklass, field);
1002 for (i = 0; i < ainfo->num_attrs; ++i) {
1003 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1004 if (klass->image == mono_defaults.corlib) {
1005 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1006 mono_custom_attrs_free (ainfo);
1007 return SPECIAL_STATIC_THREAD;
1009 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1010 mono_custom_attrs_free (ainfo);
1011 return SPECIAL_STATIC_CONTEXT;
1015 mono_custom_attrs_free (ainfo);
1016 return SPECIAL_STATIC_NONE;
1019 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1020 #define mix(a,b,c) { \
1021 a -= c; a ^= rot(c, 4); c += b; \
1022 b -= a; b ^= rot(a, 6); a += c; \
1023 c -= b; c ^= rot(b, 8); b += a; \
1024 a -= c; a ^= rot(c,16); c += b; \
1025 b -= a; b ^= rot(a,19); a += c; \
1026 c -= b; c ^= rot(b, 4); b += a; \
1028 #define final(a,b,c) { \
1029 c ^= b; c -= rot(b,14); \
1030 a ^= c; a -= rot(c,11); \
1031 b ^= a; b -= rot(a,25); \
1032 c ^= b; c -= rot(b,16); \
1033 a ^= c; a -= rot(c,4); \
1034 b ^= a; b -= rot(a,14); \
1035 c ^= b; c -= rot(b,24); \
1039 * mono_method_get_imt_slot:
1041 * The IMT slot is embedded into AOTed code, so this must return the same value
1042 * for the same method across all executions. This means:
1043 * - pointers shouldn't be used as hash values.
1044 * - mono_metadata_str_hash () should be used for hashing strings.
1047 mono_method_get_imt_slot (MonoMethod *method)
1049 MonoMethodSignature *sig;
1051 guint32 *hashes_start, *hashes;
1055 /* This can be used to stress tests the collision code */
1059 * We do this to simplify generic sharing. It will hurt
1060 * performance in cases where a class implements two different
1061 * instantiations of the same generic interface.
1062 * The code in build_imt_slots () depends on this.
1064 if (method->is_inflated)
1065 method = ((MonoMethodInflated*)method)->declaring;
1067 sig = mono_method_signature (method);
1068 hashes_count = sig->param_count + 4;
1069 hashes_start = malloc (hashes_count * sizeof (guint32));
1070 hashes = hashes_start;
1072 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1073 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1074 method->klass->name_space, method->klass->name, method->name);
1075 g_assert_not_reached ();
1078 /* Initialize hashes */
1079 hashes [0] = mono_metadata_str_hash (method->klass->name);
1080 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1081 hashes [2] = mono_metadata_str_hash (method->name);
1082 hashes [3] = mono_metadata_type_hash (sig->ret);
1083 for (i = 0; i < sig->param_count; i++) {
1084 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1087 /* Setup internal state */
1088 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1090 /* Handle most of the hashes */
1091 while (hashes_count > 3) {
1100 /* Handle the last 3 hashes (all the case statements fall through) */
1101 switch (hashes_count) {
1102 case 3 : c += hashes [2];
1103 case 2 : b += hashes [1];
1104 case 1 : a += hashes [0];
1106 case 0: /* nothing left to add */
1110 free (hashes_start);
1111 /* Report the result */
1112 return c % MONO_IMT_SIZE;
1121 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1122 guint32 imt_slot = mono_method_get_imt_slot (method);
1123 MonoImtBuilderEntry *entry;
1125 if (slot_num >= 0 && imt_slot != slot_num) {
1126 /* we build just a single imt slot and this is not it */
1130 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1131 entry->key = method;
1132 entry->value.vtable_slot = vtable_slot;
1133 entry->next = imt_builder [imt_slot];
1134 if (imt_builder [imt_slot] != NULL) {
1135 entry->children = imt_builder [imt_slot]->children + 1;
1136 if (entry->children == 1) {
1137 mono_stats.imt_slots_with_collisions++;
1138 *imt_collisions_bitmap |= (1 << imt_slot);
1141 entry->children = 0;
1142 mono_stats.imt_used_slots++;
1144 imt_builder [imt_slot] = entry;
1147 char *method_name = mono_method_full_name (method, TRUE);
1148 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1149 method, method_name, imt_slot, vtable_slot, entry->children);
1150 g_free (method_name);
1157 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1159 MonoMethod *method = e->key;
1160 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1164 method->klass->name_space,
1165 method->klass->name,
1168 printf (" * %s: NULL\n", message);
1174 compare_imt_builder_entries (const void *p1, const void *p2) {
1175 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1176 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1178 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1182 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1184 int count = end - start;
1185 int chunk_start = out_array->len;
1188 for (i = start; i < end; ++i) {
1189 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1190 item->key = sorted_array [i]->key;
1191 item->value = sorted_array [i]->value;
1192 item->has_target_code = sorted_array [i]->has_target_code;
1193 item->is_equals = TRUE;
1195 item->check_target_idx = out_array->len + 1;
1197 item->check_target_idx = 0;
1198 g_ptr_array_add (out_array, item);
1201 int middle = start + count / 2;
1202 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1204 item->key = sorted_array [middle]->key;
1205 item->is_equals = FALSE;
1206 g_ptr_array_add (out_array, item);
1207 imt_emit_ir (sorted_array, start, middle, out_array);
1208 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1214 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1215 int number_of_entries = entries->children + 1;
1216 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1217 GPtrArray *result = g_ptr_array_new ();
1218 MonoImtBuilderEntry *current_entry;
1221 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1222 sorted_array [i] = current_entry;
1224 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1226 /*for (i = 0; i < number_of_entries; i++) {
1227 print_imt_entry (" sorted array:", sorted_array [i], i);
1230 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1232 free (sorted_array);
1237 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1239 if (imt_builder_entry != NULL) {
1240 if (imt_builder_entry->children == 0 && !fail_tramp) {
1241 /* No collision, return the vtable slot contents */
1242 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1244 /* Collision, build the thunk */
1245 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1248 result = imt_thunk_builder (vtable, domain,
1249 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1250 for (i = 0; i < imt_ir->len; ++i)
1251 g_free (g_ptr_array_index (imt_ir, i));
1252 g_ptr_array_free (imt_ir, TRUE);
1264 static MonoImtBuilderEntry*
1265 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1268 * LOCKING: requires the loader and domain locks.
1272 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1276 guint32 imt_collisions_bitmap = 0;
1277 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1278 int method_count = 0;
1279 gboolean record_method_count_for_max_collisions = FALSE;
1280 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1283 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1285 for (i = 0; i < klass->interface_offsets_count; ++i) {
1286 MonoClass *iface = klass->interfaces_packed [i];
1287 int interface_offset = klass->interface_offsets_packed [i];
1288 int method_slot_in_interface, vt_slot;
1290 if (mono_class_has_variant_generic_params (iface))
1291 has_variant_iface = TRUE;
1293 vt_slot = interface_offset;
1294 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1297 if (slot_num >= 0 && iface->is_inflated) {
1299 * The imt slot of the method is the same as for its declaring method,
1300 * see the comment in mono_method_get_imt_slot (), so we can
1301 * avoid inflating methods which will be discarded by
1302 * add_imt_builder_entry anyway.
1304 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1305 if (mono_method_get_imt_slot (method) != slot_num) {
1310 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1311 if (method->is_generic) {
1312 has_generic_virtual = TRUE;
1317 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1318 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1323 if (extra_interfaces) {
1324 int interface_offset = klass->vtable_size;
1326 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1327 MonoClass* iface = list_item->data;
1328 int method_slot_in_interface;
1329 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1330 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1331 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1333 interface_offset += iface->method.count;
1336 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1337 /* overwrite the imt slot only if we're building all the entries or if
1338 * we're building this specific one
1340 if (slot_num < 0 || i == slot_num) {
1341 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1344 if (imt_builder [i]) {
1345 MonoImtBuilderEntry *entry;
1347 /* Link entries with imt_builder [i] */
1348 for (entry = entries; entry->next; entry = entry->next) {
1350 MonoMethod *method = (MonoMethod*)entry->key;
1351 char *method_name = mono_method_full_name (method, TRUE);
1352 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1353 g_free (method_name);
1356 entry->next = imt_builder [i];
1357 entries->children += imt_builder [i]->children + 1;
1359 imt_builder [i] = entries;
1362 if (has_generic_virtual || has_variant_iface) {
1364 * There might be collisions later when the the thunk is expanded.
1366 imt_collisions_bitmap |= (1 << i);
1369 * The IMT thunk might be called with an instance of one of the
1370 * generic virtual methods, so has to fallback to the IMT trampoline.
1372 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1374 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1377 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1381 if (imt_builder [i] != NULL) {
1382 int methods_in_slot = imt_builder [i]->children + 1;
1383 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1384 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1385 record_method_count_for_max_collisions = TRUE;
1387 method_count += methods_in_slot;
1391 mono_stats.imt_number_of_methods += method_count;
1392 if (record_method_count_for_max_collisions) {
1393 mono_stats.imt_method_count_when_max_collisions = method_count;
1396 for (i = 0; i < MONO_IMT_SIZE; i++) {
1397 MonoImtBuilderEntry* entry = imt_builder [i];
1398 while (entry != NULL) {
1399 MonoImtBuilderEntry* next = entry->next;
1405 /* we OR the bitmap since we may build just a single imt slot at a time */
1406 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1410 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1411 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1415 * mono_vtable_build_imt_slot:
1416 * @vtable: virtual object table struct
1417 * @imt_slot: slot in the IMT table
1419 * Fill the given @imt_slot in the IMT table of @vtable with
1420 * a trampoline or a thunk for the case of collisions.
1421 * This is part of the internal mono API.
1423 * LOCKING: Take the domain lock.
1426 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1428 gpointer *imt = (gpointer*)vtable;
1429 imt -= MONO_IMT_SIZE;
1430 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1432 /* no support for extra interfaces: the proxy objects will need
1433 * to build the complete IMT
1434 * Update and heck needs to ahppen inside the proper domain lock, as all
1435 * the changes made to a MonoVTable.
1437 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1438 mono_domain_lock (vtable->domain);
1439 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1440 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1441 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1442 mono_domain_unlock (vtable->domain);
1443 mono_loader_unlock ();
1448 * The first two free list entries both belong to the wait list: The
1449 * first entry is the pointer to the head of the list and the second
1450 * entry points to the last element. That way appending and removing
1451 * the first element are both O(1) operations.
1453 #ifdef MONO_SMALL_CONFIG
1454 #define NUM_FREE_LISTS 6
1456 #define NUM_FREE_LISTS 12
1458 #define FIRST_FREE_LIST_SIZE 64
1459 #define MAX_WAIT_LENGTH 50
1460 #define THUNK_THRESHOLD 10
1463 * LOCKING: The domain lock must be held.
1466 init_thunk_free_lists (MonoDomain *domain)
1468 if (domain->thunk_free_lists)
1470 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1474 list_index_for_size (int item_size)
1477 int size = FIRST_FREE_LIST_SIZE;
1479 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1488 * mono_method_alloc_generic_virtual_thunk:
1490 * @size: size in bytes
1492 * Allocs size bytes to be used for the code of a generic virtual
1493 * thunk. It's either allocated from the domain's code manager or
1494 * reused from a previously invalidated piece.
1496 * LOCKING: The domain lock must be held.
1499 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1501 static gboolean inited = FALSE;
1502 static int generic_virtual_thunks_size = 0;
1506 MonoThunkFreeList **l;
1508 init_thunk_free_lists (domain);
1510 size += sizeof (guint32);
1511 if (size < sizeof (MonoThunkFreeList))
1512 size = sizeof (MonoThunkFreeList);
1514 i = list_index_for_size (size);
1515 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1516 if ((*l)->size >= size) {
1517 MonoThunkFreeList *item = *l;
1519 return ((guint32*)item) + 1;
1523 /* no suitable item found - search lists of larger sizes */
1524 while (++i < NUM_FREE_LISTS) {
1525 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1528 g_assert (item->size > size);
1529 domain->thunk_free_lists [i] = item->next;
1530 return ((guint32*)item) + 1;
1533 /* still nothing found - allocate it */
1535 mono_counters_register ("Generic virtual thunk bytes",
1536 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1539 generic_virtual_thunks_size += size;
1541 p = mono_domain_code_reserve (domain, size);
1548 * LOCKING: The domain lock must be held.
1551 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1554 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1556 init_thunk_free_lists (domain);
1558 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1559 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1560 int length = item->length;
1563 /* unlink the first item from the wait list */
1564 domain->thunk_free_lists [0] = item->next;
1565 domain->thunk_free_lists [0]->length = length - 1;
1567 i = list_index_for_size (item->size);
1569 /* put it in the free list */
1570 item->next = domain->thunk_free_lists [i];
1571 domain->thunk_free_lists [i] = item;
1575 if (domain->thunk_free_lists [1]) {
1576 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1577 domain->thunk_free_lists [0]->length++;
1579 g_assert (!domain->thunk_free_lists [0]);
1581 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1582 domain->thunk_free_lists [0]->length = 1;
1586 typedef struct _GenericVirtualCase {
1590 struct _GenericVirtualCase *next;
1591 } GenericVirtualCase;
1594 * get_generic_virtual_entries:
1596 * Return IMT entries for the generic virtual method instances and
1597 * variant interface methods for vtable slot
1600 static MonoImtBuilderEntry*
1601 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1603 GenericVirtualCase *list;
1604 MonoImtBuilderEntry *entries;
1606 mono_domain_lock (domain);
1607 if (!domain->generic_virtual_cases)
1608 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1610 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1613 for (; list; list = list->next) {
1614 MonoImtBuilderEntry *entry;
1616 if (list->count < THUNK_THRESHOLD)
1619 entry = g_new0 (MonoImtBuilderEntry, 1);
1620 entry->key = list->method;
1621 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1622 entry->has_target_code = 1;
1624 entry->children = entries->children + 1;
1625 entry->next = entries;
1629 mono_domain_unlock (domain);
1631 /* FIXME: Leaking memory ? */
1636 * mono_method_add_generic_virtual_invocation:
1638 * @vtable_slot: pointer to the vtable slot
1639 * @method: the inflated generic virtual method
1640 * @code: the method's code
1642 * Registers a call via unmanaged code to a generic virtual method
1643 * instantiation or variant interface method. If the number of calls reaches a threshold
1644 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1645 * virtual method thunk.
1648 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1649 gpointer *vtable_slot,
1650 MonoMethod *method, gpointer code)
1652 static gboolean inited = FALSE;
1653 static int num_added = 0;
1655 GenericVirtualCase *gvc, *list;
1656 MonoImtBuilderEntry *entries;
1660 mono_domain_lock (domain);
1661 if (!domain->generic_virtual_cases)
1662 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1664 /* Check whether the case was already added */
1665 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1668 if (gvc->method == method)
1673 /* If not found, make a new one */
1675 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1676 gvc->method = method;
1679 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1681 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1684 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1690 if (++gvc->count == THUNK_THRESHOLD) {
1691 gpointer *old_thunk = *vtable_slot;
1692 gpointer vtable_trampoline = NULL;
1693 gpointer imt_trampoline = NULL;
1695 if ((gpointer)vtable_slot < (gpointer)vtable) {
1696 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1697 int imt_slot = MONO_IMT_SIZE + displacement;
1699 /* Force the rebuild of the thunk at the next call */
1700 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1701 *vtable_slot = imt_trampoline;
1703 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1705 entries = get_generic_virtual_entries (domain, vtable_slot);
1707 sorted = imt_sort_slot_entries (entries);
1709 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1713 MonoImtBuilderEntry *next = entries->next;
1718 for (i = 0; i < sorted->len; ++i)
1719 g_free (g_ptr_array_index (sorted, i));
1720 g_ptr_array_free (sorted, TRUE);
1723 #ifndef __native_client__
1724 /* We don't re-use any thunks as there is a lot of overhead */
1725 /* to deleting and re-using code in Native Client. */
1726 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1727 invalidate_generic_virtual_thunk (domain, old_thunk);
1731 mono_domain_unlock (domain);
1734 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1737 * mono_class_vtable:
1738 * @domain: the application domain
1739 * @class: the class to initialize
1741 * VTables are domain specific because we create domain specific code, and
1742 * they contain the domain specific static class data.
1743 * On failure, NULL is returned, and class->exception_type is set.
1746 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1748 return mono_class_vtable_full (domain, class, FALSE);
1752 * mono_class_vtable_full:
1753 * @domain: the application domain
1754 * @class: the class to initialize
1755 * @raise_on_error if an exception should be raised on failure or not
1757 * VTables are domain specific because we create domain specific code, and
1758 * they contain the domain specific static class data.
1761 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1763 MonoClassRuntimeInfo *runtime_info;
1767 if (class->exception_type) {
1769 mono_raise_exception (mono_class_get_exception_for_failure (class));
1773 /* this check can be inlined in jitted code, too */
1774 runtime_info = class->runtime_info;
1775 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1776 return runtime_info->domain_vtables [domain->domain_id];
1777 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1781 * mono_class_try_get_vtable:
1782 * @domain: the application domain
1783 * @class: the class to initialize
1785 * This function tries to get the associated vtable from @class if
1786 * it was already created.
1789 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1791 MonoClassRuntimeInfo *runtime_info;
1795 runtime_info = class->runtime_info;
1796 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1797 return runtime_info->domain_vtables [domain->domain_id];
1802 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1805 MonoClassRuntimeInfo *runtime_info, *old_info;
1806 MonoClassField *field;
1809 int imt_table_bytes = 0;
1810 guint32 vtable_size, class_size;
1813 gpointer *interface_offsets;
1815 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1816 mono_domain_lock (domain);
1817 runtime_info = class->runtime_info;
1818 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1819 mono_domain_unlock (domain);
1820 mono_loader_unlock ();
1821 return runtime_info->domain_vtables [domain->domain_id];
1823 if (!class->inited || class->exception_type) {
1824 if (!mono_class_init (class) || class->exception_type) {
1825 mono_domain_unlock (domain);
1826 mono_loader_unlock ();
1828 mono_raise_exception (mono_class_get_exception_for_failure (class));
1833 /* Array types require that their element type be valid*/
1834 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1835 MonoClass *element_class = class->element_class;
1836 if (!element_class->inited)
1837 mono_class_init (element_class);
1839 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1840 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1841 mono_class_setup_vtable (element_class);
1843 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1844 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1845 if (class->exception_type == MONO_EXCEPTION_NONE)
1846 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1847 mono_domain_unlock (domain);
1848 mono_loader_unlock ();
1850 mono_raise_exception (mono_class_get_exception_for_failure (class));
1856 * For some classes, mono_class_init () already computed class->vtable_size, and
1857 * that is all that is needed because of the vtable trampolines.
1859 if (!class->vtable_size)
1860 mono_class_setup_vtable (class);
1862 if (class->generic_class && !class->vtable)
1863 mono_class_check_vtable_constraints (class, NULL);
1865 /* Initialize klass->has_finalize */
1866 mono_class_has_finalizer (class);
1868 if (class->exception_type) {
1869 mono_domain_unlock (domain);
1870 mono_loader_unlock ();
1872 mono_raise_exception (mono_class_get_exception_for_failure (class));
1877 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1878 if (class->interface_offsets_count) {
1879 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1880 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1881 mono_stats.imt_number_of_tables++;
1882 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1885 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1886 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1889 mono_stats.used_class_count++;
1890 mono_stats.class_vtable_size += vtable_size;
1891 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1894 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1896 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1898 vt->rank = class->rank;
1899 vt->domain = domain;
1901 mono_class_compute_gc_descriptor (class);
1903 * We can't use typed allocation in the non-root domains, since the
1904 * collector needs the GC descriptor stored in the vtable even after
1905 * the mempool containing the vtable is destroyed when the domain is
1906 * unloaded. An alternative might be to allocate vtables in the GC
1907 * heap, but this does not seem to work (it leads to crashes inside
1908 * libgc). If that approach is tried, two gc descriptors need to be
1909 * allocated for each class: one for the root domain, and one for all
1910 * other domains. The second descriptor should contain a bit for the
1911 * vtable field in MonoObject, since we can no longer assume the
1912 * vtable is reachable by other roots after the appdomain is unloaded.
1914 #ifdef HAVE_BOEHM_GC
1915 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1916 vt->gc_descr = GC_NO_DESCRIPTOR;
1919 vt->gc_descr = class->gc_descr;
1921 if ((class_size = mono_class_data_size (class))) {
1922 if (class->has_static_refs) {
1923 gpointer statics_gc_descr;
1925 gsize default_bitmap [4] = {0};
1928 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1929 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1930 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1931 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1932 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1933 if (bitmap != default_bitmap)
1936 vt->data = mono_domain_alloc0 (domain, class_size);
1938 mono_stats.class_static_data_size += class_size;
1943 while ((field = mono_class_get_fields (class, &iter))) {
1944 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1946 if (mono_field_is_deleted (field))
1948 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1949 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1950 if (special_static != SPECIAL_STATIC_NONE) {
1951 guint32 size, offset;
1953 gsize default_bitmap [4] = {0};
1957 if (mono_type_is_reference (field->type)) {
1958 default_bitmap [0] = 1;
1960 bitmap = default_bitmap;
1961 } else if (mono_type_is_struct (field->type)) {
1962 fclass = mono_class_from_mono_type (field->type);
1963 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1965 default_bitmap [0] = 0;
1967 bitmap = default_bitmap;
1969 size = mono_type_size (field->type, &align);
1970 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
1971 if (!domain->special_static_fields)
1972 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1973 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1974 if (bitmap != default_bitmap)
1977 * This marks the field as special static to speed up the
1978 * checks in mono_field_static_get/set_value ().
1984 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1985 MonoClass *fklass = mono_class_from_mono_type (field->type);
1986 const char *data = mono_field_get_data (field);
1988 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1989 t = (char*)vt->data + field->offset;
1990 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1993 if (fklass->valuetype) {
1994 memcpy (t, data, mono_class_value_size (fklass, NULL));
1996 /* it's a pointer type: add check */
1997 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2004 vt->max_interface_id = class->max_interface_id;
2005 vt->interface_bitmap = class->interface_bitmap;
2007 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2008 // class->name, class->interface_offsets_count);
2010 if (! ARCH_USE_IMT) {
2011 /* initialize interface offsets */
2012 for (i = 0; i < class->interface_offsets_count; ++i) {
2013 int interface_id = class->interfaces_packed [i]->interface_id;
2014 int slot = class->interface_offsets_packed [i];
2015 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2019 /* class_vtable_array keeps an array of created vtables
2021 g_ptr_array_add (domain->class_vtable_array, vt);
2022 /* class->runtime_info is protected by the loader lock, both when
2023 * it it enlarged and when it is stored info.
2026 old_info = class->runtime_info;
2027 if (old_info && old_info->max_domain >= domain->domain_id) {
2028 /* someone already created a large enough runtime info */
2029 mono_memory_barrier ();
2030 old_info->domain_vtables [domain->domain_id] = vt;
2032 int new_size = domain->domain_id;
2034 new_size = MAX (new_size, old_info->max_domain);
2036 /* make the new size a power of two */
2038 while (new_size > i)
2041 /* this is a bounded memory retention issue: may want to
2042 * handle it differently when we'll have a rcu-like system.
2044 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2045 runtime_info->max_domain = new_size - 1;
2046 /* copy the stuff from the older info */
2048 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2050 runtime_info->domain_vtables [domain->domain_id] = vt;
2052 mono_memory_barrier ();
2053 class->runtime_info = runtime_info;
2056 /* Initialize vtable */
2057 if (callbacks.get_vtable_trampoline) {
2058 // This also covers the AOT case
2059 for (i = 0; i < class->vtable_size; ++i) {
2060 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2063 mono_class_setup_vtable (class);
2065 for (i = 0; i < class->vtable_size; ++i) {
2068 if ((cm = class->vtable [i]))
2069 vt->vtable [i] = arch_create_jit_trampoline (cm);
2073 if (ARCH_USE_IMT && imt_table_bytes) {
2074 /* Now that the vtable is full, we can actually fill up the IMT */
2075 if (callbacks.get_imt_trampoline) {
2076 /* lazy construction of the IMT entries enabled */
2077 for (i = 0; i < MONO_IMT_SIZE; ++i)
2078 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2080 build_imt (class, vt, domain, interface_offsets, NULL);
2084 mono_domain_unlock (domain);
2085 mono_loader_unlock ();
2087 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2088 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2089 mono_raise_exception (mono_class_get_exception_for_failure (class));
2091 /* make sure the parent is initialized */
2092 /*FIXME shouldn't this fail the current type?*/
2094 mono_class_vtable_full (domain, class->parent, raise_on_error);
2096 /*FIXME check for OOM*/
2097 vt->type = mono_type_get_object (domain, &class->byval_arg);
2098 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2099 /* This is unregistered in
2100 unregister_vtable_reflection_type() in
2102 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2103 if (class->contextbound)
2112 * mono_class_proxy_vtable:
2113 * @domain: the application domain
2114 * @remove_class: the remote class
2116 * Creates a vtable for transparent proxies. It is basically
2117 * a copy of the real vtable of the class wrapped in @remote_class,
2118 * but all function pointers invoke the remoting functions, and
2119 * vtable->klass points to the transparent proxy class, and not to @class.
2122 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2125 MonoVTable *vt, *pvt;
2126 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2128 GSList *extra_interfaces = NULL;
2129 MonoClass *class = remote_class->proxy_class;
2130 gpointer *interface_offsets;
2134 #ifdef COMPRESSED_INTERFACE_BITMAP
2138 vt = mono_class_vtable (domain, class);
2139 g_assert (vt); /*FIXME property handle failure*/
2140 max_interface_id = vt->max_interface_id;
2142 /* Calculate vtable space for extra interfaces */
2143 for (j = 0; j < remote_class->interface_count; j++) {
2144 MonoClass* iclass = remote_class->interfaces[j];
2148 /*FIXME test for interfaces with variant generic arguments*/
2149 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2150 continue; /* interface implemented by the class */
2151 if (g_slist_find (extra_interfaces, iclass))
2154 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2156 method_count = mono_class_num_methods (iclass);
2158 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2159 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2161 for (i = 0; i < ifaces->len; ++i) {
2162 MonoClass *ic = g_ptr_array_index (ifaces, i);
2163 /*FIXME test for interfaces with variant generic arguments*/
2164 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2165 continue; /* interface implemented by the class */
2166 if (g_slist_find (extra_interfaces, ic))
2168 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2169 method_count += mono_class_num_methods (ic);
2171 g_ptr_array_free (ifaces, TRUE);
2174 extra_interface_vtsize += method_count * sizeof (gpointer);
2175 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2179 mono_stats.imt_number_of_tables++;
2180 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2181 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2182 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2184 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2185 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2188 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2190 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2192 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2194 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2195 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2197 pvt->klass = mono_defaults.transparent_proxy_class;
2198 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2199 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2201 /* initialize vtable */
2202 mono_class_setup_vtable (class);
2203 for (i = 0; i < class->vtable_size; ++i) {
2206 if ((cm = class->vtable [i]))
2207 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2209 pvt->vtable [i] = NULL;
2212 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2213 /* create trampolines for abstract methods */
2214 for (k = class; k; k = k->parent) {
2216 gpointer iter = NULL;
2217 while ((m = mono_class_get_methods (k, &iter)))
2218 if (!pvt->vtable [m->slot])
2219 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2223 pvt->max_interface_id = max_interface_id;
2224 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2225 #ifdef COMPRESSED_INTERFACE_BITMAP
2226 bitmap = g_malloc0 (bsize);
2228 bitmap = mono_domain_alloc0 (domain, bsize);
2231 if (! ARCH_USE_IMT) {
2232 /* initialize interface offsets */
2233 for (i = 0; i < class->interface_offsets_count; ++i) {
2234 int interface_id = class->interfaces_packed [i]->interface_id;
2235 int slot = class->interface_offsets_packed [i];
2236 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2239 for (i = 0; i < class->interface_offsets_count; ++i) {
2240 int interface_id = class->interfaces_packed [i]->interface_id;
2241 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2244 if (extra_interfaces) {
2245 int slot = class->vtable_size;
2251 /* Create trampolines for the methods of the interfaces */
2252 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2253 interf = list_item->data;
2255 if (! ARCH_USE_IMT) {
2256 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2258 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2262 while ((cm = mono_class_get_methods (interf, &iter)))
2263 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2265 slot += mono_class_num_methods (interf);
2267 if (! ARCH_USE_IMT) {
2268 g_slist_free (extra_interfaces);
2273 /* Now that the vtable is full, we can actually fill up the IMT */
2274 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2275 if (extra_interfaces) {
2276 g_slist_free (extra_interfaces);
2280 #ifdef COMPRESSED_INTERFACE_BITMAP
2281 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2282 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2283 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2286 pvt->interface_bitmap = bitmap;
2292 * mono_class_field_is_special_static:
2294 * Returns whether @field is a thread/context static field.
2297 mono_class_field_is_special_static (MonoClassField *field)
2299 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2301 if (mono_field_is_deleted (field))
2303 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2304 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2311 * mono_class_field_get_special_static_type:
2312 * @field: The MonoClassField describing the field.
2314 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2315 * SPECIAL_STATIC_NONE otherwise.
2318 mono_class_field_get_special_static_type (MonoClassField *field)
2320 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2321 return SPECIAL_STATIC_NONE;
2322 if (mono_field_is_deleted (field))
2323 return SPECIAL_STATIC_NONE;
2324 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2325 return field_is_special_static (field->parent, field);
2326 return SPECIAL_STATIC_NONE;
2330 * mono_class_has_special_static_fields:
2332 * Returns whenever @klass has any thread/context static fields.
2335 mono_class_has_special_static_fields (MonoClass *klass)
2337 MonoClassField *field;
2341 while ((field = mono_class_get_fields (klass, &iter))) {
2342 g_assert (field->parent == klass);
2343 if (mono_class_field_is_special_static (field))
2351 * create_remote_class_key:
2352 * Creates an array of pointers that can be used as a hash key for a remote class.
2353 * The first element of the array is the number of pointers.
2356 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2361 if (remote_class == NULL) {
2362 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2363 key = g_malloc (sizeof(gpointer) * 3);
2364 key [0] = GINT_TO_POINTER (2);
2365 key [1] = mono_defaults.marshalbyrefobject_class;
2366 key [2] = extra_class;
2368 key = g_malloc (sizeof(gpointer) * 2);
2369 key [0] = GINT_TO_POINTER (1);
2370 key [1] = extra_class;
2373 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2374 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2375 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2376 key [1] = remote_class->proxy_class;
2378 // Keep the list of interfaces sorted
2379 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2380 if (extra_class && remote_class->interfaces [i] > extra_class) {
2381 key [j++] = extra_class;
2384 key [j] = remote_class->interfaces [i];
2387 key [j] = extra_class;
2389 // Replace the old class. The interface list is the same
2390 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2391 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2392 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2393 for (i = 0; i < remote_class->interface_count; i++)
2394 key [2 + i] = remote_class->interfaces [i];
2402 * copy_remote_class_key:
2404 * Make a copy of KEY in the domain and return the copy.
2407 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2409 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2410 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2412 memcpy (mp_key, key, key_size);
2418 * mono_remote_class:
2419 * @domain: the application domain
2420 * @class_name: name of the remote class
2422 * Creates and initializes a MonoRemoteClass object for a remote type.
2424 * Can raise an exception on failure.
2427 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2430 MonoRemoteClass *rc;
2431 gpointer* key, *mp_key;
2434 key = create_remote_class_key (NULL, proxy_class);
2436 mono_domain_lock (domain);
2437 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2441 mono_domain_unlock (domain);
2445 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2446 if (!mono_error_ok (&error)) {
2448 mono_domain_unlock (domain);
2449 mono_error_raise_exception (&error);
2452 mp_key = copy_remote_class_key (domain, key);
2456 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2457 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2458 rc->interface_count = 1;
2459 rc->interfaces [0] = proxy_class;
2460 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2462 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2463 rc->interface_count = 0;
2464 rc->proxy_class = proxy_class;
2467 rc->default_vtable = NULL;
2468 rc->xdomain_vtable = NULL;
2469 rc->proxy_class_name = name;
2470 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2472 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2474 mono_domain_unlock (domain);
2479 * clone_remote_class:
2480 * Creates a copy of the remote_class, adding the provided class or interface
2482 static MonoRemoteClass*
2483 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2485 MonoRemoteClass *rc;
2486 gpointer* key, *mp_key;
2488 key = create_remote_class_key (remote_class, extra_class);
2489 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2495 mp_key = copy_remote_class_key (domain, key);
2499 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2501 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2502 rc->proxy_class = remote_class->proxy_class;
2503 rc->interface_count = remote_class->interface_count + 1;
2505 // Keep the list of interfaces sorted, since the hash key of
2506 // the remote class depends on this
2507 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2508 if (remote_class->interfaces [i] > extra_class && i == j)
2509 rc->interfaces [j++] = extra_class;
2510 rc->interfaces [j] = remote_class->interfaces [i];
2513 rc->interfaces [j] = extra_class;
2515 // Replace the old class. The interface array is the same
2516 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2517 rc->proxy_class = extra_class;
2518 rc->interface_count = remote_class->interface_count;
2519 if (rc->interface_count > 0)
2520 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2523 rc->default_vtable = NULL;
2524 rc->xdomain_vtable = NULL;
2525 rc->proxy_class_name = remote_class->proxy_class_name;
2527 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2533 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2535 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2536 mono_domain_lock (domain);
2537 if (rp->target_domain_id != -1) {
2538 if (remote_class->xdomain_vtable == NULL)
2539 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2540 mono_domain_unlock (domain);
2541 mono_loader_unlock ();
2542 return remote_class->xdomain_vtable;
2544 if (remote_class->default_vtable == NULL) {
2547 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2548 klass = mono_class_from_mono_type (type);
2549 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2550 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2552 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2555 mono_domain_unlock (domain);
2556 mono_loader_unlock ();
2557 return remote_class->default_vtable;
2561 * mono_upgrade_remote_class:
2562 * @domain: the application domain
2563 * @tproxy: the proxy whose remote class has to be upgraded.
2564 * @klass: class to which the remote class can be casted.
2566 * Updates the vtable of the remote class by adding the necessary method slots
2567 * and interface offsets so it can be safely casted to klass. klass can be a
2568 * class or an interface.
2571 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2573 MonoTransparentProxy *tproxy;
2574 MonoRemoteClass *remote_class;
2575 gboolean redo_vtable;
2577 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2578 mono_domain_lock (domain);
2580 tproxy = (MonoTransparentProxy*) proxy_object;
2581 remote_class = tproxy->remote_class;
2583 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2586 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2587 if (remote_class->interfaces [i] == klass)
2588 redo_vtable = FALSE;
2591 redo_vtable = (remote_class->proxy_class != klass);
2595 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2596 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2599 mono_domain_unlock (domain);
2600 mono_loader_unlock ();
2605 * mono_object_get_virtual_method:
2606 * @obj: object to operate on.
2609 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2610 * the instance of a callvirt of method.
2613 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2616 MonoMethod **vtable;
2618 MonoMethod *res = NULL;
2620 klass = mono_object_class (obj);
2621 if (klass == mono_defaults.transparent_proxy_class) {
2622 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2628 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2631 mono_class_setup_vtable (klass);
2632 vtable = klass->vtable;
2634 if (method->slot == -1) {
2635 /* method->slot might not be set for instances of generic methods */
2636 if (method->is_inflated) {
2637 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2638 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2641 g_assert_not_reached ();
2645 /* check method->slot is a valid index: perform isinstance? */
2646 if (method->slot != -1) {
2647 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2649 gboolean variance_used = FALSE;
2650 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2651 g_assert (iface_offset > 0);
2652 res = vtable [iface_offset + method->slot];
2655 res = vtable [method->slot];
2660 /* It may be an interface, abstract class method or generic method */
2661 if (!res || mono_method_signature (res)->generic_param_count)
2664 /* generic methods demand invoke_with_check */
2665 if (mono_method_signature (res)->generic_param_count)
2666 res = mono_marshal_get_remoting_invoke_with_check (res);
2669 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2670 res = mono_cominterop_get_invoke (res);
2673 res = mono_marshal_get_remoting_invoke (res);
2676 if (method->is_inflated) {
2677 /* Have to inflate the result */
2678 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2688 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2690 g_error ("runtime invoke called on uninitialized runtime");
2694 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2697 * mono_runtime_invoke:
2698 * @method: method to invoke
2699 * @obJ: object instance
2700 * @params: arguments to the method
2701 * @exc: exception information.
2703 * Invokes the method represented by @method on the object @obj.
2705 * obj is the 'this' pointer, it should be NULL for static
2706 * methods, a MonoObject* for object instances and a pointer to
2707 * the value type for value types.
2709 * The params array contains the arguments to the method with the
2710 * same convention: MonoObject* pointers for object instances and
2711 * pointers to the value type otherwise.
2713 * From unmanaged code you'll usually use the
2714 * mono_runtime_invoke() variant.
2716 * Note that this function doesn't handle virtual methods for
2717 * you, it will exec the exact method you pass: we still need to
2718 * expose a function to lookup the derived class implementation
2719 * of a virtual method (there are examples of this in the code,
2722 * You can pass NULL as the exc argument if you don't want to
2723 * catch exceptions, otherwise, *exc will be set to the exception
2724 * thrown, if any. if an exception is thrown, you can't use the
2725 * MonoObject* result from the function.
2727 * If the method returns a value type, it is boxed in an object
2731 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2735 if (mono_runtime_get_no_exec ())
2736 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2738 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2739 mono_profiler_method_start_invoke (method);
2741 result = default_mono_runtime_invoke (method, obj, params, exc);
2743 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2744 mono_profiler_method_end_invoke (method);
2750 * mono_method_get_unmanaged_thunk:
2751 * @method: method to generate a thunk for.
2753 * Returns an unmanaged->managed thunk that can be used to call
2754 * a managed method directly from C.
2756 * The thunk's C signature closely matches the managed signature:
2758 * C#: public bool Equals (object obj);
2759 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2760 * MonoObject*, MonoException**);
2762 * The 1st ("this") parameter must not be used with static methods:
2764 * C#: public static bool ReferenceEquals (object a, object b);
2765 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2768 * The last argument must be a non-null pointer of a MonoException* pointer.
2769 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2770 * exception has been thrown in managed code. Otherwise it will point
2771 * to the MonoException* caught by the thunk. In this case, the result of
2772 * the thunk is undefined:
2774 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2775 * MonoException *ex = NULL;
2776 * Equals func = mono_method_get_unmanaged_thunk (method);
2777 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2779 * // handle exception
2782 * The calling convention of the thunk matches the platform's default
2783 * convention. This means that under Windows, C declarations must
2784 * contain the __stdcall attribute:
2786 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2787 * MonoObject*, MonoException**);
2791 * Value type arguments and return values are treated as they were objects:
2793 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2794 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2796 * Arguments must be properly boxed upon trunk's invocation, while return
2797 * values must be unboxed.
2800 mono_method_get_unmanaged_thunk (MonoMethod *method)
2802 method = mono_marshal_get_thunk_invoke_wrapper (method);
2803 return mono_compile_method (method);
2807 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2811 /* object fields cannot be byref, so we don't need a
2813 gpointer *p = (gpointer*)dest;
2820 case MONO_TYPE_BOOLEAN:
2822 case MONO_TYPE_U1: {
2823 guint8 *p = (guint8*)dest;
2824 *p = value ? *(guint8*)value : 0;
2829 case MONO_TYPE_CHAR: {
2830 guint16 *p = (guint16*)dest;
2831 *p = value ? *(guint16*)value : 0;
2834 #if SIZEOF_VOID_P == 4
2839 case MONO_TYPE_U4: {
2840 gint32 *p = (gint32*)dest;
2841 *p = value ? *(gint32*)value : 0;
2844 #if SIZEOF_VOID_P == 8
2849 case MONO_TYPE_U8: {
2850 gint64 *p = (gint64*)dest;
2851 *p = value ? *(gint64*)value : 0;
2854 case MONO_TYPE_R4: {
2855 float *p = (float*)dest;
2856 *p = value ? *(float*)value : 0;
2859 case MONO_TYPE_R8: {
2860 double *p = (double*)dest;
2861 *p = value ? *(double*)value : 0;
2864 case MONO_TYPE_STRING:
2865 case MONO_TYPE_SZARRAY:
2866 case MONO_TYPE_CLASS:
2867 case MONO_TYPE_OBJECT:
2868 case MONO_TYPE_ARRAY:
2869 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2871 case MONO_TYPE_FNPTR:
2872 case MONO_TYPE_PTR: {
2873 gpointer *p = (gpointer*)dest;
2874 *p = deref_pointer? *(gpointer*)value: value;
2877 case MONO_TYPE_VALUETYPE:
2878 /* note that 't' and 'type->type' can be different */
2879 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2880 t = mono_class_enum_basetype (type->data.klass)->type;
2883 MonoClass *class = mono_class_from_mono_type (type);
2884 int size = mono_class_value_size (class, NULL);
2886 memset (dest, 0, size);
2888 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2891 case MONO_TYPE_GENERICINST:
2892 t = type->data.generic_class->container_class->byval_arg.type;
2895 g_warning ("got type %x", type->type);
2896 g_assert_not_reached ();
2901 * mono_field_set_value:
2902 * @obj: Instance object
2903 * @field: MonoClassField describing the field to set
2904 * @value: The value to be set
2906 * Sets the value of the field described by @field in the object instance @obj
2907 * to the value passed in @value. This method should only be used for instance
2908 * fields. For static fields, use mono_field_static_set_value.
2910 * The value must be on the native format of the field type.
2913 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2917 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2919 dest = (char*)obj + field->offset;
2920 set_value (field->type, dest, value, FALSE);
2924 * mono_field_static_set_value:
2925 * @field: MonoClassField describing the field to set
2926 * @value: The value to be set
2928 * Sets the value of the static field described by @field
2929 * to the value passed in @value.
2931 * The value must be on the native format of the field type.
2934 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2938 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2939 /* you cant set a constant! */
2940 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2942 if (field->offset == -1) {
2943 /* Special static */
2946 mono_domain_lock (vt->domain);
2947 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2948 mono_domain_unlock (vt->domain);
2949 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2951 dest = (char*)vt->data + field->offset;
2953 set_value (field->type, dest, value, FALSE);
2956 /* Used by the debugger */
2958 mono_vtable_get_static_field_data (MonoVTable *vt)
2964 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2968 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2969 if (field->offset == -1) {
2970 /* Special static */
2973 mono_domain_lock (vt->domain);
2974 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2975 mono_domain_unlock (vt->domain);
2976 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2978 src = (guint8*)vt->data + field->offset;
2981 src = (guint8*)obj + field->offset;
2988 * mono_field_get_value:
2989 * @obj: Object instance
2990 * @field: MonoClassField describing the field to fetch information from
2991 * @value: pointer to the location where the value will be stored
2993 * Use this routine to get the value of the field @field in the object
2996 * The pointer provided by value must be of the field type, for reference
2997 * types this is a MonoObject*, for value types its the actual pointer to
3002 * mono_field_get_value (obj, int_field, &i);
3005 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3011 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3013 src = (char*)obj + field->offset;
3014 set_value (field->type, value, src, TRUE);
3018 * mono_field_get_value_object:
3019 * @domain: domain where the object will be created (if boxing)
3020 * @field: MonoClassField describing the field to fetch information from
3021 * @obj: The object instance for the field.
3023 * Returns: a new MonoObject with the value from the given field. If the
3024 * field represents a value type, the value is boxed.
3028 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3032 MonoVTable *vtable = NULL;
3034 gboolean is_static = FALSE;
3035 gboolean is_ref = FALSE;
3036 gboolean is_literal = FALSE;
3037 gboolean is_ptr = FALSE;
3039 MonoType *type = mono_field_get_type_checked (field, &error);
3041 if (!mono_error_ok (&error))
3042 mono_error_raise_exception (&error);
3044 switch (type->type) {
3045 case MONO_TYPE_STRING:
3046 case MONO_TYPE_OBJECT:
3047 case MONO_TYPE_CLASS:
3048 case MONO_TYPE_ARRAY:
3049 case MONO_TYPE_SZARRAY:
3054 case MONO_TYPE_BOOLEAN:
3057 case MONO_TYPE_CHAR:
3066 case MONO_TYPE_VALUETYPE:
3067 is_ref = type->byref;
3069 case MONO_TYPE_GENERICINST:
3070 is_ref = !mono_type_generic_inst_is_valuetype (type);
3076 g_error ("type 0x%x not handled in "
3077 "mono_field_get_value_object", type->type);
3081 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3084 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3088 vtable = mono_class_vtable (domain, field->parent);
3090 char *name = mono_type_get_full_name (field->parent);
3091 /*FIXME extend this to use the MonoError api*/
3092 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3096 if (!vtable->initialized)
3097 mono_runtime_class_init (vtable);
3105 get_default_field_value (domain, field, &o);
3106 } else if (is_static) {
3107 mono_field_static_get_value (vtable, field, &o);
3109 mono_field_get_value (obj, field, &o);
3115 static MonoMethod *m;
3121 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3122 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3128 get_default_field_value (domain, field, v);
3129 } else if (is_static) {
3130 mono_field_static_get_value (vtable, field, v);
3132 mono_field_get_value (obj, field, v);
3135 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3137 args [1] = mono_type_get_object (mono_domain_get (), type);
3139 return mono_runtime_invoke (m, NULL, args, NULL);
3142 /* boxed value type */
3143 klass = mono_class_from_mono_type (type);
3145 if (mono_class_is_nullable (klass))
3146 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3148 o = mono_object_new (domain, klass);
3149 v = ((gchar *) o) + sizeof (MonoObject);
3152 get_default_field_value (domain, field, v);
3153 } else if (is_static) {
3154 mono_field_static_get_value (vtable, field, v);
3156 mono_field_get_value (obj, field, v);
3163 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3166 const char *p = blob;
3167 mono_metadata_decode_blob_size (p, &p);
3170 case MONO_TYPE_BOOLEAN:
3173 *(guint8 *) value = *p;
3175 case MONO_TYPE_CHAR:
3178 *(guint16*) value = read16 (p);
3182 *(guint32*) value = read32 (p);
3186 *(guint64*) value = read64 (p);
3189 readr4 (p, (float*) value);
3192 readr8 (p, (double*) value);
3194 case MONO_TYPE_STRING:
3195 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3197 case MONO_TYPE_CLASS:
3198 *(gpointer*) value = NULL;
3202 g_warning ("type 0x%02x should not be in constant table", type);
3208 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3210 MonoTypeEnum def_type;
3213 data = mono_class_get_field_default_value (field, &def_type);
3214 mono_get_constant_value_from_blob (domain, def_type, data, value);
3218 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3222 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3224 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3225 get_default_field_value (vt->domain, field, value);
3229 if (field->offset == -1) {
3230 /* Special static */
3231 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3232 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3234 src = (char*)vt->data + field->offset;
3236 set_value (field->type, value, src, TRUE);
3240 * mono_field_static_get_value:
3241 * @vt: vtable to the object
3242 * @field: MonoClassField describing the field to fetch information from
3243 * @value: where the value is returned
3245 * Use this routine to get the value of the static field @field value.
3247 * The pointer provided by value must be of the field type, for reference
3248 * types this is a MonoObject*, for value types its the actual pointer to
3253 * mono_field_static_get_value (vt, int_field, &i);
3256 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3258 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3262 * mono_property_set_value:
3263 * @prop: MonoProperty to set
3264 * @obj: instance object on which to act
3265 * @params: parameters to pass to the propery
3266 * @exc: optional exception
3268 * Invokes the property's set method with the given arguments on the
3269 * object instance obj (or NULL for static properties).
3271 * You can pass NULL as the exc argument if you don't want to
3272 * catch exceptions, otherwise, *exc will be set to the exception
3273 * thrown, if any. if an exception is thrown, you can't use the
3274 * MonoObject* result from the function.
3277 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3279 default_mono_runtime_invoke (prop->set, obj, params, exc);
3283 * mono_property_get_value:
3284 * @prop: MonoProperty to fetch
3285 * @obj: instance object on which to act
3286 * @params: parameters to pass to the propery
3287 * @exc: optional exception
3289 * Invokes the property's get method with the given arguments on the
3290 * object instance obj (or NULL for static properties).
3292 * You can pass NULL as the exc argument if you don't want to
3293 * catch exceptions, otherwise, *exc will be set to the exception
3294 * thrown, if any. if an exception is thrown, you can't use the
3295 * MonoObject* result from the function.
3297 * Returns: the value from invoking the get method on the property.
3300 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3302 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3306 * mono_nullable_init:
3307 * @buf: The nullable structure to initialize.
3308 * @value: the value to initialize from
3309 * @klass: the type for the object
3311 * Initialize the nullable structure pointed to by @buf from @value which
3312 * should be a boxed value type. The size of @buf should be able to hold
3313 * as much data as the @klass->instance_size (which is the number of bytes
3314 * that will be copies).
3316 * Since Nullables have variable structure, we can not define a C
3317 * structure for them.
3320 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3322 MonoClass *param_class = klass->cast_class;
3324 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3325 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3327 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3329 if (param_class->has_references)
3330 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3332 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3334 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3339 * mono_nullable_box:
3340 * @buf: The buffer representing the data to be boxed
3341 * @klass: the type to box it as.
3343 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3347 mono_nullable_box (guint8 *buf, MonoClass *klass)
3349 MonoClass *param_class = klass->cast_class;
3351 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3352 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3354 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3355 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3356 if (param_class->has_references)
3357 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3359 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3367 * mono_get_delegate_invoke:
3368 * @klass: The delegate class
3370 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3373 mono_get_delegate_invoke (MonoClass *klass)
3377 /* This is called at runtime, so avoid the slower search in metadata */
3378 mono_class_setup_methods (klass);
3379 if (klass->exception_type)
3381 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3386 * mono_runtime_delegate_invoke:
3387 * @delegate: pointer to a delegate object.
3388 * @params: parameters for the delegate.
3389 * @exc: Pointer to the exception result.
3391 * Invokes the delegate method @delegate with the parameters provided.
3393 * You can pass NULL as the exc argument if you don't want to
3394 * catch exceptions, otherwise, *exc will be set to the exception
3395 * thrown, if any. if an exception is thrown, you can't use the
3396 * MonoObject* result from the function.
3399 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3403 im = mono_get_delegate_invoke (delegate->vtable->klass);
3406 return mono_runtime_invoke (im, delegate, params, exc);
3409 static char **main_args = NULL;
3410 static int num_main_args;
3413 * mono_runtime_get_main_args:
3415 * Returns: a MonoArray with the arguments passed to the main program
3418 mono_runtime_get_main_args (void)
3422 MonoDomain *domain = mono_domain_get ();
3427 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3429 for (i = 0; i < num_main_args; ++i)
3430 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3436 free_main_args (void)
3440 for (i = 0; i < num_main_args; ++i)
3441 g_free (main_args [i]);
3446 * mono_runtime_run_main:
3447 * @method: the method to start the application with (usually Main)
3448 * @argc: number of arguments from the command line
3449 * @argv: array of strings from the command line
3450 * @exc: excetption results
3452 * Execute a standard Main() method (argc/argv contains the
3453 * executable name). This method also sets the command line argument value
3454 * needed by System.Environment.
3459 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3463 MonoArray *args = NULL;
3464 MonoDomain *domain = mono_domain_get ();
3465 gchar *utf8_fullpath;
3466 MonoMethodSignature *sig;
3468 g_assert (method != NULL);
3470 mono_thread_set_main (mono_thread_current ());
3472 main_args = g_new0 (char*, argc);
3473 num_main_args = argc;
3475 if (!g_path_is_absolute (argv [0])) {
3476 gchar *basename = g_path_get_basename (argv [0]);
3477 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3481 utf8_fullpath = mono_utf8_from_external (fullpath);
3482 if(utf8_fullpath == NULL) {
3483 /* Printing the arg text will cause glib to
3484 * whinge about "Invalid UTF-8", but at least
3485 * its relevant, and shows the problem text
3488 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3489 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3496 utf8_fullpath = mono_utf8_from_external (argv[0]);
3497 if(utf8_fullpath == NULL) {
3498 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3499 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3504 main_args [0] = utf8_fullpath;
3506 for (i = 1; i < argc; ++i) {
3509 utf8_arg=mono_utf8_from_external (argv[i]);
3510 if(utf8_arg==NULL) {
3511 /* Ditto the comment about Invalid UTF-8 here */
3512 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3513 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3517 main_args [i] = utf8_arg;
3522 sig = mono_method_signature (method);
3524 g_print ("Unable to load Main method.\n");
3528 if (sig->param_count) {
3529 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3530 for (i = 0; i < argc; ++i) {
3531 /* The encodings should all work, given that
3532 * we've checked all these args for the
3535 gchar *str = mono_utf8_from_external (argv [i]);
3536 MonoString *arg = mono_string_new (domain, str);
3537 mono_array_setref (args, i, arg);
3541 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3544 mono_assembly_set_main (method->klass->image->assembly);
3546 return mono_runtime_exec_main (method, args, exc);
3550 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3552 static MonoMethod *serialize_method;
3557 if (!serialize_method) {
3558 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3559 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3562 if (!serialize_method) {
3567 g_assert (!mono_object_class (obj)->marshalbyref);
3571 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3579 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3581 static MonoMethod *deserialize_method;
3586 if (!deserialize_method) {
3587 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3588 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3590 if (!deserialize_method) {
3597 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3605 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3607 static MonoMethod *get_proxy_method;
3609 MonoDomain *domain = mono_domain_get ();
3610 MonoRealProxy *real_proxy;
3611 MonoReflectionType *reflection_type;
3612 MonoTransparentProxy *transparent_proxy;
3614 if (!get_proxy_method)
3615 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3617 g_assert (obj->vtable->klass->marshalbyref);
3619 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3620 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3622 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3623 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3626 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3630 return (MonoObject*) transparent_proxy;
3634 * mono_object_xdomain_representation
3636 * @target_domain: a domain
3637 * @exc: pointer to a MonoObject*
3639 * Creates a representation of obj in the domain target_domain. This
3640 * is either a copy of obj arrived through via serialization and
3641 * deserialization or a proxy, depending on whether the object is
3642 * serializable or marshal by ref. obj must not be in target_domain.
3644 * If the object cannot be represented in target_domain, NULL is
3645 * returned and *exc is set to an appropriate exception.
3648 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3650 MonoObject *deserialized = NULL;
3651 gboolean failure = FALSE;
3655 if (mono_object_class (obj)->marshalbyref) {
3656 deserialized = make_transparent_proxy (obj, &failure, exc);
3658 MonoDomain *domain = mono_domain_get ();
3659 MonoObject *serialized;
3661 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3662 serialized = serialize_object (obj, &failure, exc);
3663 mono_domain_set_internal_with_options (target_domain, FALSE);
3665 deserialized = deserialize_object (serialized, &failure, exc);
3666 if (domain != target_domain)
3667 mono_domain_set_internal_with_options (domain, FALSE);
3670 return deserialized;
3673 /* Used in call_unhandled_exception_delegate */
3675 create_unhandled_exception_eventargs (MonoObject *exc)
3679 MonoMethod *method = NULL;
3680 MonoBoolean is_terminating = TRUE;
3683 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3686 mono_class_init (klass);
3688 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3689 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3693 args [1] = &is_terminating;
3695 obj = mono_object_new (mono_domain_get (), klass);
3696 mono_runtime_invoke (method, obj, args, NULL);
3701 /* Used in mono_unhandled_exception */
3703 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3704 MonoObject *e = NULL;
3706 MonoDomain *current_domain = mono_domain_get ();
3708 if (domain != current_domain)
3709 mono_domain_set_internal_with_options (domain, FALSE);
3711 g_assert (domain == mono_object_domain (domain->domain));
3713 if (mono_object_domain (exc) != domain) {
3714 MonoObject *serialization_exc;
3716 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3718 if (serialization_exc) {
3720 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3723 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3724 "System.Runtime.Serialization", "SerializationException",
3725 "Could not serialize unhandled exception.");
3729 g_assert (mono_object_domain (exc) == domain);
3731 pa [0] = domain->domain;
3732 pa [1] = create_unhandled_exception_eventargs (exc);
3733 mono_runtime_delegate_invoke (delegate, pa, &e);
3735 if (domain != current_domain)
3736 mono_domain_set_internal_with_options (current_domain, FALSE);
3740 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3741 if (!mono_error_ok (&error)) {
3742 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3743 mono_error_cleanup (&error);
3745 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3751 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3754 * mono_runtime_unhandled_exception_policy_set:
3755 * @policy: the new policy
3757 * This is a VM internal routine.
3759 * Sets the runtime policy for handling unhandled exceptions.
3762 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3763 runtime_unhandled_exception_policy = policy;
3767 * mono_runtime_unhandled_exception_policy_get:
3769 * This is a VM internal routine.
3771 * Gets the runtime policy for handling unhandled exceptions.
3773 MonoRuntimeUnhandledExceptionPolicy
3774 mono_runtime_unhandled_exception_policy_get (void) {
3775 return runtime_unhandled_exception_policy;
3779 * mono_unhandled_exception:
3780 * @exc: exception thrown
3782 * This is a VM internal routine.
3784 * We call this function when we detect an unhandled exception
3785 * in the default domain.
3787 * It invokes the * UnhandledException event in AppDomain or prints
3788 * a warning to the console
3791 mono_unhandled_exception (MonoObject *exc)
3793 MonoDomain *current_domain = mono_domain_get ();
3794 MonoDomain *root_domain = mono_get_root_domain ();
3795 MonoClassField *field;
3796 MonoObject *current_appdomain_delegate;
3797 MonoObject *root_appdomain_delegate;
3799 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3800 "UnhandledException");
3803 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3804 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3805 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3806 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3807 if (current_domain != root_domain) {
3808 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3810 current_appdomain_delegate = NULL;
3813 /* set exitcode only if we will abort the process */
3815 mono_environment_exitcode_set (1);
3816 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3817 mono_print_unhandled_exception (exc);
3819 if (root_appdomain_delegate) {
3820 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3822 if (current_appdomain_delegate) {
3823 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3830 * mono_runtime_exec_managed_code:
3831 * @domain: Application domain
3832 * @main_func: function to invoke from the execution thread
3833 * @main_args: parameter to the main_func
3835 * Launch a new thread to execute a function
3837 * main_func is called back from the thread with main_args as the
3838 * parameter. The callback function is expected to start Main()
3839 * eventually. This function then waits for all managed threads to
3841 * It is not necesseray anymore to execute managed code in a subthread,
3842 * so this function should not be used anymore by default: just
3843 * execute the code and then call mono_thread_manage ().
3846 mono_runtime_exec_managed_code (MonoDomain *domain,
3847 MonoMainThreadFunc main_func,
3850 mono_thread_create (domain, main_func, main_args);
3852 mono_thread_manage ();
3856 * Execute a standard Main() method (args doesn't contain the
3860 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3865 MonoCustomAttrInfo* cinfo;
3866 gboolean has_stathread_attribute;
3867 MonoInternalThread* thread = mono_thread_internal_current ();
3873 domain = mono_object_domain (args);
3874 if (!domain->entry_assembly) {
3876 MonoAssembly *assembly;
3878 assembly = method->klass->image->assembly;
3879 domain->entry_assembly = assembly;
3880 /* Domains created from another domain already have application_base and configuration_file set */
3881 if (domain->setup->application_base == NULL) {
3882 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3885 if (domain->setup->configuration_file == NULL) {
3886 str = g_strconcat (assembly->image->name, ".config", NULL);
3887 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3889 mono_set_private_bin_path_from_config (domain);
3893 cinfo = mono_custom_attrs_from_method (method);
3895 static MonoClass *stathread_attribute = NULL;
3896 if (!stathread_attribute)
3897 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3898 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3900 mono_custom_attrs_free (cinfo);
3902 has_stathread_attribute = FALSE;
3904 if (has_stathread_attribute) {
3905 thread->apartment_state = ThreadApartmentState_STA;
3907 thread->apartment_state = ThreadApartmentState_MTA;
3909 mono_thread_init_apartment_state ();
3911 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3913 /* FIXME: check signature of method */
3914 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3916 res = mono_runtime_invoke (method, NULL, pa, exc);
3918 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3922 mono_environment_exitcode_set (rval);
3924 mono_runtime_invoke (method, NULL, pa, exc);
3928 /* If the return type of Main is void, only
3929 * set the exitcode if an exception was thrown
3930 * (we don't want to blow away an
3931 * explicitly-set exit code)
3934 mono_environment_exitcode_set (rval);
3938 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3944 * mono_install_runtime_invoke:
3945 * @func: Function to install
3947 * This is a VM internal routine
3950 mono_install_runtime_invoke (MonoInvokeFunc func)
3952 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3957 * mono_runtime_invoke_array:
3958 * @method: method to invoke
3959 * @obJ: object instance
3960 * @params: arguments to the method
3961 * @exc: exception information.
3963 * Invokes the method represented by @method on the object @obj.
3965 * obj is the 'this' pointer, it should be NULL for static
3966 * methods, a MonoObject* for object instances and a pointer to
3967 * the value type for value types.
3969 * The params array contains the arguments to the method with the
3970 * same convention: MonoObject* pointers for object instances and
3971 * pointers to the value type otherwise. The _invoke_array
3972 * variant takes a C# object[] as the params argument (MonoArray
3973 * *params): in this case the value types are boxed inside the
3974 * respective reference representation.
3976 * From unmanaged code you'll usually use the
3977 * mono_runtime_invoke() variant.
3979 * Note that this function doesn't handle virtual methods for
3980 * you, it will exec the exact method you pass: we still need to
3981 * expose a function to lookup the derived class implementation
3982 * of a virtual method (there are examples of this in the code,
3985 * You can pass NULL as the exc argument if you don't want to
3986 * catch exceptions, otherwise, *exc will be set to the exception
3987 * thrown, if any. if an exception is thrown, you can't use the
3988 * MonoObject* result from the function.
3990 * If the method returns a value type, it is boxed in an object
3994 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3997 MonoMethodSignature *sig = mono_method_signature (method);
3998 gpointer *pa = NULL;
4001 gboolean has_byref_nullables = FALSE;
4003 if (NULL != params) {
4004 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4005 for (i = 0; i < mono_array_length (params); i++) {
4006 MonoType *t = sig->params [i];
4012 case MONO_TYPE_BOOLEAN:
4015 case MONO_TYPE_CHAR:
4024 case MONO_TYPE_VALUETYPE:
4025 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4026 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4027 pa [i] = mono_array_get (params, MonoObject*, i);
4029 has_byref_nullables = TRUE;
4031 /* MS seems to create the objects if a null is passed in */
4032 if (!mono_array_get (params, MonoObject*, i))
4033 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4037 * We can't pass the unboxed vtype byref to the callee, since
4038 * that would mean the callee would be able to modify boxed
4039 * primitive types. So we (and MS) make a copy of the boxed
4040 * object, pass that to the callee, and replace the original
4041 * boxed object in the arg array with the copy.
4043 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4044 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4045 mono_array_setref (params, i, copy);
4048 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4051 case MONO_TYPE_STRING:
4052 case MONO_TYPE_OBJECT:
4053 case MONO_TYPE_CLASS:
4054 case MONO_TYPE_ARRAY:
4055 case MONO_TYPE_SZARRAY:
4057 pa [i] = mono_array_addr (params, MonoObject*, i);
4058 // FIXME: I need to check this code path
4060 pa [i] = mono_array_get (params, MonoObject*, i);
4062 case MONO_TYPE_GENERICINST:
4064 t = &t->data.generic_class->container_class->this_arg;
4066 t = &t->data.generic_class->container_class->byval_arg;
4068 case MONO_TYPE_PTR: {
4071 /* The argument should be an IntPtr */
4072 arg = mono_array_get (params, MonoObject*, i);
4076 g_assert (arg->vtable->klass == mono_defaults.int_class);
4077 pa [i] = ((MonoIntPtr*)arg)->m_value;
4082 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4087 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4090 if (mono_class_is_nullable (method->klass)) {
4091 /* Need to create a boxed vtype instead */
4097 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4101 obj = mono_object_new (mono_domain_get (), method->klass);
4102 g_assert (obj); /*maybe we should raise a TLE instead?*/
4103 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4104 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4106 if (method->klass->valuetype)
4107 o = mono_object_unbox (obj);
4110 } else if (method->klass->valuetype) {
4111 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4114 mono_runtime_invoke (method, o, pa, exc);
4117 if (mono_class_is_nullable (method->klass)) {
4118 MonoObject *nullable;
4120 /* Convert the unboxed vtype into a Nullable structure */
4121 nullable = mono_object_new (mono_domain_get (), method->klass);
4123 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4124 obj = mono_object_unbox (nullable);
4127 /* obj must be already unboxed if needed */
4128 res = mono_runtime_invoke (method, obj, pa, exc);
4130 if (sig->ret->type == MONO_TYPE_PTR) {
4131 MonoClass *pointer_class;
4132 static MonoMethod *box_method;
4134 MonoObject *box_exc;
4137 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4138 * convert it to a Pointer object.
4140 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4142 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4144 g_assert (res->vtable->klass == mono_defaults.int_class);
4145 box_args [0] = ((MonoIntPtr*)res)->m_value;
4146 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4147 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4148 g_assert (!box_exc);
4151 if (has_byref_nullables) {
4153 * The runtime invoke wrapper already converted byref nullables back,
4154 * and stored them in pa, we just need to copy them back to the
4157 for (i = 0; i < mono_array_length (params); i++) {
4158 MonoType *t = sig->params [i];
4160 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4161 mono_array_setref (params, i, pa [i]);
4170 arith_overflow (void)
4172 mono_raise_exception (mono_get_exception_overflow ());
4176 * mono_object_allocate:
4177 * @size: number of bytes to allocate
4179 * This is a very simplistic routine until we have our GC-aware
4182 * Returns: an allocated object of size @size, or NULL on failure.
4184 static inline void *
4185 mono_object_allocate (size_t size, MonoVTable *vtable)
4188 mono_stats.new_object_count++;
4189 ALLOC_OBJECT (o, vtable, size);
4195 * mono_object_allocate_ptrfree:
4196 * @size: number of bytes to allocate
4198 * Note that the memory allocated is not zeroed.
4199 * Returns: an allocated object of size @size, or NULL on failure.
4201 static inline void *
4202 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4205 mono_stats.new_object_count++;
4206 ALLOC_PTRFREE (o, vtable, size);
4210 static inline void *
4211 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4214 ALLOC_TYPED (o, size, vtable);
4215 mono_stats.new_object_count++;
4222 * @klass: the class of the object that we want to create
4224 * Returns: a newly created object whose definition is
4225 * looked up using @klass. This will not invoke any constructors,
4226 * so the consumer of this routine has to invoke any constructors on
4227 * its own to initialize the object.
4229 * It returns NULL on failure.
4232 mono_object_new (MonoDomain *domain, MonoClass *klass)
4236 MONO_ARCH_SAVE_REGS;
4237 vtable = mono_class_vtable (domain, klass);
4240 return mono_object_new_specific (vtable);
4244 * mono_object_new_pinned:
4246 * Same as mono_object_new, but the returned object will be pinned.
4247 * For SGEN, these objects will only be freed at appdomain unload.
4250 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4254 MONO_ARCH_SAVE_REGS;
4255 vtable = mono_class_vtable (domain, klass);
4260 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4262 return mono_object_new_specific (vtable);
4267 * mono_object_new_specific:
4268 * @vtable: the vtable of the object that we want to create
4270 * Returns: A newly created object with class and domain specified
4274 mono_object_new_specific (MonoVTable *vtable)
4278 MONO_ARCH_SAVE_REGS;
4280 /* check for is_com_object for COM Interop */
4281 if (vtable->remote || vtable->klass->is_com_object)
4284 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4287 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4290 mono_class_init (klass);
4292 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4294 vtable->domain->create_proxy_for_type_method = im;
4297 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4299 o = mono_runtime_invoke (im, NULL, pa, NULL);
4300 if (o != NULL) return o;
4303 return mono_object_new_alloc_specific (vtable);
4307 mono_object_new_alloc_specific (MonoVTable *vtable)
4311 if (!vtable->klass->has_references) {
4312 o = mono_object_new_ptrfree (vtable);
4313 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4314 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4316 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4317 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4319 if (G_UNLIKELY (vtable->klass->has_finalize))
4320 mono_object_register_finalizer (o);
4322 if (G_UNLIKELY (profile_allocs))
4323 mono_profiler_allocation (o, vtable->klass);
4328 mono_object_new_fast (MonoVTable *vtable)
4331 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4336 mono_object_new_ptrfree (MonoVTable *vtable)
4339 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4340 #if NEED_TO_ZERO_PTRFREE
4341 /* an inline memset is much faster for the common vcase of small objects
4342 * note we assume the allocated size is a multiple of sizeof (void*).
4344 if (vtable->klass->instance_size < 128) {
4346 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4347 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4353 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4360 mono_object_new_ptrfree_box (MonoVTable *vtable)
4363 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4364 /* the object will be boxed right away, no need to memzero it */
4369 * mono_class_get_allocation_ftn:
4371 * @for_box: the object will be used for boxing
4372 * @pass_size_in_words:
4374 * Return the allocation function appropriate for the given class.
4378 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4380 *pass_size_in_words = FALSE;
4382 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4383 profile_allocs = FALSE;
4385 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4386 return mono_object_new_specific;
4388 if (!vtable->klass->has_references) {
4389 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4391 return mono_object_new_ptrfree_box;
4392 return mono_object_new_ptrfree;
4395 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4397 return mono_object_new_fast;
4400 * FIXME: This is actually slower than mono_object_new_fast, because
4401 * of the overhead of parameter passing.
4404 *pass_size_in_words = TRUE;
4405 #ifdef GC_REDIRECT_TO_LOCAL
4406 return GC_local_gcj_fast_malloc;
4408 return GC_gcj_fast_malloc;
4413 return mono_object_new_specific;
4417 * mono_object_new_from_token:
4418 * @image: Context where the type_token is hosted
4419 * @token: a token of the type that we want to create
4421 * Returns: A newly created object whose definition is
4422 * looked up using @token in the @image image
4425 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4429 class = mono_class_get (image, token);
4431 return mono_object_new (domain, class);
4436 * mono_object_clone:
4437 * @obj: the object to clone
4439 * Returns: A newly created object who is a shallow copy of @obj
4442 mono_object_clone (MonoObject *obj)
4445 int size = obj->vtable->klass->instance_size;
4447 o = mono_object_allocate (size, obj->vtable);
4449 if (obj->vtable->klass->has_references) {
4450 mono_gc_wbarrier_object_copy (o, obj);
4452 int size = obj->vtable->klass->instance_size;
4453 /* do not copy the sync state */
4454 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4456 if (G_UNLIKELY (profile_allocs))
4457 mono_profiler_allocation (o, obj->vtable->klass);
4459 if (obj->vtable->klass->has_finalize)
4460 mono_object_register_finalizer (o);
4465 * mono_array_full_copy:
4466 * @src: source array to copy
4467 * @dest: destination array
4469 * Copies the content of one array to another with exactly the same type and size.
4472 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4475 MonoClass *klass = src->obj.vtable->klass;
4477 MONO_ARCH_SAVE_REGS;
4479 g_assert (klass == dest->obj.vtable->klass);
4481 size = mono_array_length (src);
4482 g_assert (size == mono_array_length (dest));
4483 size *= mono_array_element_size (klass);
4485 if (klass->element_class->valuetype) {
4486 if (klass->element_class->has_references)
4487 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4489 memcpy (&dest->vector, &src->vector, size);
4491 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4494 memcpy (&dest->vector, &src->vector, size);
4499 * mono_array_clone_in_domain:
4500 * @domain: the domain in which the array will be cloned into
4501 * @array: the array to clone
4503 * This routine returns a copy of the array that is hosted on the
4504 * specified MonoDomain.
4507 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4512 MonoClass *klass = array->obj.vtable->klass;
4514 MONO_ARCH_SAVE_REGS;
4516 if (array->bounds == NULL) {
4517 size = mono_array_length (array);
4518 o = mono_array_new_full (domain, klass, &size, NULL);
4520 size *= mono_array_element_size (klass);
4522 if (klass->element_class->valuetype) {
4523 if (klass->element_class->has_references)
4524 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4526 memcpy (&o->vector, &array->vector, size);
4528 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4531 memcpy (&o->vector, &array->vector, size);
4536 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4537 size = mono_array_element_size (klass);
4538 for (i = 0; i < klass->rank; ++i) {
4539 sizes [i] = array->bounds [i].length;
4540 size *= array->bounds [i].length;
4541 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4543 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4545 if (klass->element_class->valuetype) {
4546 if (klass->element_class->has_references)
4547 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4549 memcpy (&o->vector, &array->vector, size);
4551 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4554 memcpy (&o->vector, &array->vector, size);
4562 * @array: the array to clone
4564 * Returns: A newly created array who is a shallow copy of @array
4567 mono_array_clone (MonoArray *array)
4569 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4572 /* helper macros to check for overflow when calculating the size of arrays */
4573 #ifdef MONO_BIG_ARRAYS
4574 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4575 #define MYGUINT_MAX MYGUINT64_MAX
4576 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4577 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4578 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4579 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4580 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4582 #define MYGUINT32_MAX 4294967295U
4583 #define MYGUINT_MAX MYGUINT32_MAX
4584 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4585 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4586 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4587 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4588 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4592 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4596 byte_len = mono_array_element_size (class);
4597 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4600 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4602 byte_len += sizeof (MonoArray);
4610 * mono_array_new_full:
4611 * @domain: domain where the object is created
4612 * @array_class: array class
4613 * @lengths: lengths for each dimension in the array
4614 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4616 * This routine creates a new array objects with the given dimensions,
4617 * lower bounds and type.
4620 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4622 uintptr_t byte_len, len, bounds_size;
4625 MonoArrayBounds *bounds;
4629 if (!array_class->inited)
4630 mono_class_init (array_class);
4634 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4635 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4637 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4641 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4643 for (i = 0; i < array_class->rank; ++i) {
4644 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4646 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4647 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4652 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4653 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4657 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4658 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4659 byte_len = (byte_len + 3) & ~3;
4660 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4661 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4662 byte_len += bounds_size;
4665 * Following three lines almost taken from mono_object_new ():
4666 * they need to be kept in sync.
4668 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4669 #ifndef HAVE_SGEN_GC
4670 if (!array_class->has_references) {
4671 o = mono_object_allocate_ptrfree (byte_len, vtable);
4672 #if NEED_TO_ZERO_PTRFREE
4673 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4675 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4676 o = mono_object_allocate_spec (byte_len, vtable);
4678 o = mono_object_allocate (byte_len, vtable);
4681 array = (MonoArray*)o;
4682 array->max_length = len;
4685 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4686 array->bounds = bounds;
4690 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4692 o = mono_gc_alloc_vector (vtable, byte_len, len);
4693 array = (MonoArray*)o;
4694 mono_stats.new_object_count++;
4696 bounds = array->bounds;
4700 for (i = 0; i < array_class->rank; ++i) {
4701 bounds [i].length = lengths [i];
4703 bounds [i].lower_bound = lower_bounds [i];
4707 if (G_UNLIKELY (profile_allocs))
4708 mono_profiler_allocation (o, array_class);
4715 * @domain: domain where the object is created
4716 * @eclass: element class
4717 * @n: number of array elements
4719 * This routine creates a new szarray with @n elements of type @eclass.
4722 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4726 MONO_ARCH_SAVE_REGS;
4728 ac = mono_array_class_get (eclass, 1);
4731 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4735 * mono_array_new_specific:
4736 * @vtable: a vtable in the appropriate domain for an initialized class
4737 * @n: number of array elements
4739 * This routine is a fast alternative to mono_array_new() for code which
4740 * can be sure about the domain it operates in.
4743 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4749 MONO_ARCH_SAVE_REGS;
4751 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4756 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4757 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4760 #ifndef HAVE_SGEN_GC
4761 if (!vtable->klass->has_references) {
4762 o = mono_object_allocate_ptrfree (byte_len, vtable);
4763 #if NEED_TO_ZERO_PTRFREE
4764 ((MonoArray*)o)->bounds = NULL;
4765 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4767 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4768 o = mono_object_allocate_spec (byte_len, vtable);
4770 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4771 o = mono_object_allocate (byte_len, vtable);
4774 ao = (MonoArray *)o;
4777 o = mono_gc_alloc_vector (vtable, byte_len, n);
4779 mono_stats.new_object_count++;
4782 if (G_UNLIKELY (profile_allocs))
4783 mono_profiler_allocation (o, vtable->klass);
4789 * mono_string_new_utf16:
4790 * @text: a pointer to an utf16 string
4791 * @len: the length of the string
4793 * Returns: A newly created string object which contains @text.
4796 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4800 s = mono_string_new_size (domain, len);
4801 g_assert (s != NULL);
4803 memcpy (mono_string_chars (s), text, len * 2);
4809 * mono_string_new_size:
4810 * @text: a pointer to an utf16 string
4811 * @len: the length of the string
4813 * Returns: A newly created string object of @len
4816 mono_string_new_size (MonoDomain *domain, gint32 len)
4820 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4822 /* overflow ? can't fit it, can't allocate it! */
4824 mono_gc_out_of_memory (-1);
4826 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4829 #ifndef HAVE_SGEN_GC
4830 s = mono_object_allocate_ptrfree (size, vtable);
4834 s = mono_gc_alloc_string (vtable, size, len);
4836 #if NEED_TO_ZERO_PTRFREE
4839 if (G_UNLIKELY (profile_allocs))
4840 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4846 * mono_string_new_len:
4847 * @text: a pointer to an utf8 string
4848 * @length: number of bytes in @text to consider
4850 * Returns: A newly created string object which contains @text.
4853 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4855 GError *error = NULL;
4856 MonoString *o = NULL;
4858 glong items_written;
4860 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4863 o = mono_string_new_utf16 (domain, ut, items_written);
4865 g_error_free (error);
4874 * @text: a pointer to an utf8 string
4876 * Returns: A newly created string object which contains @text.
4879 mono_string_new (MonoDomain *domain, const char *text)
4881 GError *error = NULL;
4882 MonoString *o = NULL;
4884 glong items_written;
4889 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4892 o = mono_string_new_utf16 (domain, ut, items_written);
4894 g_error_free (error);
4897 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4902 MonoString *o = NULL;
4904 if (!g_utf8_validate (text, -1, &end))
4907 len = g_utf8_strlen (text, -1);
4908 o = mono_string_new_size (domain, len);
4909 str = mono_string_chars (o);
4911 while (text < end) {
4912 *str++ = g_utf8_get_char (text);
4913 text = g_utf8_next_char (text);
4920 * mono_string_new_wrapper:
4921 * @text: pointer to utf8 characters.
4923 * Helper function to create a string object from @text in the current domain.
4926 mono_string_new_wrapper (const char *text)
4928 MonoDomain *domain = mono_domain_get ();
4930 MONO_ARCH_SAVE_REGS;
4933 return mono_string_new (domain, text);
4940 * @class: the class of the value
4941 * @value: a pointer to the unboxed data
4943 * Returns: A newly created object which contains @value.
4946 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4952 g_assert (class->valuetype);
4953 if (mono_class_is_nullable (class))
4954 return mono_nullable_box (value, class);
4956 vtable = mono_class_vtable (domain, class);
4959 size = mono_class_instance_size (class);
4960 res = mono_object_new_alloc_specific (vtable);
4961 if (G_UNLIKELY (profile_allocs))
4962 mono_profiler_allocation (res, class);
4964 size = size - sizeof (MonoObject);
4967 g_assert (size == mono_class_value_size (class, NULL));
4968 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4970 #if NO_UNALIGNED_ACCESS
4971 memcpy ((char *)res + sizeof (MonoObject), value, size);
4975 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4978 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4981 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4984 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4987 memcpy ((char *)res + sizeof (MonoObject), value, size);
4991 if (class->has_finalize)
4992 mono_object_register_finalizer (res);
4998 * @dest: destination pointer
4999 * @src: source pointer
5000 * @klass: a valuetype class
5002 * Copy a valuetype from @src to @dest. This function must be used
5003 * when @klass contains references fields.
5006 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5008 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5012 * mono_value_copy_array:
5013 * @dest: destination array
5014 * @dest_idx: index in the @dest array
5015 * @src: source pointer
5016 * @count: number of items
5018 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5019 * This function must be used when @klass contains references fields.
5020 * Overlap is handled.
5023 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5025 int size = mono_array_element_size (dest->obj.vtable->klass);
5026 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5027 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5028 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5032 * mono_object_get_domain:
5033 * @obj: object to query
5035 * Returns: the MonoDomain where the object is hosted
5038 mono_object_get_domain (MonoObject *obj)
5040 return mono_object_domain (obj);
5044 * mono_object_get_class:
5045 * @obj: object to query
5047 * Returns: the MonOClass of the object.
5050 mono_object_get_class (MonoObject *obj)
5052 return mono_object_class (obj);
5055 * mono_object_get_size:
5056 * @o: object to query
5058 * Returns: the size, in bytes, of @o
5061 mono_object_get_size (MonoObject* o)
5063 MonoClass* klass = mono_object_class (o);
5064 if (klass == mono_defaults.string_class) {
5065 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5066 } else if (o->vtable->rank) {
5067 MonoArray *array = (MonoArray*)o;
5068 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5069 if (array->bounds) {
5072 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5076 return mono_class_instance_size (klass);
5081 * mono_object_unbox:
5082 * @obj: object to unbox
5084 * Returns: a pointer to the start of the valuetype boxed in this
5087 * This method will assert if the object passed is not a valuetype.
5090 mono_object_unbox (MonoObject *obj)
5092 /* add assert for valuetypes? */
5093 g_assert (obj->vtable->klass->valuetype);
5094 return ((char*)obj) + sizeof (MonoObject);
5098 * mono_object_isinst:
5100 * @klass: a pointer to a class
5102 * Returns: @obj if @obj is derived from @klass
5105 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5108 mono_class_init (klass);
5110 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5111 return mono_object_isinst_mbyref (obj, klass);
5116 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5120 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5129 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5130 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5134 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5135 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5138 MonoClass *oklass = vt->klass;
5139 if ((oklass == mono_defaults.transparent_proxy_class))
5140 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5142 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5146 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5148 MonoDomain *domain = mono_domain_get ();
5150 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5151 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5152 MonoMethod *im = NULL;
5155 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5156 im = mono_object_get_virtual_method (rp, im);
5159 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5162 res = mono_runtime_invoke (im, rp, pa, NULL);
5164 if (*(MonoBoolean *) mono_object_unbox(res)) {
5165 /* Update the vtable of the remote type, so it can safely cast to this new type */
5166 mono_upgrade_remote_class (domain, obj, klass);
5175 * mono_object_castclass_mbyref:
5177 * @klass: a pointer to a class
5179 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5182 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5184 if (!obj) return NULL;
5185 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5187 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5189 "InvalidCastException"));
5194 MonoDomain *orig_domain;
5200 str_lookup (MonoDomain *domain, gpointer user_data)
5202 LDStrInfo *info = user_data;
5203 if (info->res || domain == info->orig_domain)
5205 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5211 mono_string_get_pinned (MonoString *str)
5215 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5216 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5218 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5219 news->length = mono_string_length (str);
5225 #define mono_string_get_pinned(str) (str)
5229 mono_string_is_interned_lookup (MonoString *str, int insert)
5231 MonoGHashTable *ldstr_table;
5235 domain = ((MonoObject *)str)->vtable->domain;
5236 ldstr_table = domain->ldstr_table;
5238 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5243 str = mono_string_get_pinned (str);
5245 mono_g_hash_table_insert (ldstr_table, str, str);
5249 LDStrInfo ldstr_info;
5250 ldstr_info.orig_domain = domain;
5251 ldstr_info.ins = str;
5252 ldstr_info.res = NULL;
5254 mono_domain_foreach (str_lookup, &ldstr_info);
5255 if (ldstr_info.res) {
5257 * the string was already interned in some other domain:
5258 * intern it in the current one as well.
5260 mono_g_hash_table_insert (ldstr_table, str, str);
5270 * mono_string_is_interned:
5271 * @o: String to probe
5273 * Returns whether the string has been interned.
5276 mono_string_is_interned (MonoString *o)
5278 return mono_string_is_interned_lookup (o, FALSE);
5282 * mono_string_intern:
5283 * @o: String to intern
5285 * Interns the string passed.
5286 * Returns: The interned string.
5289 mono_string_intern (MonoString *str)
5291 return mono_string_is_interned_lookup (str, TRUE);
5296 * @domain: the domain where the string will be used.
5297 * @image: a metadata context
5298 * @idx: index into the user string table.
5300 * Implementation for the ldstr opcode.
5301 * Returns: a loaded string from the @image/@idx combination.
5304 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5306 MONO_ARCH_SAVE_REGS;
5308 if (image->dynamic) {
5309 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5312 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5313 return NULL; /*FIXME we should probably be raising an exception here*/
5314 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5319 * mono_ldstr_metadata_sig
5320 * @domain: the domain for the string
5321 * @sig: the signature of a metadata string
5323 * Returns: a MonoString for a string stored in the metadata
5326 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5328 const char *str = sig;
5329 MonoString *o, *interned;
5332 len2 = mono_metadata_decode_blob_size (str, &str);
5335 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5336 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5339 guint16 *p2 = (guint16*)mono_string_chars (o);
5340 for (i = 0; i < len2; ++i) {
5341 *p2 = GUINT16_FROM_LE (*p2);
5347 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5349 /* o will get garbage collected */
5353 o = mono_string_get_pinned (o);
5355 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5362 * mono_string_to_utf8:
5363 * @s: a System.String
5365 * Returns the UTF8 representation for @s.
5366 * The resulting buffer needs to be freed with mono_free().
5368 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5371 mono_string_to_utf8 (MonoString *s)
5374 char *result = mono_string_to_utf8_checked (s, &error);
5376 if (!mono_error_ok (&error))
5377 mono_error_raise_exception (&error);
5382 * mono_string_to_utf8_checked:
5383 * @s: a System.String
5384 * @error: a MonoError.
5386 * Converts a MonoString to its UTF8 representation. May fail; check
5387 * @error to determine whether the conversion was successful.
5388 * The resulting buffer should be freed with mono_free().
5391 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5395 GError *gerror = NULL;
5397 mono_error_init (error);
5403 return g_strdup ("");
5405 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5407 mono_error_set_argument (error, "string", "%s", gerror->message);
5408 g_error_free (gerror);
5411 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5412 if (s->length > written) {
5413 /* allocate the total length and copy the part of the string that has been converted */
5414 char *as2 = g_malloc0 (s->length);
5415 memcpy (as2, as, written);
5424 * mono_string_to_utf8_ignore:
5427 * Converts a MonoString to its UTF8 representation. Will ignore
5428 * invalid surrogate pairs.
5429 * The resulting buffer should be freed with mono_free().
5433 mono_string_to_utf8_ignore (MonoString *s)
5442 return g_strdup ("");
5444 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5446 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5447 if (s->length > written) {
5448 /* allocate the total length and copy the part of the string that has been converted */
5449 char *as2 = g_malloc0 (s->length);
5450 memcpy (as2, as, written);
5459 * mono_string_to_utf8_image_ignore:
5460 * @s: a System.String
5462 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5465 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5467 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5471 * mono_string_to_utf8_mp_ignore:
5472 * @s: a System.String
5474 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5477 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5479 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5484 * mono_string_to_utf16:
5487 * Return an null-terminated array of the utf-16 chars
5488 * contained in @s. The result must be freed with g_free().
5489 * This is a temporary helper until our string implementation
5490 * is reworked to always include the null terminating char.
5493 mono_string_to_utf16 (MonoString *s)
5500 as = g_malloc ((s->length * 2) + 2);
5501 as [(s->length * 2)] = '\0';
5502 as [(s->length * 2) + 1] = '\0';
5505 return (gunichar2 *)(as);
5508 memcpy (as, mono_string_chars(s), s->length * 2);
5509 return (gunichar2 *)(as);
5513 * mono_string_from_utf16:
5514 * @data: the UTF16 string (LPWSTR) to convert
5516 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5518 * Returns: a MonoString.
5521 mono_string_from_utf16 (gunichar2 *data)
5523 MonoDomain *domain = mono_domain_get ();
5529 while (data [len]) len++;
5531 return mono_string_new_utf16 (domain, data, len);
5536 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5543 r = mono_string_to_utf8_ignore (s);
5545 r = mono_string_to_utf8_checked (s, error);
5546 if (!mono_error_ok (error))
5553 len = strlen (r) + 1;
5555 mp_s = mono_mempool_alloc (mp, len);
5557 mp_s = mono_image_alloc (image, len);
5559 memcpy (mp_s, r, len);
5567 * mono_string_to_utf8_image:
5568 * @s: a System.String
5570 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5573 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5575 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5579 * mono_string_to_utf8_mp:
5580 * @s: a System.String
5582 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5585 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5587 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5591 default_ex_handler (MonoException *ex)
5593 MonoObject *o = (MonoObject*)ex;
5594 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5598 static MonoExceptionFunc ex_handler = default_ex_handler;
5601 * mono_install_handler:
5602 * @func: exception handler
5604 * This is an internal JIT routine used to install the handler for exceptions
5608 mono_install_handler (MonoExceptionFunc func)
5610 ex_handler = func? func: default_ex_handler;
5614 * mono_raise_exception:
5615 * @ex: exception object
5617 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5620 mono_raise_exception (MonoException *ex)
5623 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5624 * that will cause gcc to omit the function epilog, causing problems when
5625 * the JIT tries to walk the stack, since the return address on the stack
5626 * will point into the next function in the executable, not this one.
5629 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5630 MonoInternalThread *thread = mono_thread_internal_current ();
5631 g_assert (ex->object.vtable->domain == mono_domain_get ());
5632 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5639 * mono_wait_handle_new:
5640 * @domain: Domain where the object will be created
5641 * @handle: Handle for the wait handle
5643 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5646 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5648 MonoWaitHandle *res;
5649 gpointer params [1];
5650 static MonoMethod *handle_set;
5652 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5654 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5656 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5658 params [0] = &handle;
5659 mono_runtime_invoke (handle_set, res, params, NULL);
5665 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5667 static MonoClassField *f_os_handle;
5668 static MonoClassField *f_safe_handle;
5670 if (!f_os_handle && !f_safe_handle) {
5671 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5672 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5677 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5681 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5688 mono_runtime_capture_context (MonoDomain *domain)
5690 RuntimeInvokeFunction runtime_invoke;
5692 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5693 MonoMethod *method = mono_get_context_capture_method ();
5694 MonoMethod *wrapper;
5697 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5698 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5699 domain->capture_context_method = mono_compile_method (method);
5702 runtime_invoke = domain->capture_context_runtime_invoke;
5704 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5707 * mono_async_result_new:
5708 * @domain:domain where the object will be created.
5709 * @handle: wait handle.
5710 * @state: state to pass to AsyncResult
5711 * @data: C closure data.
5713 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5714 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5718 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5720 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5721 MonoObject *context = mono_runtime_capture_context (domain);
5722 /* we must capture the execution context from the original thread */
5724 MONO_OBJECT_SETREF (res, execution_context, context);
5725 /* note: result may be null if the flow is suppressed */
5729 MONO_OBJECT_SETREF (res, object_data, object_data);
5730 MONO_OBJECT_SETREF (res, async_state, state);
5732 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5734 res->sync_completed = FALSE;
5735 res->completed = FALSE;
5741 mono_message_init (MonoDomain *domain,
5742 MonoMethodMessage *this,
5743 MonoReflectionMethod *method,
5744 MonoArray *out_args)
5746 static MonoClass *object_array_klass;
5747 static MonoClass *byte_array_klass;
5748 static MonoClass *string_array_klass;
5749 MonoMethodSignature *sig = mono_method_signature (method->method);
5755 if (!object_array_klass) {
5758 klass = mono_array_class_get (mono_defaults.object_class, 1);
5761 mono_memory_barrier ();
5762 object_array_klass = klass;
5764 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5767 mono_memory_barrier ();
5768 byte_array_klass = klass;
5770 klass = mono_array_class_get (mono_defaults.string_class, 1);
5773 mono_memory_barrier ();
5774 string_array_klass = klass;
5777 MONO_OBJECT_SETREF (this, method, method);
5779 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5780 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5781 this->async_result = NULL;
5782 this->call_type = CallType_Sync;
5784 names = g_new (char *, sig->param_count);
5785 mono_method_get_param_names (method->method, (const char **) names);
5786 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5788 for (i = 0; i < sig->param_count; i++) {
5789 name = mono_string_new (domain, names [i]);
5790 mono_array_setref (this->names, i, name);
5794 for (i = 0, j = 0; i < sig->param_count; i++) {
5795 if (sig->params [i]->byref) {
5797 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5798 mono_array_setref (this->args, i, arg);
5802 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5806 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5809 mono_array_set (this->arg_types, guint8, i, arg_type);
5814 * mono_remoting_invoke:
5815 * @real_proxy: pointer to a RealProxy object
5816 * @msg: The MonoMethodMessage to execute
5817 * @exc: used to store exceptions
5818 * @out_args: used to store output arguments
5820 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5821 * IMessage interface and it is not trivial to extract results from there. So
5822 * we call an helper method PrivateInvoke instead of calling
5823 * RealProxy::Invoke() directly.
5825 * Returns: the result object.
5828 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5829 MonoObject **exc, MonoArray **out_args)
5831 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5834 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5837 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5839 real_proxy->vtable->domain->private_invoke_method = im;
5842 pa [0] = real_proxy;
5847 return mono_runtime_invoke (im, NULL, pa, exc);
5851 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5852 MonoObject **exc, MonoArray **out_args)
5854 static MonoClass *object_array_klass;
5857 MonoMethodSignature *sig;
5859 int i, j, outarg_count = 0;
5861 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5863 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5864 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5865 target = tp->rp->unwrapped_server;
5867 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5871 domain = mono_domain_get ();
5872 method = msg->method->method;
5873 sig = mono_method_signature (method);
5875 for (i = 0; i < sig->param_count; i++) {
5876 if (sig->params [i]->byref)
5880 if (!object_array_klass) {
5883 klass = mono_array_class_get (mono_defaults.object_class, 1);
5886 mono_memory_barrier ();
5887 object_array_klass = klass;
5890 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5891 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5894 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5896 for (i = 0, j = 0; i < sig->param_count; i++) {
5897 if (sig->params [i]->byref) {
5899 arg = mono_array_get (msg->args, gpointer, i);
5900 mono_array_setref (*out_args, j, arg);
5909 * mono_object_to_string:
5911 * @exc: Any exception thrown by ToString (). May be NULL.
5913 * Returns: the result of calling ToString () on an object.
5916 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5918 static MonoMethod *to_string = NULL;
5924 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5926 method = mono_object_get_virtual_method (obj, to_string);
5928 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5932 * mono_print_unhandled_exception:
5933 * @exc: The exception
5935 * Prints the unhandled exception.
5938 mono_print_unhandled_exception (MonoObject *exc)
5941 char *message = (char*)"";
5942 gboolean free_message = FALSE;
5945 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5946 message = g_strdup ("OutOfMemoryException");
5948 str = mono_object_to_string (exc, NULL);
5950 message = mono_string_to_utf8_checked (str, &error);
5951 if (!mono_error_ok (&error)) {
5952 mono_error_cleanup (&error);
5953 message = (char *) "";
5955 free_message = TRUE;
5961 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5962 * exc->vtable->klass->name, message);
5964 g_printerr ("\nUnhandled Exception: %s\n", message);
5971 * mono_delegate_ctor:
5972 * @this: pointer to an uninitialized delegate object
5973 * @target: target object
5974 * @addr: pointer to native code
5977 * Initialize a delegate and sets a specific method, not the one
5978 * associated with addr. This is useful when sharing generic code.
5979 * In that case addr will most probably not be associated with the
5980 * correct instantiation of the method.
5983 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5985 MonoDelegate *delegate = (MonoDelegate *)this;
5992 delegate->method = method;
5994 class = this->vtable->klass;
5995 mono_stats.delegate_creations++;
5997 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5999 method = mono_marshal_get_remoting_invoke (method);
6000 delegate->method_ptr = mono_compile_method (method);
6001 MONO_OBJECT_SETREF (delegate, target, target);
6002 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6003 method = mono_marshal_get_unbox_wrapper (method);
6004 delegate->method_ptr = mono_compile_method (method);
6005 MONO_OBJECT_SETREF (delegate, target, target);
6007 delegate->method_ptr = addr;
6008 MONO_OBJECT_SETREF (delegate, target, target);
6011 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
6015 * mono_delegate_ctor:
6016 * @this: pointer to an uninitialized delegate object
6017 * @target: target object
6018 * @addr: pointer to native code
6020 * This is used to initialize a delegate.
6023 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6025 MonoDomain *domain = mono_domain_get ();
6027 MonoMethod *method = NULL;
6031 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
6032 method = ji->method;
6033 g_assert (!method->klass->generic_container);
6036 mono_delegate_ctor_with_method (this, target, addr, method);
6040 * mono_method_call_message_new:
6041 * @method: method to encapsulate
6042 * @params: parameters to the method
6043 * @invoke: optional, delegate invoke.
6044 * @cb: async callback delegate.
6045 * @state: state passed to the async callback.
6047 * Translates arguments pointers into a MonoMethodMessage.
6050 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6051 MonoDelegate **cb, MonoObject **state)
6053 MonoDomain *domain = mono_domain_get ();
6054 MonoMethodSignature *sig = mono_method_signature (method);
6055 MonoMethodMessage *msg;
6058 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6061 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6062 count = sig->param_count - 2;
6064 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6065 count = sig->param_count;
6068 for (i = 0; i < count; i++) {
6073 if (sig->params [i]->byref)
6074 vpos = *((gpointer *)params [i]);
6078 type = sig->params [i]->type;
6079 class = mono_class_from_mono_type (sig->params [i]);
6081 if (class->valuetype)
6082 arg = mono_value_box (domain, class, vpos);
6084 arg = *((MonoObject **)vpos);
6086 mono_array_setref (msg->args, i, arg);
6089 if (cb != NULL && state != NULL) {
6090 *cb = *((MonoDelegate **)params [i]);
6092 *state = *((MonoObject **)params [i]);
6099 * mono_method_return_message_restore:
6101 * Restore results from message based processing back to arguments pointers
6104 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6106 MonoMethodSignature *sig = mono_method_signature (method);
6107 int i, j, type, size, out_len;
6109 if (out_args == NULL)
6111 out_len = mono_array_length (out_args);
6115 for (i = 0, j = 0; i < sig->param_count; i++) {
6116 MonoType *pt = sig->params [i];
6121 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6123 arg = mono_array_get (out_args, gpointer, j);
6126 g_assert (type != MONO_TYPE_VOID);
6128 if (MONO_TYPE_IS_REFERENCE (pt)) {
6129 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6132 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6133 size = mono_class_value_size (class, NULL);
6134 if (class->has_references)
6135 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6137 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6139 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6140 memset (*((gpointer *)params [i]), 0, size);
6150 * mono_load_remote_field:
6151 * @this: pointer to an object
6152 * @klass: klass of the object containing @field
6153 * @field: the field to load
6154 * @res: a storage to store the result
6156 * This method is called by the runtime on attempts to load fields of
6157 * transparent proxy objects. @this points to such TP, @klass is the class of
6158 * the object containing @field. @res is a storage location which can be
6159 * used to store the result.
6161 * Returns: an address pointing to the value of field.
6164 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6166 static MonoMethod *getter = NULL;
6167 MonoDomain *domain = mono_domain_get ();
6168 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6169 MonoClass *field_class;
6170 MonoMethodMessage *msg;
6171 MonoArray *out_args;
6175 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6176 g_assert (res != NULL);
6178 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6179 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6184 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6188 field_class = mono_class_from_mono_type (field->type);
6190 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6191 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6192 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6194 full_name = mono_type_get_full_name (klass);
6195 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6196 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6199 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6201 if (exc) mono_raise_exception ((MonoException *)exc);
6203 if (mono_array_length (out_args) == 0)
6206 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6208 if (field_class->valuetype) {
6209 return ((char *)*res) + sizeof (MonoObject);
6215 * mono_load_remote_field_new:
6220 * Missing documentation.
6223 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6225 static MonoMethod *getter = NULL;
6226 MonoDomain *domain = mono_domain_get ();
6227 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6228 MonoClass *field_class;
6229 MonoMethodMessage *msg;
6230 MonoArray *out_args;
6231 MonoObject *exc, *res;
6234 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6236 field_class = mono_class_from_mono_type (field->type);
6238 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6240 if (field_class->valuetype) {
6241 res = mono_object_new (domain, field_class);
6242 val = ((gchar *) res) + sizeof (MonoObject);
6246 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6251 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6255 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6256 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6258 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6260 full_name = mono_type_get_full_name (klass);
6261 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6262 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6265 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6267 if (exc) mono_raise_exception ((MonoException *)exc);
6269 if (mono_array_length (out_args) == 0)
6272 res = mono_array_get (out_args, MonoObject *, 0);
6278 * mono_store_remote_field:
6279 * @this: pointer to an object
6280 * @klass: klass of the object containing @field
6281 * @field: the field to load
6282 * @val: the value/object to store
6284 * This method is called by the runtime on attempts to store fields of
6285 * transparent proxy objects. @this points to such TP, @klass is the class of
6286 * the object containing @field. @val is the new value to store in @field.
6289 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6291 static MonoMethod *setter = NULL;
6292 MonoDomain *domain = mono_domain_get ();
6293 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6294 MonoClass *field_class;
6295 MonoMethodMessage *msg;
6296 MonoArray *out_args;
6301 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6303 field_class = mono_class_from_mono_type (field->type);
6305 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6306 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6307 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6312 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6316 if (field_class->valuetype)
6317 arg = mono_value_box (domain, field_class, val);
6319 arg = *((MonoObject **)val);
6322 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6323 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6325 full_name = mono_type_get_full_name (klass);
6326 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6327 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6328 mono_array_setref (msg->args, 2, arg);
6331 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6333 if (exc) mono_raise_exception ((MonoException *)exc);
6337 * mono_store_remote_field_new:
6343 * Missing documentation
6346 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6348 static MonoMethod *setter = NULL;
6349 MonoDomain *domain = mono_domain_get ();
6350 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6351 MonoClass *field_class;
6352 MonoMethodMessage *msg;
6353 MonoArray *out_args;
6357 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6359 field_class = mono_class_from_mono_type (field->type);
6361 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6362 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6363 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6368 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6372 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6373 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6375 full_name = mono_type_get_full_name (klass);
6376 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6377 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6378 mono_array_setref (msg->args, 2, arg);
6381 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6383 if (exc) mono_raise_exception ((MonoException *)exc);
6387 * mono_create_ftnptr:
6389 * Given a function address, create a function descriptor for it.
6390 * This is only needed on some platforms.
6393 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6395 return callbacks.create_ftnptr (domain, addr);
6399 * mono_get_addr_from_ftnptr:
6401 * Given a pointer to a function descriptor, return the function address.
6402 * This is only needed on some platforms.
6405 mono_get_addr_from_ftnptr (gpointer descr)
6407 return callbacks.get_addr_from_ftnptr (descr);
6411 * mono_string_chars:
6414 * Returns a pointer to the UCS16 characters stored in the MonoString
6417 mono_string_chars (MonoString *s)
6423 * mono_string_length:
6426 * Returns the lenght in characters of the string
6429 mono_string_length (MonoString *s)
6435 * mono_array_length:
6436 * @array: a MonoArray*
6438 * Returns the total number of elements in the array. This works for
6439 * both vectors and multidimensional arrays.
6442 mono_array_length (MonoArray *array)
6444 return array->max_length;
6448 * mono_array_addr_with_size:
6449 * @array: a MonoArray*
6450 * @size: size of the array elements
6451 * @idx: index into the array
6453 * Returns the address of the @idx element in the array.
6456 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6458 return ((char*)(array)->vector) + size * idx;