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);
760 * mono_class_compute_bitmap:
762 * Mono internal function to compute a bitmap of reference fields in a class.
765 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
767 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
772 * similar to the above, but sets the bits in the bitmap for any non-ref field
773 * and ignores static fields
776 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
778 MonoClassField *field;
783 max_size = class->instance_size / sizeof (gpointer);
784 if (max_size >= size) {
785 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
788 for (p = class; p != NULL; p = p->parent) {
789 gpointer iter = NULL;
790 while ((field = mono_class_get_fields (p, &iter))) {
793 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
795 /* FIXME: should not happen, flag as type load error */
796 if (field->type->byref)
799 pos = field->offset / sizeof (gpointer);
802 type = mono_type_get_underlying_type (field->type);
803 switch (type->type) {
804 #if SIZEOF_VOID_P == 8
808 case MONO_TYPE_FNPTR:
813 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
814 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
815 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
818 #if SIZEOF_VOID_P == 4
822 case MONO_TYPE_FNPTR:
827 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
828 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
829 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
835 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
836 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
837 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
840 case MONO_TYPE_BOOLEAN:
843 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
845 case MONO_TYPE_STRING:
846 case MONO_TYPE_SZARRAY:
847 case MONO_TYPE_CLASS:
848 case MONO_TYPE_OBJECT:
849 case MONO_TYPE_ARRAY:
851 case MONO_TYPE_GENERICINST:
852 if (!mono_type_generic_inst_is_valuetype (type)) {
857 case MONO_TYPE_VALUETYPE: {
858 MonoClass *fclass = mono_class_from_mono_type (field->type);
859 /* remove the object header */
860 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
864 g_assert_not_reached ();
873 * mono_class_insecure_overlapping:
874 * check if a class with explicit layout has references and non-references
875 * fields overlapping.
877 * Returns: TRUE if it is insecure to load the type.
880 mono_class_insecure_overlapping (MonoClass *klass)
884 gsize default_bitmap [4] = {0};
886 gsize default_nrbitmap [4] = {0};
887 int i, insecure = FALSE;
890 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
891 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
893 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
894 int idx = i % (sizeof (bitmap [0]) * 8);
895 if (bitmap [idx] & nrbitmap [idx]) {
900 if (bitmap != default_bitmap)
902 if (nrbitmap != default_nrbitmap)
905 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
913 mono_string_alloc (int length)
915 return mono_string_new_size (mono_domain_get (), length);
919 mono_class_compute_gc_descriptor (MonoClass *class)
923 gsize default_bitmap [4] = {0};
924 static gboolean gcj_inited = FALSE;
929 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
930 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
931 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
932 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
934 #ifdef HAVE_GC_GCJ_MALLOC
936 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
940 #ifdef GC_REDIRECT_TO_LOCAL
941 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
942 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
944 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
945 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
950 mono_loader_unlock ();
954 mono_class_init (class);
956 if (class->gc_descr_inited)
959 class->gc_descr_inited = TRUE;
960 class->gc_descr = GC_NO_DESCRIPTOR;
962 bitmap = default_bitmap;
963 if (class == mono_defaults.string_class) {
964 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
965 } else if (class->rank) {
966 mono_class_compute_gc_descriptor (class->element_class);
967 if (!class->element_class->valuetype) {
969 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
970 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
971 class->name_space, class->name);*/
973 /* remove the object header */
974 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
975 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
976 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
977 class->name_space, class->name);*/
978 if (bitmap != default_bitmap)
982 /*static int count = 0;
985 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
986 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
988 if (class->gc_descr == GC_NO_DESCRIPTOR)
989 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
991 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
992 if (bitmap != default_bitmap)
998 * field_is_special_static:
999 * @fklass: The MonoClass to look up.
1000 * @field: The MonoClassField describing the field.
1002 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1003 * SPECIAL_STATIC_NONE otherwise.
1006 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1008 MonoCustomAttrInfo *ainfo;
1010 ainfo = mono_custom_attrs_from_field (fklass, field);
1013 for (i = 0; i < ainfo->num_attrs; ++i) {
1014 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1015 if (klass->image == mono_defaults.corlib) {
1016 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1017 mono_custom_attrs_free (ainfo);
1018 return SPECIAL_STATIC_THREAD;
1020 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1021 mono_custom_attrs_free (ainfo);
1022 return SPECIAL_STATIC_CONTEXT;
1026 mono_custom_attrs_free (ainfo);
1027 return SPECIAL_STATIC_NONE;
1030 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1031 #define mix(a,b,c) { \
1032 a -= c; a ^= rot(c, 4); c += b; \
1033 b -= a; b ^= rot(a, 6); a += c; \
1034 c -= b; c ^= rot(b, 8); b += a; \
1035 a -= c; a ^= rot(c,16); c += b; \
1036 b -= a; b ^= rot(a,19); a += c; \
1037 c -= b; c ^= rot(b, 4); b += a; \
1039 #define final(a,b,c) { \
1040 c ^= b; c -= rot(b,14); \
1041 a ^= c; a -= rot(c,11); \
1042 b ^= a; b -= rot(a,25); \
1043 c ^= b; c -= rot(b,16); \
1044 a ^= c; a -= rot(c,4); \
1045 b ^= a; b -= rot(a,14); \
1046 c ^= b; c -= rot(b,24); \
1050 * mono_method_get_imt_slot:
1052 * The IMT slot is embedded into AOTed code, so this must return the same value
1053 * for the same method across all executions. This means:
1054 * - pointers shouldn't be used as hash values.
1055 * - mono_metadata_str_hash () should be used for hashing strings.
1058 mono_method_get_imt_slot (MonoMethod *method)
1060 MonoMethodSignature *sig;
1062 guint32 *hashes_start, *hashes;
1066 /* This can be used to stress tests the collision code */
1070 * We do this to simplify generic sharing. It will hurt
1071 * performance in cases where a class implements two different
1072 * instantiations of the same generic interface.
1073 * The code in build_imt_slots () depends on this.
1075 if (method->is_inflated)
1076 method = ((MonoMethodInflated*)method)->declaring;
1078 sig = mono_method_signature (method);
1079 hashes_count = sig->param_count + 4;
1080 hashes_start = malloc (hashes_count * sizeof (guint32));
1081 hashes = hashes_start;
1083 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1084 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1085 method->klass->name_space, method->klass->name, method->name);
1086 g_assert_not_reached ();
1089 /* Initialize hashes */
1090 hashes [0] = mono_metadata_str_hash (method->klass->name);
1091 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1092 hashes [2] = mono_metadata_str_hash (method->name);
1093 hashes [3] = mono_metadata_type_hash (sig->ret);
1094 for (i = 0; i < sig->param_count; i++) {
1095 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1098 /* Setup internal state */
1099 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1101 /* Handle most of the hashes */
1102 while (hashes_count > 3) {
1111 /* Handle the last 3 hashes (all the case statements fall through) */
1112 switch (hashes_count) {
1113 case 3 : c += hashes [2];
1114 case 2 : b += hashes [1];
1115 case 1 : a += hashes [0];
1117 case 0: /* nothing left to add */
1121 free (hashes_start);
1122 /* Report the result */
1123 return c % MONO_IMT_SIZE;
1132 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1133 guint32 imt_slot = mono_method_get_imt_slot (method);
1134 MonoImtBuilderEntry *entry;
1136 if (slot_num >= 0 && imt_slot != slot_num) {
1137 /* we build just a single imt slot and this is not it */
1141 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1142 entry->key = method;
1143 entry->value.vtable_slot = vtable_slot;
1144 entry->next = imt_builder [imt_slot];
1145 if (imt_builder [imt_slot] != NULL) {
1146 entry->children = imt_builder [imt_slot]->children + 1;
1147 if (entry->children == 1) {
1148 mono_stats.imt_slots_with_collisions++;
1149 *imt_collisions_bitmap |= (1 << imt_slot);
1152 entry->children = 0;
1153 mono_stats.imt_used_slots++;
1155 imt_builder [imt_slot] = entry;
1158 char *method_name = mono_method_full_name (method, TRUE);
1159 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1160 method, method_name, imt_slot, vtable_slot, entry->children);
1161 g_free (method_name);
1168 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1170 MonoMethod *method = e->key;
1171 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1175 method->klass->name_space,
1176 method->klass->name,
1179 printf (" * %s: NULL\n", message);
1185 compare_imt_builder_entries (const void *p1, const void *p2) {
1186 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1187 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1189 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1193 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1195 int count = end - start;
1196 int chunk_start = out_array->len;
1199 for (i = start; i < end; ++i) {
1200 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1201 item->key = sorted_array [i]->key;
1202 item->value = sorted_array [i]->value;
1203 item->has_target_code = sorted_array [i]->has_target_code;
1204 item->is_equals = TRUE;
1206 item->check_target_idx = out_array->len + 1;
1208 item->check_target_idx = 0;
1209 g_ptr_array_add (out_array, item);
1212 int middle = start + count / 2;
1213 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1215 item->key = sorted_array [middle]->key;
1216 item->is_equals = FALSE;
1217 g_ptr_array_add (out_array, item);
1218 imt_emit_ir (sorted_array, start, middle, out_array);
1219 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1225 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1226 int number_of_entries = entries->children + 1;
1227 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1228 GPtrArray *result = g_ptr_array_new ();
1229 MonoImtBuilderEntry *current_entry;
1232 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1233 sorted_array [i] = current_entry;
1235 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1237 /*for (i = 0; i < number_of_entries; i++) {
1238 print_imt_entry (" sorted array:", sorted_array [i], i);
1241 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1243 free (sorted_array);
1248 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1250 if (imt_builder_entry != NULL) {
1251 if (imt_builder_entry->children == 0 && !fail_tramp) {
1252 /* No collision, return the vtable slot contents */
1253 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1255 /* Collision, build the thunk */
1256 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1259 result = imt_thunk_builder (vtable, domain,
1260 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1261 for (i = 0; i < imt_ir->len; ++i)
1262 g_free (g_ptr_array_index (imt_ir, i));
1263 g_ptr_array_free (imt_ir, TRUE);
1275 static MonoImtBuilderEntry*
1276 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1279 * LOCKING: requires the loader and domain locks.
1283 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1287 guint32 imt_collisions_bitmap = 0;
1288 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1289 int method_count = 0;
1290 gboolean record_method_count_for_max_collisions = FALSE;
1291 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1294 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1296 for (i = 0; i < klass->interface_offsets_count; ++i) {
1297 MonoClass *iface = klass->interfaces_packed [i];
1298 int interface_offset = klass->interface_offsets_packed [i];
1299 int method_slot_in_interface, vt_slot;
1301 if (mono_class_has_variant_generic_params (iface))
1302 has_variant_iface = TRUE;
1304 vt_slot = interface_offset;
1305 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1308 if (slot_num >= 0 && iface->is_inflated) {
1310 * The imt slot of the method is the same as for its declaring method,
1311 * see the comment in mono_method_get_imt_slot (), so we can
1312 * avoid inflating methods which will be discarded by
1313 * add_imt_builder_entry anyway.
1315 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1316 if (mono_method_get_imt_slot (method) != slot_num) {
1321 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1322 if (method->is_generic) {
1323 has_generic_virtual = TRUE;
1328 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1329 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1334 if (extra_interfaces) {
1335 int interface_offset = klass->vtable_size;
1337 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1338 MonoClass* iface = list_item->data;
1339 int method_slot_in_interface;
1340 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1341 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1342 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1344 interface_offset += iface->method.count;
1347 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1348 /* overwrite the imt slot only if we're building all the entries or if
1349 * we're building this specific one
1351 if (slot_num < 0 || i == slot_num) {
1352 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1355 if (imt_builder [i]) {
1356 MonoImtBuilderEntry *entry;
1358 /* Link entries with imt_builder [i] */
1359 for (entry = entries; entry->next; entry = entry->next) {
1361 MonoMethod *method = (MonoMethod*)entry->key;
1362 char *method_name = mono_method_full_name (method, TRUE);
1363 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1364 g_free (method_name);
1367 entry->next = imt_builder [i];
1368 entries->children += imt_builder [i]->children + 1;
1370 imt_builder [i] = entries;
1373 if (has_generic_virtual || has_variant_iface) {
1375 * There might be collisions later when the the thunk is expanded.
1377 imt_collisions_bitmap |= (1 << i);
1380 * The IMT thunk might be called with an instance of one of the
1381 * generic virtual methods, so has to fallback to the IMT trampoline.
1383 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1385 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1388 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1392 if (imt_builder [i] != NULL) {
1393 int methods_in_slot = imt_builder [i]->children + 1;
1394 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1395 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1396 record_method_count_for_max_collisions = TRUE;
1398 method_count += methods_in_slot;
1402 mono_stats.imt_number_of_methods += method_count;
1403 if (record_method_count_for_max_collisions) {
1404 mono_stats.imt_method_count_when_max_collisions = method_count;
1407 for (i = 0; i < MONO_IMT_SIZE; i++) {
1408 MonoImtBuilderEntry* entry = imt_builder [i];
1409 while (entry != NULL) {
1410 MonoImtBuilderEntry* next = entry->next;
1416 /* we OR the bitmap since we may build just a single imt slot at a time */
1417 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1421 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1422 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1426 * mono_vtable_build_imt_slot:
1427 * @vtable: virtual object table struct
1428 * @imt_slot: slot in the IMT table
1430 * Fill the given @imt_slot in the IMT table of @vtable with
1431 * a trampoline or a thunk for the case of collisions.
1432 * This is part of the internal mono API.
1434 * LOCKING: Take the domain lock.
1437 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1439 gpointer *imt = (gpointer*)vtable;
1440 imt -= MONO_IMT_SIZE;
1441 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1443 /* no support for extra interfaces: the proxy objects will need
1444 * to build the complete IMT
1445 * Update and heck needs to ahppen inside the proper domain lock, as all
1446 * the changes made to a MonoVTable.
1448 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1449 mono_domain_lock (vtable->domain);
1450 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1451 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1452 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1453 mono_domain_unlock (vtable->domain);
1454 mono_loader_unlock ();
1459 * The first two free list entries both belong to the wait list: The
1460 * first entry is the pointer to the head of the list and the second
1461 * entry points to the last element. That way appending and removing
1462 * the first element are both O(1) operations.
1464 #ifdef MONO_SMALL_CONFIG
1465 #define NUM_FREE_LISTS 6
1467 #define NUM_FREE_LISTS 12
1469 #define FIRST_FREE_LIST_SIZE 64
1470 #define MAX_WAIT_LENGTH 50
1471 #define THUNK_THRESHOLD 10
1474 * LOCKING: The domain lock must be held.
1477 init_thunk_free_lists (MonoDomain *domain)
1479 if (domain->thunk_free_lists)
1481 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1485 list_index_for_size (int item_size)
1488 int size = FIRST_FREE_LIST_SIZE;
1490 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1499 * mono_method_alloc_generic_virtual_thunk:
1501 * @size: size in bytes
1503 * Allocs size bytes to be used for the code of a generic virtual
1504 * thunk. It's either allocated from the domain's code manager or
1505 * reused from a previously invalidated piece.
1507 * LOCKING: The domain lock must be held.
1510 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1512 static gboolean inited = FALSE;
1513 static int generic_virtual_thunks_size = 0;
1517 MonoThunkFreeList **l;
1519 init_thunk_free_lists (domain);
1521 size += sizeof (guint32);
1522 if (size < sizeof (MonoThunkFreeList))
1523 size = sizeof (MonoThunkFreeList);
1525 i = list_index_for_size (size);
1526 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1527 if ((*l)->size >= size) {
1528 MonoThunkFreeList *item = *l;
1530 return ((guint32*)item) + 1;
1534 /* no suitable item found - search lists of larger sizes */
1535 while (++i < NUM_FREE_LISTS) {
1536 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1539 g_assert (item->size > size);
1540 domain->thunk_free_lists [i] = item->next;
1541 return ((guint32*)item) + 1;
1544 /* still nothing found - allocate it */
1546 mono_counters_register ("Generic virtual thunk bytes",
1547 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1550 generic_virtual_thunks_size += size;
1552 p = mono_domain_code_reserve (domain, size);
1559 * LOCKING: The domain lock must be held.
1562 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1565 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1567 init_thunk_free_lists (domain);
1569 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1570 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1571 int length = item->length;
1574 /* unlink the first item from the wait list */
1575 domain->thunk_free_lists [0] = item->next;
1576 domain->thunk_free_lists [0]->length = length - 1;
1578 i = list_index_for_size (item->size);
1580 /* put it in the free list */
1581 item->next = domain->thunk_free_lists [i];
1582 domain->thunk_free_lists [i] = item;
1586 if (domain->thunk_free_lists [1]) {
1587 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1588 domain->thunk_free_lists [0]->length++;
1590 g_assert (!domain->thunk_free_lists [0]);
1592 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1593 domain->thunk_free_lists [0]->length = 1;
1597 typedef struct _GenericVirtualCase {
1601 struct _GenericVirtualCase *next;
1602 } GenericVirtualCase;
1605 * get_generic_virtual_entries:
1607 * Return IMT entries for the generic virtual method instances and
1608 * variant interface methods for vtable slot
1611 static MonoImtBuilderEntry*
1612 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1614 GenericVirtualCase *list;
1615 MonoImtBuilderEntry *entries;
1617 mono_domain_lock (domain);
1618 if (!domain->generic_virtual_cases)
1619 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1621 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1624 for (; list; list = list->next) {
1625 MonoImtBuilderEntry *entry;
1627 if (list->count < THUNK_THRESHOLD)
1630 entry = g_new0 (MonoImtBuilderEntry, 1);
1631 entry->key = list->method;
1632 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1633 entry->has_target_code = 1;
1635 entry->children = entries->children + 1;
1636 entry->next = entries;
1640 mono_domain_unlock (domain);
1642 /* FIXME: Leaking memory ? */
1647 * mono_method_add_generic_virtual_invocation:
1649 * @vtable_slot: pointer to the vtable slot
1650 * @method: the inflated generic virtual method
1651 * @code: the method's code
1653 * Registers a call via unmanaged code to a generic virtual method
1654 * instantiation or variant interface method. If the number of calls reaches a threshold
1655 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1656 * virtual method thunk.
1659 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1660 gpointer *vtable_slot,
1661 MonoMethod *method, gpointer code)
1663 static gboolean inited = FALSE;
1664 static int num_added = 0;
1666 GenericVirtualCase *gvc, *list;
1667 MonoImtBuilderEntry *entries;
1671 mono_domain_lock (domain);
1672 if (!domain->generic_virtual_cases)
1673 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1675 /* Check whether the case was already added */
1676 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1679 if (gvc->method == method)
1684 /* If not found, make a new one */
1686 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1687 gvc->method = method;
1690 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1692 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1695 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1701 if (++gvc->count == THUNK_THRESHOLD) {
1702 gpointer *old_thunk = *vtable_slot;
1703 gpointer vtable_trampoline = NULL;
1704 gpointer imt_trampoline = NULL;
1706 if ((gpointer)vtable_slot < (gpointer)vtable) {
1707 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1708 int imt_slot = MONO_IMT_SIZE + displacement;
1710 /* Force the rebuild of the thunk at the next call */
1711 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1712 *vtable_slot = imt_trampoline;
1714 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1716 entries = get_generic_virtual_entries (domain, vtable_slot);
1718 sorted = imt_sort_slot_entries (entries);
1720 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1724 MonoImtBuilderEntry *next = entries->next;
1729 for (i = 0; i < sorted->len; ++i)
1730 g_free (g_ptr_array_index (sorted, i));
1731 g_ptr_array_free (sorted, TRUE);
1734 #ifndef __native_client__
1735 /* We don't re-use any thunks as there is a lot of overhead */
1736 /* to deleting and re-using code in Native Client. */
1737 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1738 invalidate_generic_virtual_thunk (domain, old_thunk);
1742 mono_domain_unlock (domain);
1745 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1748 * mono_class_vtable:
1749 * @domain: the application domain
1750 * @class: the class to initialize
1752 * VTables are domain specific because we create domain specific code, and
1753 * they contain the domain specific static class data.
1754 * On failure, NULL is returned, and class->exception_type is set.
1757 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1759 return mono_class_vtable_full (domain, class, FALSE);
1763 * mono_class_vtable_full:
1764 * @domain: the application domain
1765 * @class: the class to initialize
1766 * @raise_on_error if an exception should be raised on failure or not
1768 * VTables are domain specific because we create domain specific code, and
1769 * they contain the domain specific static class data.
1772 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1774 MonoClassRuntimeInfo *runtime_info;
1778 if (class->exception_type) {
1780 mono_raise_exception (mono_class_get_exception_for_failure (class));
1784 /* this check can be inlined in jitted code, too */
1785 runtime_info = class->runtime_info;
1786 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1787 return runtime_info->domain_vtables [domain->domain_id];
1788 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1792 * mono_class_try_get_vtable:
1793 * @domain: the application domain
1794 * @class: the class to initialize
1796 * This function tries to get the associated vtable from @class if
1797 * it was already created.
1800 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1802 MonoClassRuntimeInfo *runtime_info;
1806 runtime_info = class->runtime_info;
1807 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1808 return runtime_info->domain_vtables [domain->domain_id];
1813 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1816 MonoClassRuntimeInfo *runtime_info, *old_info;
1817 MonoClassField *field;
1820 int imt_table_bytes = 0;
1821 guint32 vtable_size, class_size;
1824 gpointer *interface_offsets;
1826 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1827 mono_domain_lock (domain);
1828 runtime_info = class->runtime_info;
1829 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1830 mono_domain_unlock (domain);
1831 mono_loader_unlock ();
1832 return runtime_info->domain_vtables [domain->domain_id];
1834 if (!class->inited || class->exception_type) {
1835 if (!mono_class_init (class) || class->exception_type) {
1836 mono_domain_unlock (domain);
1837 mono_loader_unlock ();
1839 mono_raise_exception (mono_class_get_exception_for_failure (class));
1844 /* Array types require that their element type be valid*/
1845 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1846 MonoClass *element_class = class->element_class;
1847 if (!element_class->inited)
1848 mono_class_init (element_class);
1850 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1851 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1852 mono_class_setup_vtable (element_class);
1854 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1855 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1856 if (class->exception_type == MONO_EXCEPTION_NONE)
1857 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1858 mono_domain_unlock (domain);
1859 mono_loader_unlock ();
1861 mono_raise_exception (mono_class_get_exception_for_failure (class));
1867 * For some classes, mono_class_init () already computed class->vtable_size, and
1868 * that is all that is needed because of the vtable trampolines.
1870 if (!class->vtable_size)
1871 mono_class_setup_vtable (class);
1873 if (class->generic_class && !class->vtable)
1874 mono_class_check_vtable_constraints (class, NULL);
1876 /* Initialize klass->has_finalize */
1877 mono_class_has_finalizer (class);
1879 if (class->exception_type) {
1880 mono_domain_unlock (domain);
1881 mono_loader_unlock ();
1883 mono_raise_exception (mono_class_get_exception_for_failure (class));
1888 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1889 if (class->interface_offsets_count) {
1890 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1891 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1892 mono_stats.imt_number_of_tables++;
1893 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1896 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1897 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1900 mono_stats.used_class_count++;
1901 mono_stats.class_vtable_size += vtable_size;
1902 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1905 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1907 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1909 vt->rank = class->rank;
1910 vt->domain = domain;
1912 mono_class_compute_gc_descriptor (class);
1914 * We can't use typed allocation in the non-root domains, since the
1915 * collector needs the GC descriptor stored in the vtable even after
1916 * the mempool containing the vtable is destroyed when the domain is
1917 * unloaded. An alternative might be to allocate vtables in the GC
1918 * heap, but this does not seem to work (it leads to crashes inside
1919 * libgc). If that approach is tried, two gc descriptors need to be
1920 * allocated for each class: one for the root domain, and one for all
1921 * other domains. The second descriptor should contain a bit for the
1922 * vtable field in MonoObject, since we can no longer assume the
1923 * vtable is reachable by other roots after the appdomain is unloaded.
1925 #ifdef HAVE_BOEHM_GC
1926 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1927 vt->gc_descr = GC_NO_DESCRIPTOR;
1930 vt->gc_descr = class->gc_descr;
1932 if ((class_size = mono_class_data_size (class))) {
1933 if (class->has_static_refs) {
1934 gpointer statics_gc_descr;
1936 gsize default_bitmap [4] = {0};
1939 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1940 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1941 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1942 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1943 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1944 if (bitmap != default_bitmap)
1947 vt->data = mono_domain_alloc0 (domain, class_size);
1949 mono_stats.class_static_data_size += class_size;
1954 while ((field = mono_class_get_fields (class, &iter))) {
1955 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1957 if (mono_field_is_deleted (field))
1959 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1960 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1961 if (special_static != SPECIAL_STATIC_NONE) {
1962 guint32 size, offset;
1964 gsize default_bitmap [4] = {0};
1968 if (mono_type_is_reference (field->type)) {
1969 default_bitmap [0] = 1;
1971 bitmap = default_bitmap;
1972 } else if (mono_type_is_struct (field->type)) {
1973 fclass = mono_class_from_mono_type (field->type);
1974 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1976 default_bitmap [0] = 0;
1978 bitmap = default_bitmap;
1980 size = mono_type_size (field->type, &align);
1981 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, max_set);
1982 if (!domain->special_static_fields)
1983 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1984 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1985 if (bitmap != default_bitmap)
1988 * This marks the field as special static to speed up the
1989 * checks in mono_field_static_get/set_value ().
1995 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1996 MonoClass *fklass = mono_class_from_mono_type (field->type);
1997 const char *data = mono_field_get_data (field);
1999 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2000 t = (char*)vt->data + field->offset;
2001 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2004 if (fklass->valuetype) {
2005 memcpy (t, data, mono_class_value_size (fklass, NULL));
2007 /* it's a pointer type: add check */
2008 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2015 vt->max_interface_id = class->max_interface_id;
2016 vt->interface_bitmap = class->interface_bitmap;
2018 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2019 // class->name, class->interface_offsets_count);
2021 if (! ARCH_USE_IMT) {
2022 /* initialize interface offsets */
2023 for (i = 0; i < class->interface_offsets_count; ++i) {
2024 int interface_id = class->interfaces_packed [i]->interface_id;
2025 int slot = class->interface_offsets_packed [i];
2026 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2030 /* class_vtable_array keeps an array of created vtables
2032 g_ptr_array_add (domain->class_vtable_array, vt);
2033 /* class->runtime_info is protected by the loader lock, both when
2034 * it it enlarged and when it is stored info.
2037 old_info = class->runtime_info;
2038 if (old_info && old_info->max_domain >= domain->domain_id) {
2039 /* someone already created a large enough runtime info */
2040 mono_memory_barrier ();
2041 old_info->domain_vtables [domain->domain_id] = vt;
2043 int new_size = domain->domain_id;
2045 new_size = MAX (new_size, old_info->max_domain);
2047 /* make the new size a power of two */
2049 while (new_size > i)
2052 /* this is a bounded memory retention issue: may want to
2053 * handle it differently when we'll have a rcu-like system.
2055 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2056 runtime_info->max_domain = new_size - 1;
2057 /* copy the stuff from the older info */
2059 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2061 runtime_info->domain_vtables [domain->domain_id] = vt;
2063 mono_memory_barrier ();
2064 class->runtime_info = runtime_info;
2067 /* Initialize vtable */
2068 if (callbacks.get_vtable_trampoline) {
2069 // This also covers the AOT case
2070 for (i = 0; i < class->vtable_size; ++i) {
2071 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2074 mono_class_setup_vtable (class);
2076 for (i = 0; i < class->vtable_size; ++i) {
2079 if ((cm = class->vtable [i]))
2080 vt->vtable [i] = arch_create_jit_trampoline (cm);
2084 if (ARCH_USE_IMT && imt_table_bytes) {
2085 /* Now that the vtable is full, we can actually fill up the IMT */
2086 if (callbacks.get_imt_trampoline) {
2087 /* lazy construction of the IMT entries enabled */
2088 for (i = 0; i < MONO_IMT_SIZE; ++i)
2089 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2091 build_imt (class, vt, domain, interface_offsets, NULL);
2095 mono_domain_unlock (domain);
2096 mono_loader_unlock ();
2098 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2099 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2100 mono_raise_exception (mono_class_get_exception_for_failure (class));
2102 /* make sure the parent is initialized */
2103 /*FIXME shouldn't this fail the current type?*/
2105 mono_class_vtable_full (domain, class->parent, raise_on_error);
2107 /*FIXME check for OOM*/
2108 vt->type = mono_type_get_object (domain, &class->byval_arg);
2109 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2110 /* This is unregistered in
2111 unregister_vtable_reflection_type() in
2113 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2114 if (class->contextbound)
2123 * mono_class_proxy_vtable:
2124 * @domain: the application domain
2125 * @remove_class: the remote class
2127 * Creates a vtable for transparent proxies. It is basically
2128 * a copy of the real vtable of the class wrapped in @remote_class,
2129 * but all function pointers invoke the remoting functions, and
2130 * vtable->klass points to the transparent proxy class, and not to @class.
2133 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2136 MonoVTable *vt, *pvt;
2137 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2139 GSList *extra_interfaces = NULL;
2140 MonoClass *class = remote_class->proxy_class;
2141 gpointer *interface_offsets;
2145 #ifdef COMPRESSED_INTERFACE_BITMAP
2149 vt = mono_class_vtable (domain, class);
2150 g_assert (vt); /*FIXME property handle failure*/
2151 max_interface_id = vt->max_interface_id;
2153 /* Calculate vtable space for extra interfaces */
2154 for (j = 0; j < remote_class->interface_count; j++) {
2155 MonoClass* iclass = remote_class->interfaces[j];
2159 /*FIXME test for interfaces with variant generic arguments*/
2160 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2161 continue; /* interface implemented by the class */
2162 if (g_slist_find (extra_interfaces, iclass))
2165 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2167 method_count = mono_class_num_methods (iclass);
2169 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2170 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2172 for (i = 0; i < ifaces->len; ++i) {
2173 MonoClass *ic = g_ptr_array_index (ifaces, i);
2174 /*FIXME test for interfaces with variant generic arguments*/
2175 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2176 continue; /* interface implemented by the class */
2177 if (g_slist_find (extra_interfaces, ic))
2179 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2180 method_count += mono_class_num_methods (ic);
2182 g_ptr_array_free (ifaces, TRUE);
2185 extra_interface_vtsize += method_count * sizeof (gpointer);
2186 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2190 mono_stats.imt_number_of_tables++;
2191 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2192 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2193 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2195 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2196 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2199 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2201 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2203 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2205 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2206 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2208 pvt->klass = mono_defaults.transparent_proxy_class;
2209 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2210 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2212 /* initialize vtable */
2213 mono_class_setup_vtable (class);
2214 for (i = 0; i < class->vtable_size; ++i) {
2217 if ((cm = class->vtable [i]))
2218 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2220 pvt->vtable [i] = NULL;
2223 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2224 /* create trampolines for abstract methods */
2225 for (k = class; k; k = k->parent) {
2227 gpointer iter = NULL;
2228 while ((m = mono_class_get_methods (k, &iter)))
2229 if (!pvt->vtable [m->slot])
2230 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2234 pvt->max_interface_id = max_interface_id;
2235 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2236 #ifdef COMPRESSED_INTERFACE_BITMAP
2237 bitmap = g_malloc0 (bsize);
2239 bitmap = mono_domain_alloc0 (domain, bsize);
2242 if (! ARCH_USE_IMT) {
2243 /* initialize interface offsets */
2244 for (i = 0; i < class->interface_offsets_count; ++i) {
2245 int interface_id = class->interfaces_packed [i]->interface_id;
2246 int slot = class->interface_offsets_packed [i];
2247 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2250 for (i = 0; i < class->interface_offsets_count; ++i) {
2251 int interface_id = class->interfaces_packed [i]->interface_id;
2252 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2255 if (extra_interfaces) {
2256 int slot = class->vtable_size;
2262 /* Create trampolines for the methods of the interfaces */
2263 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2264 interf = list_item->data;
2266 if (! ARCH_USE_IMT) {
2267 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2269 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2273 while ((cm = mono_class_get_methods (interf, &iter)))
2274 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2276 slot += mono_class_num_methods (interf);
2278 if (! ARCH_USE_IMT) {
2279 g_slist_free (extra_interfaces);
2284 /* Now that the vtable is full, we can actually fill up the IMT */
2285 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2286 if (extra_interfaces) {
2287 g_slist_free (extra_interfaces);
2291 #ifdef COMPRESSED_INTERFACE_BITMAP
2292 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2293 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2294 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2297 pvt->interface_bitmap = bitmap;
2303 * mono_class_field_is_special_static:
2305 * Returns whether @field is a thread/context static field.
2308 mono_class_field_is_special_static (MonoClassField *field)
2310 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2312 if (mono_field_is_deleted (field))
2314 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2315 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2322 * mono_class_field_get_special_static_type:
2323 * @field: The MonoClassField describing the field.
2325 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2326 * SPECIAL_STATIC_NONE otherwise.
2329 mono_class_field_get_special_static_type (MonoClassField *field)
2331 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2332 return SPECIAL_STATIC_NONE;
2333 if (mono_field_is_deleted (field))
2334 return SPECIAL_STATIC_NONE;
2335 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2336 return field_is_special_static (field->parent, field);
2337 return SPECIAL_STATIC_NONE;
2341 * mono_class_has_special_static_fields:
2343 * Returns whenever @klass has any thread/context static fields.
2346 mono_class_has_special_static_fields (MonoClass *klass)
2348 MonoClassField *field;
2352 while ((field = mono_class_get_fields (klass, &iter))) {
2353 g_assert (field->parent == klass);
2354 if (mono_class_field_is_special_static (field))
2362 * create_remote_class_key:
2363 * Creates an array of pointers that can be used as a hash key for a remote class.
2364 * The first element of the array is the number of pointers.
2367 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2372 if (remote_class == NULL) {
2373 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2374 key = g_malloc (sizeof(gpointer) * 3);
2375 key [0] = GINT_TO_POINTER (2);
2376 key [1] = mono_defaults.marshalbyrefobject_class;
2377 key [2] = extra_class;
2379 key = g_malloc (sizeof(gpointer) * 2);
2380 key [0] = GINT_TO_POINTER (1);
2381 key [1] = extra_class;
2384 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2385 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2386 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2387 key [1] = remote_class->proxy_class;
2389 // Keep the list of interfaces sorted
2390 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2391 if (extra_class && remote_class->interfaces [i] > extra_class) {
2392 key [j++] = extra_class;
2395 key [j] = remote_class->interfaces [i];
2398 key [j] = extra_class;
2400 // Replace the old class. The interface list is the same
2401 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2402 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2403 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2404 for (i = 0; i < remote_class->interface_count; i++)
2405 key [2 + i] = remote_class->interfaces [i];
2413 * copy_remote_class_key:
2415 * Make a copy of KEY in the domain and return the copy.
2418 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2420 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2421 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2423 memcpy (mp_key, key, key_size);
2429 * mono_remote_class:
2430 * @domain: the application domain
2431 * @class_name: name of the remote class
2433 * Creates and initializes a MonoRemoteClass object for a remote type.
2435 * Can raise an exception on failure.
2438 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2441 MonoRemoteClass *rc;
2442 gpointer* key, *mp_key;
2445 key = create_remote_class_key (NULL, proxy_class);
2447 mono_domain_lock (domain);
2448 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2452 mono_domain_unlock (domain);
2456 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2457 if (!mono_error_ok (&error)) {
2459 mono_domain_unlock (domain);
2460 mono_error_raise_exception (&error);
2463 mp_key = copy_remote_class_key (domain, key);
2467 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2468 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2469 rc->interface_count = 1;
2470 rc->interfaces [0] = proxy_class;
2471 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2473 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2474 rc->interface_count = 0;
2475 rc->proxy_class = proxy_class;
2478 rc->default_vtable = NULL;
2479 rc->xdomain_vtable = NULL;
2480 rc->proxy_class_name = name;
2481 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2483 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2485 mono_domain_unlock (domain);
2490 * clone_remote_class:
2491 * Creates a copy of the remote_class, adding the provided class or interface
2493 static MonoRemoteClass*
2494 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2496 MonoRemoteClass *rc;
2497 gpointer* key, *mp_key;
2499 key = create_remote_class_key (remote_class, extra_class);
2500 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2506 mp_key = copy_remote_class_key (domain, key);
2510 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2512 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2513 rc->proxy_class = remote_class->proxy_class;
2514 rc->interface_count = remote_class->interface_count + 1;
2516 // Keep the list of interfaces sorted, since the hash key of
2517 // the remote class depends on this
2518 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2519 if (remote_class->interfaces [i] > extra_class && i == j)
2520 rc->interfaces [j++] = extra_class;
2521 rc->interfaces [j] = remote_class->interfaces [i];
2524 rc->interfaces [j] = extra_class;
2526 // Replace the old class. The interface array is the same
2527 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2528 rc->proxy_class = extra_class;
2529 rc->interface_count = remote_class->interface_count;
2530 if (rc->interface_count > 0)
2531 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2534 rc->default_vtable = NULL;
2535 rc->xdomain_vtable = NULL;
2536 rc->proxy_class_name = remote_class->proxy_class_name;
2538 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2544 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2546 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2547 mono_domain_lock (domain);
2548 if (rp->target_domain_id != -1) {
2549 if (remote_class->xdomain_vtable == NULL)
2550 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2551 mono_domain_unlock (domain);
2552 mono_loader_unlock ();
2553 return remote_class->xdomain_vtable;
2555 if (remote_class->default_vtable == NULL) {
2558 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2559 klass = mono_class_from_mono_type (type);
2560 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2561 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2563 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2566 mono_domain_unlock (domain);
2567 mono_loader_unlock ();
2568 return remote_class->default_vtable;
2572 * mono_upgrade_remote_class:
2573 * @domain: the application domain
2574 * @tproxy: the proxy whose remote class has to be upgraded.
2575 * @klass: class to which the remote class can be casted.
2577 * Updates the vtable of the remote class by adding the necessary method slots
2578 * and interface offsets so it can be safely casted to klass. klass can be a
2579 * class or an interface.
2582 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2584 MonoTransparentProxy *tproxy;
2585 MonoRemoteClass *remote_class;
2586 gboolean redo_vtable;
2588 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2589 mono_domain_lock (domain);
2591 tproxy = (MonoTransparentProxy*) proxy_object;
2592 remote_class = tproxy->remote_class;
2594 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2597 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2598 if (remote_class->interfaces [i] == klass)
2599 redo_vtable = FALSE;
2602 redo_vtable = (remote_class->proxy_class != klass);
2606 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2607 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2610 mono_domain_unlock (domain);
2611 mono_loader_unlock ();
2616 * mono_object_get_virtual_method:
2617 * @obj: object to operate on.
2620 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2621 * the instance of a callvirt of method.
2624 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2627 MonoMethod **vtable;
2629 MonoMethod *res = NULL;
2631 klass = mono_object_class (obj);
2632 if (klass == mono_defaults.transparent_proxy_class) {
2633 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2639 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2642 mono_class_setup_vtable (klass);
2643 vtable = klass->vtable;
2645 if (method->slot == -1) {
2646 /* method->slot might not be set for instances of generic methods */
2647 if (method->is_inflated) {
2648 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2649 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2652 g_assert_not_reached ();
2656 /* check method->slot is a valid index: perform isinstance? */
2657 if (method->slot != -1) {
2658 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2660 gboolean variance_used = FALSE;
2661 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2662 g_assert (iface_offset > 0);
2663 res = vtable [iface_offset + method->slot];
2666 res = vtable [method->slot];
2671 /* It may be an interface, abstract class method or generic method */
2672 if (!res || mono_method_signature (res)->generic_param_count)
2675 /* generic methods demand invoke_with_check */
2676 if (mono_method_signature (res)->generic_param_count)
2677 res = mono_marshal_get_remoting_invoke_with_check (res);
2680 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2681 res = mono_cominterop_get_invoke (res);
2684 res = mono_marshal_get_remoting_invoke (res);
2687 if (method->is_inflated) {
2688 /* Have to inflate the result */
2689 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2699 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2701 g_error ("runtime invoke called on uninitialized runtime");
2705 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2708 * mono_runtime_invoke:
2709 * @method: method to invoke
2710 * @obJ: object instance
2711 * @params: arguments to the method
2712 * @exc: exception information.
2714 * Invokes the method represented by @method on the object @obj.
2716 * obj is the 'this' pointer, it should be NULL for static
2717 * methods, a MonoObject* for object instances and a pointer to
2718 * the value type for value types.
2720 * The params array contains the arguments to the method with the
2721 * same convention: MonoObject* pointers for object instances and
2722 * pointers to the value type otherwise.
2724 * From unmanaged code you'll usually use the
2725 * mono_runtime_invoke() variant.
2727 * Note that this function doesn't handle virtual methods for
2728 * you, it will exec the exact method you pass: we still need to
2729 * expose a function to lookup the derived class implementation
2730 * of a virtual method (there are examples of this in the code,
2733 * You can pass NULL as the exc argument if you don't want to
2734 * catch exceptions, otherwise, *exc will be set to the exception
2735 * thrown, if any. if an exception is thrown, you can't use the
2736 * MonoObject* result from the function.
2738 * If the method returns a value type, it is boxed in an object
2742 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2746 if (mono_runtime_get_no_exec ())
2747 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2749 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2750 mono_profiler_method_start_invoke (method);
2752 result = default_mono_runtime_invoke (method, obj, params, exc);
2754 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2755 mono_profiler_method_end_invoke (method);
2761 * mono_method_get_unmanaged_thunk:
2762 * @method: method to generate a thunk for.
2764 * Returns an unmanaged->managed thunk that can be used to call
2765 * a managed method directly from C.
2767 * The thunk's C signature closely matches the managed signature:
2769 * C#: public bool Equals (object obj);
2770 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2771 * MonoObject*, MonoException**);
2773 * The 1st ("this") parameter must not be used with static methods:
2775 * C#: public static bool ReferenceEquals (object a, object b);
2776 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2779 * The last argument must be a non-null pointer of a MonoException* pointer.
2780 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2781 * exception has been thrown in managed code. Otherwise it will point
2782 * to the MonoException* caught by the thunk. In this case, the result of
2783 * the thunk is undefined:
2785 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2786 * MonoException *ex = NULL;
2787 * Equals func = mono_method_get_unmanaged_thunk (method);
2788 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2790 * // handle exception
2793 * The calling convention of the thunk matches the platform's default
2794 * convention. This means that under Windows, C declarations must
2795 * contain the __stdcall attribute:
2797 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2798 * MonoObject*, MonoException**);
2802 * Value type arguments and return values are treated as they were objects:
2804 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2805 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2807 * Arguments must be properly boxed upon trunk's invocation, while return
2808 * values must be unboxed.
2811 mono_method_get_unmanaged_thunk (MonoMethod *method)
2813 method = mono_marshal_get_thunk_invoke_wrapper (method);
2814 return mono_compile_method (method);
2818 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2822 /* object fields cannot be byref, so we don't need a
2824 gpointer *p = (gpointer*)dest;
2831 case MONO_TYPE_BOOLEAN:
2833 case MONO_TYPE_U1: {
2834 guint8 *p = (guint8*)dest;
2835 *p = value ? *(guint8*)value : 0;
2840 case MONO_TYPE_CHAR: {
2841 guint16 *p = (guint16*)dest;
2842 *p = value ? *(guint16*)value : 0;
2845 #if SIZEOF_VOID_P == 4
2850 case MONO_TYPE_U4: {
2851 gint32 *p = (gint32*)dest;
2852 *p = value ? *(gint32*)value : 0;
2855 #if SIZEOF_VOID_P == 8
2860 case MONO_TYPE_U8: {
2861 gint64 *p = (gint64*)dest;
2862 *p = value ? *(gint64*)value : 0;
2865 case MONO_TYPE_R4: {
2866 float *p = (float*)dest;
2867 *p = value ? *(float*)value : 0;
2870 case MONO_TYPE_R8: {
2871 double *p = (double*)dest;
2872 *p = value ? *(double*)value : 0;
2875 case MONO_TYPE_STRING:
2876 case MONO_TYPE_SZARRAY:
2877 case MONO_TYPE_CLASS:
2878 case MONO_TYPE_OBJECT:
2879 case MONO_TYPE_ARRAY:
2880 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2882 case MONO_TYPE_FNPTR:
2883 case MONO_TYPE_PTR: {
2884 gpointer *p = (gpointer*)dest;
2885 *p = deref_pointer? *(gpointer*)value: value;
2888 case MONO_TYPE_VALUETYPE:
2889 /* note that 't' and 'type->type' can be different */
2890 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2891 t = mono_class_enum_basetype (type->data.klass)->type;
2894 MonoClass *class = mono_class_from_mono_type (type);
2895 int size = mono_class_value_size (class, NULL);
2897 memset (dest, 0, size);
2899 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2902 case MONO_TYPE_GENERICINST:
2903 t = type->data.generic_class->container_class->byval_arg.type;
2906 g_warning ("got type %x", type->type);
2907 g_assert_not_reached ();
2912 * mono_field_set_value:
2913 * @obj: Instance object
2914 * @field: MonoClassField describing the field to set
2915 * @value: The value to be set
2917 * Sets the value of the field described by @field in the object instance @obj
2918 * to the value passed in @value. This method should only be used for instance
2919 * fields. For static fields, use mono_field_static_set_value.
2921 * The value must be on the native format of the field type.
2924 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2928 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2930 dest = (char*)obj + field->offset;
2931 set_value (field->type, dest, value, FALSE);
2935 * mono_field_static_set_value:
2936 * @field: MonoClassField describing the field to set
2937 * @value: The value to be set
2939 * Sets the value of the static field described by @field
2940 * to the value passed in @value.
2942 * The value must be on the native format of the field type.
2945 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2949 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2950 /* you cant set a constant! */
2951 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2953 if (field->offset == -1) {
2954 /* Special static */
2957 mono_domain_lock (vt->domain);
2958 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2959 mono_domain_unlock (vt->domain);
2960 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2962 dest = (char*)vt->data + field->offset;
2964 set_value (field->type, dest, value, FALSE);
2967 /* Used by the debugger */
2969 mono_vtable_get_static_field_data (MonoVTable *vt)
2975 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2979 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2980 if (field->offset == -1) {
2981 /* Special static */
2984 mono_domain_lock (vt->domain);
2985 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2986 mono_domain_unlock (vt->domain);
2987 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2989 src = (guint8*)vt->data + field->offset;
2992 src = (guint8*)obj + field->offset;
2999 * mono_field_get_value:
3000 * @obj: Object instance
3001 * @field: MonoClassField describing the field to fetch information from
3002 * @value: pointer to the location where the value will be stored
3004 * Use this routine to get the value of the field @field in the object
3007 * The pointer provided by value must be of the field type, for reference
3008 * types this is a MonoObject*, for value types its the actual pointer to
3013 * mono_field_get_value (obj, int_field, &i);
3016 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3022 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3024 src = (char*)obj + field->offset;
3025 set_value (field->type, value, src, TRUE);
3029 * mono_field_get_value_object:
3030 * @domain: domain where the object will be created (if boxing)
3031 * @field: MonoClassField describing the field to fetch information from
3032 * @obj: The object instance for the field.
3034 * Returns: a new MonoObject with the value from the given field. If the
3035 * field represents a value type, the value is boxed.
3039 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3043 MonoVTable *vtable = NULL;
3045 gboolean is_static = FALSE;
3046 gboolean is_ref = FALSE;
3047 gboolean is_literal = FALSE;
3048 gboolean is_ptr = FALSE;
3050 MonoType *type = mono_field_get_type_checked (field, &error);
3052 if (!mono_error_ok (&error))
3053 mono_error_raise_exception (&error);
3055 switch (type->type) {
3056 case MONO_TYPE_STRING:
3057 case MONO_TYPE_OBJECT:
3058 case MONO_TYPE_CLASS:
3059 case MONO_TYPE_ARRAY:
3060 case MONO_TYPE_SZARRAY:
3065 case MONO_TYPE_BOOLEAN:
3068 case MONO_TYPE_CHAR:
3077 case MONO_TYPE_VALUETYPE:
3078 is_ref = type->byref;
3080 case MONO_TYPE_GENERICINST:
3081 is_ref = !mono_type_generic_inst_is_valuetype (type);
3087 g_error ("type 0x%x not handled in "
3088 "mono_field_get_value_object", type->type);
3092 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3095 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3099 vtable = mono_class_vtable (domain, field->parent);
3101 char *name = mono_type_get_full_name (field->parent);
3102 /*FIXME extend this to use the MonoError api*/
3103 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3107 if (!vtable->initialized)
3108 mono_runtime_class_init (vtable);
3116 get_default_field_value (domain, field, &o);
3117 } else if (is_static) {
3118 mono_field_static_get_value (vtable, field, &o);
3120 mono_field_get_value (obj, field, &o);
3126 static MonoMethod *m;
3132 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3133 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3139 get_default_field_value (domain, field, v);
3140 } else if (is_static) {
3141 mono_field_static_get_value (vtable, field, v);
3143 mono_field_get_value (obj, field, v);
3146 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3148 args [1] = mono_type_get_object (mono_domain_get (), type);
3150 return mono_runtime_invoke (m, NULL, args, NULL);
3153 /* boxed value type */
3154 klass = mono_class_from_mono_type (type);
3156 if (mono_class_is_nullable (klass))
3157 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3159 o = mono_object_new (domain, klass);
3160 v = ((gchar *) o) + sizeof (MonoObject);
3163 get_default_field_value (domain, field, v);
3164 } else if (is_static) {
3165 mono_field_static_get_value (vtable, field, v);
3167 mono_field_get_value (obj, field, v);
3174 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3177 const char *p = blob;
3178 mono_metadata_decode_blob_size (p, &p);
3181 case MONO_TYPE_BOOLEAN:
3184 *(guint8 *) value = *p;
3186 case MONO_TYPE_CHAR:
3189 *(guint16*) value = read16 (p);
3193 *(guint32*) value = read32 (p);
3197 *(guint64*) value = read64 (p);
3200 readr4 (p, (float*) value);
3203 readr8 (p, (double*) value);
3205 case MONO_TYPE_STRING:
3206 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3208 case MONO_TYPE_CLASS:
3209 *(gpointer*) value = NULL;
3213 g_warning ("type 0x%02x should not be in constant table", type);
3219 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3221 MonoTypeEnum def_type;
3224 data = mono_class_get_field_default_value (field, &def_type);
3225 mono_get_constant_value_from_blob (domain, def_type, data, value);
3229 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3233 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3235 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3236 get_default_field_value (vt->domain, field, value);
3240 if (field->offset == -1) {
3241 /* Special static */
3242 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3243 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3245 src = (char*)vt->data + field->offset;
3247 set_value (field->type, value, src, TRUE);
3251 * mono_field_static_get_value:
3252 * @vt: vtable to the object
3253 * @field: MonoClassField describing the field to fetch information from
3254 * @value: where the value is returned
3256 * Use this routine to get the value of the static field @field value.
3258 * The pointer provided by value must be of the field type, for reference
3259 * types this is a MonoObject*, for value types its the actual pointer to
3264 * mono_field_static_get_value (vt, int_field, &i);
3267 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3269 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3273 * mono_property_set_value:
3274 * @prop: MonoProperty to set
3275 * @obj: instance object on which to act
3276 * @params: parameters to pass to the propery
3277 * @exc: optional exception
3279 * Invokes the property's set method with the given arguments on the
3280 * object instance obj (or NULL for static properties).
3282 * You can pass NULL as the exc argument if you don't want to
3283 * catch exceptions, otherwise, *exc will be set to the exception
3284 * thrown, if any. if an exception is thrown, you can't use the
3285 * MonoObject* result from the function.
3288 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3290 default_mono_runtime_invoke (prop->set, obj, params, exc);
3294 * mono_property_get_value:
3295 * @prop: MonoProperty to fetch
3296 * @obj: instance object on which to act
3297 * @params: parameters to pass to the propery
3298 * @exc: optional exception
3300 * Invokes the property's get method with the given arguments on the
3301 * object instance obj (or NULL for static properties).
3303 * You can pass NULL as the exc argument if you don't want to
3304 * catch exceptions, otherwise, *exc will be set to the exception
3305 * thrown, if any. if an exception is thrown, you can't use the
3306 * MonoObject* result from the function.
3308 * Returns: the value from invoking the get method on the property.
3311 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3313 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3317 * mono_nullable_init:
3318 * @buf: The nullable structure to initialize.
3319 * @value: the value to initialize from
3320 * @klass: the type for the object
3322 * Initialize the nullable structure pointed to by @buf from @value which
3323 * should be a boxed value type. The size of @buf should be able to hold
3324 * as much data as the @klass->instance_size (which is the number of bytes
3325 * that will be copies).
3327 * Since Nullables have variable structure, we can not define a C
3328 * structure for them.
3331 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3333 MonoClass *param_class = klass->cast_class;
3335 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3336 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3338 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3340 if (param_class->has_references)
3341 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3343 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3345 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3350 * mono_nullable_box:
3351 * @buf: The buffer representing the data to be boxed
3352 * @klass: the type to box it as.
3354 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3358 mono_nullable_box (guint8 *buf, MonoClass *klass)
3360 MonoClass *param_class = klass->cast_class;
3362 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3363 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3365 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3366 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3367 if (param_class->has_references)
3368 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3370 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3378 * mono_get_delegate_invoke:
3379 * @klass: The delegate class
3381 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3384 mono_get_delegate_invoke (MonoClass *klass)
3388 /* This is called at runtime, so avoid the slower search in metadata */
3389 mono_class_setup_methods (klass);
3390 if (klass->exception_type)
3392 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3397 * mono_runtime_delegate_invoke:
3398 * @delegate: pointer to a delegate object.
3399 * @params: parameters for the delegate.
3400 * @exc: Pointer to the exception result.
3402 * Invokes the delegate method @delegate with the parameters provided.
3404 * You can pass NULL as the exc argument if you don't want to
3405 * catch exceptions, otherwise, *exc will be set to the exception
3406 * thrown, if any. if an exception is thrown, you can't use the
3407 * MonoObject* result from the function.
3410 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3414 im = mono_get_delegate_invoke (delegate->vtable->klass);
3417 return mono_runtime_invoke (im, delegate, params, exc);
3420 static char **main_args = NULL;
3421 static int num_main_args;
3424 * mono_runtime_get_main_args:
3426 * Returns: a MonoArray with the arguments passed to the main program
3429 mono_runtime_get_main_args (void)
3433 MonoDomain *domain = mono_domain_get ();
3438 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3440 for (i = 0; i < num_main_args; ++i)
3441 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3447 free_main_args (void)
3451 for (i = 0; i < num_main_args; ++i)
3452 g_free (main_args [i]);
3457 * mono_runtime_run_main:
3458 * @method: the method to start the application with (usually Main)
3459 * @argc: number of arguments from the command line
3460 * @argv: array of strings from the command line
3461 * @exc: excetption results
3463 * Execute a standard Main() method (argc/argv contains the
3464 * executable name). This method also sets the command line argument value
3465 * needed by System.Environment.
3470 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3474 MonoArray *args = NULL;
3475 MonoDomain *domain = mono_domain_get ();
3476 gchar *utf8_fullpath;
3477 MonoMethodSignature *sig;
3479 g_assert (method != NULL);
3481 mono_thread_set_main (mono_thread_current ());
3483 main_args = g_new0 (char*, argc);
3484 num_main_args = argc;
3486 if (!g_path_is_absolute (argv [0])) {
3487 gchar *basename = g_path_get_basename (argv [0]);
3488 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3492 utf8_fullpath = mono_utf8_from_external (fullpath);
3493 if(utf8_fullpath == NULL) {
3494 /* Printing the arg text will cause glib to
3495 * whinge about "Invalid UTF-8", but at least
3496 * its relevant, and shows the problem text
3499 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3500 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3507 utf8_fullpath = mono_utf8_from_external (argv[0]);
3508 if(utf8_fullpath == NULL) {
3509 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3510 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3515 main_args [0] = utf8_fullpath;
3517 for (i = 1; i < argc; ++i) {
3520 utf8_arg=mono_utf8_from_external (argv[i]);
3521 if(utf8_arg==NULL) {
3522 /* Ditto the comment about Invalid UTF-8 here */
3523 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3524 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3528 main_args [i] = utf8_arg;
3533 sig = mono_method_signature (method);
3535 g_print ("Unable to load Main method.\n");
3539 if (sig->param_count) {
3540 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3541 for (i = 0; i < argc; ++i) {
3542 /* The encodings should all work, given that
3543 * we've checked all these args for the
3546 gchar *str = mono_utf8_from_external (argv [i]);
3547 MonoString *arg = mono_string_new (domain, str);
3548 mono_array_setref (args, i, arg);
3552 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3555 mono_assembly_set_main (method->klass->image->assembly);
3557 return mono_runtime_exec_main (method, args, exc);
3561 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3563 static MonoMethod *serialize_method;
3568 if (!serialize_method) {
3569 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3570 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3573 if (!serialize_method) {
3578 g_assert (!mono_object_class (obj)->marshalbyref);
3582 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3590 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3592 static MonoMethod *deserialize_method;
3597 if (!deserialize_method) {
3598 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3599 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3601 if (!deserialize_method) {
3608 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3616 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3618 static MonoMethod *get_proxy_method;
3620 MonoDomain *domain = mono_domain_get ();
3621 MonoRealProxy *real_proxy;
3622 MonoReflectionType *reflection_type;
3623 MonoTransparentProxy *transparent_proxy;
3625 if (!get_proxy_method)
3626 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3628 g_assert (obj->vtable->klass->marshalbyref);
3630 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3631 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3633 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3634 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3637 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3641 return (MonoObject*) transparent_proxy;
3645 * mono_object_xdomain_representation
3647 * @target_domain: a domain
3648 * @exc: pointer to a MonoObject*
3650 * Creates a representation of obj in the domain target_domain. This
3651 * is either a copy of obj arrived through via serialization and
3652 * deserialization or a proxy, depending on whether the object is
3653 * serializable or marshal by ref. obj must not be in target_domain.
3655 * If the object cannot be represented in target_domain, NULL is
3656 * returned and *exc is set to an appropriate exception.
3659 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3661 MonoObject *deserialized = NULL;
3662 gboolean failure = FALSE;
3666 if (mono_object_class (obj)->marshalbyref) {
3667 deserialized = make_transparent_proxy (obj, &failure, exc);
3669 MonoDomain *domain = mono_domain_get ();
3670 MonoObject *serialized;
3672 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3673 serialized = serialize_object (obj, &failure, exc);
3674 mono_domain_set_internal_with_options (target_domain, FALSE);
3676 deserialized = deserialize_object (serialized, &failure, exc);
3677 if (domain != target_domain)
3678 mono_domain_set_internal_with_options (domain, FALSE);
3681 return deserialized;
3684 /* Used in call_unhandled_exception_delegate */
3686 create_unhandled_exception_eventargs (MonoObject *exc)
3690 MonoMethod *method = NULL;
3691 MonoBoolean is_terminating = TRUE;
3694 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3697 mono_class_init (klass);
3699 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3700 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3704 args [1] = &is_terminating;
3706 obj = mono_object_new (mono_domain_get (), klass);
3707 mono_runtime_invoke (method, obj, args, NULL);
3712 /* Used in mono_unhandled_exception */
3714 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3715 MonoObject *e = NULL;
3717 MonoDomain *current_domain = mono_domain_get ();
3719 if (domain != current_domain)
3720 mono_domain_set_internal_with_options (domain, FALSE);
3722 g_assert (domain == mono_object_domain (domain->domain));
3724 if (mono_object_domain (exc) != domain) {
3725 MonoObject *serialization_exc;
3727 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3729 if (serialization_exc) {
3731 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3734 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3735 "System.Runtime.Serialization", "SerializationException",
3736 "Could not serialize unhandled exception.");
3740 g_assert (mono_object_domain (exc) == domain);
3742 pa [0] = domain->domain;
3743 pa [1] = create_unhandled_exception_eventargs (exc);
3744 mono_runtime_delegate_invoke (delegate, pa, &e);
3746 if (domain != current_domain)
3747 mono_domain_set_internal_with_options (current_domain, FALSE);
3751 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3752 if (!mono_error_ok (&error)) {
3753 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3754 mono_error_cleanup (&error);
3756 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3762 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3765 * mono_runtime_unhandled_exception_policy_set:
3766 * @policy: the new policy
3768 * This is a VM internal routine.
3770 * Sets the runtime policy for handling unhandled exceptions.
3773 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3774 runtime_unhandled_exception_policy = policy;
3778 * mono_runtime_unhandled_exception_policy_get:
3780 * This is a VM internal routine.
3782 * Gets the runtime policy for handling unhandled exceptions.
3784 MonoRuntimeUnhandledExceptionPolicy
3785 mono_runtime_unhandled_exception_policy_get (void) {
3786 return runtime_unhandled_exception_policy;
3790 * mono_unhandled_exception:
3791 * @exc: exception thrown
3793 * This is a VM internal routine.
3795 * We call this function when we detect an unhandled exception
3796 * in the default domain.
3798 * It invokes the * UnhandledException event in AppDomain or prints
3799 * a warning to the console
3802 mono_unhandled_exception (MonoObject *exc)
3804 MonoDomain *current_domain = mono_domain_get ();
3805 MonoDomain *root_domain = mono_get_root_domain ();
3806 MonoClassField *field;
3807 MonoObject *current_appdomain_delegate;
3808 MonoObject *root_appdomain_delegate;
3810 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3811 "UnhandledException");
3814 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3815 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3816 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3817 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3818 if (current_domain != root_domain) {
3819 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3821 current_appdomain_delegate = NULL;
3824 /* set exitcode only if we will abort the process */
3826 mono_environment_exitcode_set (1);
3827 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3828 mono_print_unhandled_exception (exc);
3830 if (root_appdomain_delegate) {
3831 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3833 if (current_appdomain_delegate) {
3834 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3841 * mono_runtime_exec_managed_code:
3842 * @domain: Application domain
3843 * @main_func: function to invoke from the execution thread
3844 * @main_args: parameter to the main_func
3846 * Launch a new thread to execute a function
3848 * main_func is called back from the thread with main_args as the
3849 * parameter. The callback function is expected to start Main()
3850 * eventually. This function then waits for all managed threads to
3852 * It is not necesseray anymore to execute managed code in a subthread,
3853 * so this function should not be used anymore by default: just
3854 * execute the code and then call mono_thread_manage ().
3857 mono_runtime_exec_managed_code (MonoDomain *domain,
3858 MonoMainThreadFunc main_func,
3861 mono_thread_create (domain, main_func, main_args);
3863 mono_thread_manage ();
3867 * Execute a standard Main() method (args doesn't contain the
3871 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3876 MonoCustomAttrInfo* cinfo;
3877 gboolean has_stathread_attribute;
3878 MonoInternalThread* thread = mono_thread_internal_current ();
3884 domain = mono_object_domain (args);
3885 if (!domain->entry_assembly) {
3887 MonoAssembly *assembly;
3889 assembly = method->klass->image->assembly;
3890 domain->entry_assembly = assembly;
3891 /* Domains created from another domain already have application_base and configuration_file set */
3892 if (domain->setup->application_base == NULL) {
3893 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3896 if (domain->setup->configuration_file == NULL) {
3897 str = g_strconcat (assembly->image->name, ".config", NULL);
3898 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3900 mono_set_private_bin_path_from_config (domain);
3904 cinfo = mono_custom_attrs_from_method (method);
3906 static MonoClass *stathread_attribute = NULL;
3907 if (!stathread_attribute)
3908 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3909 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3911 mono_custom_attrs_free (cinfo);
3913 has_stathread_attribute = FALSE;
3915 if (has_stathread_attribute) {
3916 thread->apartment_state = ThreadApartmentState_STA;
3918 thread->apartment_state = ThreadApartmentState_MTA;
3920 mono_thread_init_apartment_state ();
3922 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3924 /* FIXME: check signature of method */
3925 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3927 res = mono_runtime_invoke (method, NULL, pa, exc);
3929 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3933 mono_environment_exitcode_set (rval);
3935 mono_runtime_invoke (method, NULL, pa, exc);
3939 /* If the return type of Main is void, only
3940 * set the exitcode if an exception was thrown
3941 * (we don't want to blow away an
3942 * explicitly-set exit code)
3945 mono_environment_exitcode_set (rval);
3949 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3955 * mono_install_runtime_invoke:
3956 * @func: Function to install
3958 * This is a VM internal routine
3961 mono_install_runtime_invoke (MonoInvokeFunc func)
3963 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3968 * mono_runtime_invoke_array:
3969 * @method: method to invoke
3970 * @obJ: object instance
3971 * @params: arguments to the method
3972 * @exc: exception information.
3974 * Invokes the method represented by @method on the object @obj.
3976 * obj is the 'this' pointer, it should be NULL for static
3977 * methods, a MonoObject* for object instances and a pointer to
3978 * the value type for value types.
3980 * The params array contains the arguments to the method with the
3981 * same convention: MonoObject* pointers for object instances and
3982 * pointers to the value type otherwise. The _invoke_array
3983 * variant takes a C# object[] as the params argument (MonoArray
3984 * *params): in this case the value types are boxed inside the
3985 * respective reference representation.
3987 * From unmanaged code you'll usually use the
3988 * mono_runtime_invoke() variant.
3990 * Note that this function doesn't handle virtual methods for
3991 * you, it will exec the exact method you pass: we still need to
3992 * expose a function to lookup the derived class implementation
3993 * of a virtual method (there are examples of this in the code,
3996 * You can pass NULL as the exc argument if you don't want to
3997 * catch exceptions, otherwise, *exc will be set to the exception
3998 * thrown, if any. if an exception is thrown, you can't use the
3999 * MonoObject* result from the function.
4001 * If the method returns a value type, it is boxed in an object
4005 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4008 MonoMethodSignature *sig = mono_method_signature (method);
4009 gpointer *pa = NULL;
4012 gboolean has_byref_nullables = FALSE;
4014 if (NULL != params) {
4015 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4016 for (i = 0; i < mono_array_length (params); i++) {
4017 MonoType *t = sig->params [i];
4023 case MONO_TYPE_BOOLEAN:
4026 case MONO_TYPE_CHAR:
4035 case MONO_TYPE_VALUETYPE:
4036 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4037 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4038 pa [i] = mono_array_get (params, MonoObject*, i);
4040 has_byref_nullables = TRUE;
4042 /* MS seems to create the objects if a null is passed in */
4043 if (!mono_array_get (params, MonoObject*, i))
4044 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4048 * We can't pass the unboxed vtype byref to the callee, since
4049 * that would mean the callee would be able to modify boxed
4050 * primitive types. So we (and MS) make a copy of the boxed
4051 * object, pass that to the callee, and replace the original
4052 * boxed object in the arg array with the copy.
4054 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4055 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4056 mono_array_setref (params, i, copy);
4059 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4062 case MONO_TYPE_STRING:
4063 case MONO_TYPE_OBJECT:
4064 case MONO_TYPE_CLASS:
4065 case MONO_TYPE_ARRAY:
4066 case MONO_TYPE_SZARRAY:
4068 pa [i] = mono_array_addr (params, MonoObject*, i);
4069 // FIXME: I need to check this code path
4071 pa [i] = mono_array_get (params, MonoObject*, i);
4073 case MONO_TYPE_GENERICINST:
4075 t = &t->data.generic_class->container_class->this_arg;
4077 t = &t->data.generic_class->container_class->byval_arg;
4079 case MONO_TYPE_PTR: {
4082 /* The argument should be an IntPtr */
4083 arg = mono_array_get (params, MonoObject*, i);
4087 g_assert (arg->vtable->klass == mono_defaults.int_class);
4088 pa [i] = ((MonoIntPtr*)arg)->m_value;
4093 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4098 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4101 if (mono_class_is_nullable (method->klass)) {
4102 /* Need to create a boxed vtype instead */
4108 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4112 obj = mono_object_new (mono_domain_get (), method->klass);
4113 g_assert (obj); /*maybe we should raise a TLE instead?*/
4114 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4115 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4117 if (method->klass->valuetype)
4118 o = mono_object_unbox (obj);
4121 } else if (method->klass->valuetype) {
4122 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4125 mono_runtime_invoke (method, o, pa, exc);
4128 if (mono_class_is_nullable (method->klass)) {
4129 MonoObject *nullable;
4131 /* Convert the unboxed vtype into a Nullable structure */
4132 nullable = mono_object_new (mono_domain_get (), method->klass);
4134 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4135 obj = mono_object_unbox (nullable);
4138 /* obj must be already unboxed if needed */
4139 res = mono_runtime_invoke (method, obj, pa, exc);
4141 if (sig->ret->type == MONO_TYPE_PTR) {
4142 MonoClass *pointer_class;
4143 static MonoMethod *box_method;
4145 MonoObject *box_exc;
4148 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4149 * convert it to a Pointer object.
4151 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4153 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4155 g_assert (res->vtable->klass == mono_defaults.int_class);
4156 box_args [0] = ((MonoIntPtr*)res)->m_value;
4157 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4158 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4159 g_assert (!box_exc);
4162 if (has_byref_nullables) {
4164 * The runtime invoke wrapper already converted byref nullables back,
4165 * and stored them in pa, we just need to copy them back to the
4168 for (i = 0; i < mono_array_length (params); i++) {
4169 MonoType *t = sig->params [i];
4171 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4172 mono_array_setref (params, i, pa [i]);
4181 arith_overflow (void)
4183 mono_raise_exception (mono_get_exception_overflow ());
4187 * mono_object_allocate:
4188 * @size: number of bytes to allocate
4190 * This is a very simplistic routine until we have our GC-aware
4193 * Returns: an allocated object of size @size, or NULL on failure.
4195 static inline void *
4196 mono_object_allocate (size_t size, MonoVTable *vtable)
4199 mono_stats.new_object_count++;
4200 ALLOC_OBJECT (o, vtable, size);
4206 * mono_object_allocate_ptrfree:
4207 * @size: number of bytes to allocate
4209 * Note that the memory allocated is not zeroed.
4210 * Returns: an allocated object of size @size, or NULL on failure.
4212 static inline void *
4213 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4216 mono_stats.new_object_count++;
4217 ALLOC_PTRFREE (o, vtable, size);
4221 static inline void *
4222 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4225 ALLOC_TYPED (o, size, vtable);
4226 mono_stats.new_object_count++;
4233 * @klass: the class of the object that we want to create
4235 * Returns: a newly created object whose definition is
4236 * looked up using @klass. This will not invoke any constructors,
4237 * so the consumer of this routine has to invoke any constructors on
4238 * its own to initialize the object.
4240 * It returns NULL on failure.
4243 mono_object_new (MonoDomain *domain, MonoClass *klass)
4247 MONO_ARCH_SAVE_REGS;
4248 vtable = mono_class_vtable (domain, klass);
4251 return mono_object_new_specific (vtable);
4255 * mono_object_new_pinned:
4257 * Same as mono_object_new, but the returned object will be pinned.
4258 * For SGEN, these objects will only be freed at appdomain unload.
4261 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4265 MONO_ARCH_SAVE_REGS;
4266 vtable = mono_class_vtable (domain, klass);
4271 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4273 return mono_object_new_specific (vtable);
4278 * mono_object_new_specific:
4279 * @vtable: the vtable of the object that we want to create
4281 * Returns: A newly created object with class and domain specified
4285 mono_object_new_specific (MonoVTable *vtable)
4289 MONO_ARCH_SAVE_REGS;
4291 /* check for is_com_object for COM Interop */
4292 if (vtable->remote || vtable->klass->is_com_object)
4295 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4298 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4301 mono_class_init (klass);
4303 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4305 vtable->domain->create_proxy_for_type_method = im;
4308 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4310 o = mono_runtime_invoke (im, NULL, pa, NULL);
4311 if (o != NULL) return o;
4314 return mono_object_new_alloc_specific (vtable);
4318 mono_object_new_alloc_specific (MonoVTable *vtable)
4322 if (!vtable->klass->has_references) {
4323 o = mono_object_new_ptrfree (vtable);
4324 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4325 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4327 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4328 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4330 if (G_UNLIKELY (vtable->klass->has_finalize))
4331 mono_object_register_finalizer (o);
4333 if (G_UNLIKELY (profile_allocs))
4334 mono_profiler_allocation (o, vtable->klass);
4339 mono_object_new_fast (MonoVTable *vtable)
4342 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4347 mono_object_new_ptrfree (MonoVTable *vtable)
4350 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4351 #if NEED_TO_ZERO_PTRFREE
4352 /* an inline memset is much faster for the common vcase of small objects
4353 * note we assume the allocated size is a multiple of sizeof (void*).
4355 if (vtable->klass->instance_size < 128) {
4357 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4358 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4364 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4371 mono_object_new_ptrfree_box (MonoVTable *vtable)
4374 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4375 /* the object will be boxed right away, no need to memzero it */
4380 * mono_class_get_allocation_ftn:
4382 * @for_box: the object will be used for boxing
4383 * @pass_size_in_words:
4385 * Return the allocation function appropriate for the given class.
4389 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4391 *pass_size_in_words = FALSE;
4393 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4394 profile_allocs = FALSE;
4396 if (mono_class_has_finalizer (vtable->klass) || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4397 return mono_object_new_specific;
4399 if (!vtable->klass->has_references) {
4400 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4402 return mono_object_new_ptrfree_box;
4403 return mono_object_new_ptrfree;
4406 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4408 return mono_object_new_fast;
4411 * FIXME: This is actually slower than mono_object_new_fast, because
4412 * of the overhead of parameter passing.
4415 *pass_size_in_words = TRUE;
4416 #ifdef GC_REDIRECT_TO_LOCAL
4417 return GC_local_gcj_fast_malloc;
4419 return GC_gcj_fast_malloc;
4424 return mono_object_new_specific;
4428 * mono_object_new_from_token:
4429 * @image: Context where the type_token is hosted
4430 * @token: a token of the type that we want to create
4432 * Returns: A newly created object whose definition is
4433 * looked up using @token in the @image image
4436 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4440 class = mono_class_get (image, token);
4442 return mono_object_new (domain, class);
4447 * mono_object_clone:
4448 * @obj: the object to clone
4450 * Returns: A newly created object who is a shallow copy of @obj
4453 mono_object_clone (MonoObject *obj)
4456 int size = obj->vtable->klass->instance_size;
4458 o = mono_object_allocate (size, obj->vtable);
4460 if (obj->vtable->klass->has_references) {
4461 mono_gc_wbarrier_object_copy (o, obj);
4463 int size = obj->vtable->klass->instance_size;
4464 /* do not copy the sync state */
4465 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4467 if (G_UNLIKELY (profile_allocs))
4468 mono_profiler_allocation (o, obj->vtable->klass);
4470 if (obj->vtable->klass->has_finalize)
4471 mono_object_register_finalizer (o);
4476 * mono_array_full_copy:
4477 * @src: source array to copy
4478 * @dest: destination array
4480 * Copies the content of one array to another with exactly the same type and size.
4483 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4486 MonoClass *klass = src->obj.vtable->klass;
4488 MONO_ARCH_SAVE_REGS;
4490 g_assert (klass == dest->obj.vtable->klass);
4492 size = mono_array_length (src);
4493 g_assert (size == mono_array_length (dest));
4494 size *= mono_array_element_size (klass);
4496 if (klass->element_class->valuetype) {
4497 if (klass->element_class->has_references)
4498 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4500 memcpy (&dest->vector, &src->vector, size);
4502 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4505 memcpy (&dest->vector, &src->vector, size);
4510 * mono_array_clone_in_domain:
4511 * @domain: the domain in which the array will be cloned into
4512 * @array: the array to clone
4514 * This routine returns a copy of the array that is hosted on the
4515 * specified MonoDomain.
4518 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4523 MonoClass *klass = array->obj.vtable->klass;
4525 MONO_ARCH_SAVE_REGS;
4527 if (array->bounds == NULL) {
4528 size = mono_array_length (array);
4529 o = mono_array_new_full (domain, klass, &size, NULL);
4531 size *= mono_array_element_size (klass);
4533 if (klass->element_class->valuetype) {
4534 if (klass->element_class->has_references)
4535 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4537 memcpy (&o->vector, &array->vector, size);
4539 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4542 memcpy (&o->vector, &array->vector, size);
4547 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4548 size = mono_array_element_size (klass);
4549 for (i = 0; i < klass->rank; ++i) {
4550 sizes [i] = array->bounds [i].length;
4551 size *= array->bounds [i].length;
4552 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4554 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4556 if (klass->element_class->valuetype) {
4557 if (klass->element_class->has_references)
4558 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4560 memcpy (&o->vector, &array->vector, size);
4562 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4565 memcpy (&o->vector, &array->vector, size);
4573 * @array: the array to clone
4575 * Returns: A newly created array who is a shallow copy of @array
4578 mono_array_clone (MonoArray *array)
4580 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4583 /* helper macros to check for overflow when calculating the size of arrays */
4584 #ifdef MONO_BIG_ARRAYS
4585 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4586 #define MYGUINT_MAX MYGUINT64_MAX
4587 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4588 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4589 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4590 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4591 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4593 #define MYGUINT32_MAX 4294967295U
4594 #define MYGUINT_MAX MYGUINT32_MAX
4595 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4596 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4597 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4598 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4599 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4603 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4607 byte_len = mono_array_element_size (class);
4608 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4611 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4613 byte_len += sizeof (MonoArray);
4621 * mono_array_new_full:
4622 * @domain: domain where the object is created
4623 * @array_class: array class
4624 * @lengths: lengths for each dimension in the array
4625 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4627 * This routine creates a new array objects with the given dimensions,
4628 * lower bounds and type.
4631 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4633 uintptr_t byte_len, len, bounds_size;
4636 MonoArrayBounds *bounds;
4640 if (!array_class->inited)
4641 mono_class_init (array_class);
4645 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4646 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4648 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4652 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4654 for (i = 0; i < array_class->rank; ++i) {
4655 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4657 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4658 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4663 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4664 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4668 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4669 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4670 byte_len = (byte_len + 3) & ~3;
4671 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4672 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4673 byte_len += bounds_size;
4676 * Following three lines almost taken from mono_object_new ():
4677 * they need to be kept in sync.
4679 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4680 #ifndef HAVE_SGEN_GC
4681 if (!array_class->has_references) {
4682 o = mono_object_allocate_ptrfree (byte_len, vtable);
4683 #if NEED_TO_ZERO_PTRFREE
4684 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4686 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4687 o = mono_object_allocate_spec (byte_len, vtable);
4689 o = mono_object_allocate (byte_len, vtable);
4692 array = (MonoArray*)o;
4693 array->max_length = len;
4696 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4697 array->bounds = bounds;
4701 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4703 o = mono_gc_alloc_vector (vtable, byte_len, len);
4704 array = (MonoArray*)o;
4705 mono_stats.new_object_count++;
4707 bounds = array->bounds;
4711 for (i = 0; i < array_class->rank; ++i) {
4712 bounds [i].length = lengths [i];
4714 bounds [i].lower_bound = lower_bounds [i];
4718 if (G_UNLIKELY (profile_allocs))
4719 mono_profiler_allocation (o, array_class);
4726 * @domain: domain where the object is created
4727 * @eclass: element class
4728 * @n: number of array elements
4730 * This routine creates a new szarray with @n elements of type @eclass.
4733 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4737 MONO_ARCH_SAVE_REGS;
4739 ac = mono_array_class_get (eclass, 1);
4742 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4746 * mono_array_new_specific:
4747 * @vtable: a vtable in the appropriate domain for an initialized class
4748 * @n: number of array elements
4750 * This routine is a fast alternative to mono_array_new() for code which
4751 * can be sure about the domain it operates in.
4754 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4760 MONO_ARCH_SAVE_REGS;
4762 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4767 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4768 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4771 #ifndef HAVE_SGEN_GC
4772 if (!vtable->klass->has_references) {
4773 o = mono_object_allocate_ptrfree (byte_len, vtable);
4774 #if NEED_TO_ZERO_PTRFREE
4775 ((MonoArray*)o)->bounds = NULL;
4776 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4778 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4779 o = mono_object_allocate_spec (byte_len, vtable);
4781 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4782 o = mono_object_allocate (byte_len, vtable);
4785 ao = (MonoArray *)o;
4788 o = mono_gc_alloc_vector (vtable, byte_len, n);
4790 mono_stats.new_object_count++;
4793 if (G_UNLIKELY (profile_allocs))
4794 mono_profiler_allocation (o, vtable->klass);
4800 * mono_string_new_utf16:
4801 * @text: a pointer to an utf16 string
4802 * @len: the length of the string
4804 * Returns: A newly created string object which contains @text.
4807 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4811 s = mono_string_new_size (domain, len);
4812 g_assert (s != NULL);
4814 memcpy (mono_string_chars (s), text, len * 2);
4820 * mono_string_new_size:
4821 * @text: a pointer to an utf16 string
4822 * @len: the length of the string
4824 * Returns: A newly created string object of @len
4827 mono_string_new_size (MonoDomain *domain, gint32 len)
4831 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4833 /* overflow ? can't fit it, can't allocate it! */
4835 mono_gc_out_of_memory (-1);
4837 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4840 #ifndef HAVE_SGEN_GC
4841 s = mono_object_allocate_ptrfree (size, vtable);
4845 s = mono_gc_alloc_string (vtable, size, len);
4847 #if NEED_TO_ZERO_PTRFREE
4850 if (G_UNLIKELY (profile_allocs))
4851 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4857 * mono_string_new_len:
4858 * @text: a pointer to an utf8 string
4859 * @length: number of bytes in @text to consider
4861 * Returns: A newly created string object which contains @text.
4864 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4866 GError *error = NULL;
4867 MonoString *o = NULL;
4869 glong items_written;
4871 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4874 o = mono_string_new_utf16 (domain, ut, items_written);
4876 g_error_free (error);
4885 * @text: a pointer to an utf8 string
4887 * Returns: A newly created string object which contains @text.
4890 mono_string_new (MonoDomain *domain, const char *text)
4892 GError *error = NULL;
4893 MonoString *o = NULL;
4895 glong items_written;
4900 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4903 o = mono_string_new_utf16 (domain, ut, items_written);
4905 g_error_free (error);
4908 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4913 MonoString *o = NULL;
4915 if (!g_utf8_validate (text, -1, &end))
4918 len = g_utf8_strlen (text, -1);
4919 o = mono_string_new_size (domain, len);
4920 str = mono_string_chars (o);
4922 while (text < end) {
4923 *str++ = g_utf8_get_char (text);
4924 text = g_utf8_next_char (text);
4931 * mono_string_new_wrapper:
4932 * @text: pointer to utf8 characters.
4934 * Helper function to create a string object from @text in the current domain.
4937 mono_string_new_wrapper (const char *text)
4939 MonoDomain *domain = mono_domain_get ();
4941 MONO_ARCH_SAVE_REGS;
4944 return mono_string_new (domain, text);
4951 * @class: the class of the value
4952 * @value: a pointer to the unboxed data
4954 * Returns: A newly created object which contains @value.
4957 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4963 g_assert (class->valuetype);
4964 if (mono_class_is_nullable (class))
4965 return mono_nullable_box (value, class);
4967 vtable = mono_class_vtable (domain, class);
4970 size = mono_class_instance_size (class);
4971 res = mono_object_new_alloc_specific (vtable);
4972 if (G_UNLIKELY (profile_allocs))
4973 mono_profiler_allocation (res, class);
4975 size = size - sizeof (MonoObject);
4978 g_assert (size == mono_class_value_size (class, NULL));
4979 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4981 #if NO_UNALIGNED_ACCESS
4982 memcpy ((char *)res + sizeof (MonoObject), value, size);
4986 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4989 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4992 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4995 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4998 memcpy ((char *)res + sizeof (MonoObject), value, size);
5002 if (class->has_finalize)
5003 mono_object_register_finalizer (res);
5009 * @dest: destination pointer
5010 * @src: source pointer
5011 * @klass: a valuetype class
5013 * Copy a valuetype from @src to @dest. This function must be used
5014 * when @klass contains references fields.
5017 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5019 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5023 * mono_value_copy_array:
5024 * @dest: destination array
5025 * @dest_idx: index in the @dest array
5026 * @src: source pointer
5027 * @count: number of items
5029 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5030 * This function must be used when @klass contains references fields.
5031 * Overlap is handled.
5034 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5036 int size = mono_array_element_size (dest->obj.vtable->klass);
5037 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5038 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5039 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5043 * mono_object_get_domain:
5044 * @obj: object to query
5046 * Returns: the MonoDomain where the object is hosted
5049 mono_object_get_domain (MonoObject *obj)
5051 return mono_object_domain (obj);
5055 * mono_object_get_class:
5056 * @obj: object to query
5058 * Returns: the MonOClass of the object.
5061 mono_object_get_class (MonoObject *obj)
5063 return mono_object_class (obj);
5066 * mono_object_get_size:
5067 * @o: object to query
5069 * Returns: the size, in bytes, of @o
5072 mono_object_get_size (MonoObject* o)
5074 MonoClass* klass = mono_object_class (o);
5075 if (klass == mono_defaults.string_class) {
5076 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5077 } else if (o->vtable->rank) {
5078 MonoArray *array = (MonoArray*)o;
5079 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5080 if (array->bounds) {
5083 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5087 return mono_class_instance_size (klass);
5092 * mono_object_unbox:
5093 * @obj: object to unbox
5095 * Returns: a pointer to the start of the valuetype boxed in this
5098 * This method will assert if the object passed is not a valuetype.
5101 mono_object_unbox (MonoObject *obj)
5103 /* add assert for valuetypes? */
5104 g_assert (obj->vtable->klass->valuetype);
5105 return ((char*)obj) + sizeof (MonoObject);
5109 * mono_object_isinst:
5111 * @klass: a pointer to a class
5113 * Returns: @obj if @obj is derived from @klass
5116 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5119 mono_class_init (klass);
5121 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5122 return mono_object_isinst_mbyref (obj, klass);
5127 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5131 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5140 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5141 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5145 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5146 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5149 MonoClass *oklass = vt->klass;
5150 if ((oklass == mono_defaults.transparent_proxy_class))
5151 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5153 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5157 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5159 MonoDomain *domain = mono_domain_get ();
5161 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5162 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5163 MonoMethod *im = NULL;
5166 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5167 im = mono_object_get_virtual_method (rp, im);
5170 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5173 res = mono_runtime_invoke (im, rp, pa, NULL);
5175 if (*(MonoBoolean *) mono_object_unbox(res)) {
5176 /* Update the vtable of the remote type, so it can safely cast to this new type */
5177 mono_upgrade_remote_class (domain, obj, klass);
5186 * mono_object_castclass_mbyref:
5188 * @klass: a pointer to a class
5190 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5193 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5195 if (!obj) return NULL;
5196 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5198 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5200 "InvalidCastException"));
5205 MonoDomain *orig_domain;
5211 str_lookup (MonoDomain *domain, gpointer user_data)
5213 LDStrInfo *info = user_data;
5214 if (info->res || domain == info->orig_domain)
5216 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5222 mono_string_get_pinned (MonoString *str)
5226 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5227 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5229 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5230 news->length = mono_string_length (str);
5236 #define mono_string_get_pinned(str) (str)
5240 mono_string_is_interned_lookup (MonoString *str, int insert)
5242 MonoGHashTable *ldstr_table;
5246 domain = ((MonoObject *)str)->vtable->domain;
5247 ldstr_table = domain->ldstr_table;
5249 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5254 str = mono_string_get_pinned (str);
5256 mono_g_hash_table_insert (ldstr_table, str, str);
5260 LDStrInfo ldstr_info;
5261 ldstr_info.orig_domain = domain;
5262 ldstr_info.ins = str;
5263 ldstr_info.res = NULL;
5265 mono_domain_foreach (str_lookup, &ldstr_info);
5266 if (ldstr_info.res) {
5268 * the string was already interned in some other domain:
5269 * intern it in the current one as well.
5271 mono_g_hash_table_insert (ldstr_table, str, str);
5281 * mono_string_is_interned:
5282 * @o: String to probe
5284 * Returns whether the string has been interned.
5287 mono_string_is_interned (MonoString *o)
5289 return mono_string_is_interned_lookup (o, FALSE);
5293 * mono_string_intern:
5294 * @o: String to intern
5296 * Interns the string passed.
5297 * Returns: The interned string.
5300 mono_string_intern (MonoString *str)
5302 return mono_string_is_interned_lookup (str, TRUE);
5307 * @domain: the domain where the string will be used.
5308 * @image: a metadata context
5309 * @idx: index into the user string table.
5311 * Implementation for the ldstr opcode.
5312 * Returns: a loaded string from the @image/@idx combination.
5315 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5317 MONO_ARCH_SAVE_REGS;
5319 if (image->dynamic) {
5320 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5323 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5324 return NULL; /*FIXME we should probably be raising an exception here*/
5325 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5330 * mono_ldstr_metadata_sig
5331 * @domain: the domain for the string
5332 * @sig: the signature of a metadata string
5334 * Returns: a MonoString for a string stored in the metadata
5337 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5339 const char *str = sig;
5340 MonoString *o, *interned;
5343 len2 = mono_metadata_decode_blob_size (str, &str);
5346 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5347 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5350 guint16 *p2 = (guint16*)mono_string_chars (o);
5351 for (i = 0; i < len2; ++i) {
5352 *p2 = GUINT16_FROM_LE (*p2);
5358 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5360 /* o will get garbage collected */
5364 o = mono_string_get_pinned (o);
5366 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5373 * mono_string_to_utf8:
5374 * @s: a System.String
5376 * Returns the UTF8 representation for @s.
5377 * The resulting buffer needs to be freed with mono_free().
5379 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5382 mono_string_to_utf8 (MonoString *s)
5385 char *result = mono_string_to_utf8_checked (s, &error);
5387 if (!mono_error_ok (&error))
5388 mono_error_raise_exception (&error);
5393 * mono_string_to_utf8_checked:
5394 * @s: a System.String
5395 * @error: a MonoError.
5397 * Converts a MonoString to its UTF8 representation. May fail; check
5398 * @error to determine whether the conversion was successful.
5399 * The resulting buffer should be freed with mono_free().
5402 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5406 GError *gerror = NULL;
5408 mono_error_init (error);
5414 return g_strdup ("");
5416 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5418 mono_error_set_argument (error, "string", "%s", gerror->message);
5419 g_error_free (gerror);
5422 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5423 if (s->length > written) {
5424 /* allocate the total length and copy the part of the string that has been converted */
5425 char *as2 = g_malloc0 (s->length);
5426 memcpy (as2, as, written);
5435 * mono_string_to_utf8_ignore:
5438 * Converts a MonoString to its UTF8 representation. Will ignore
5439 * invalid surrogate pairs.
5440 * The resulting buffer should be freed with mono_free().
5444 mono_string_to_utf8_ignore (MonoString *s)
5453 return g_strdup ("");
5455 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5457 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5458 if (s->length > written) {
5459 /* allocate the total length and copy the part of the string that has been converted */
5460 char *as2 = g_malloc0 (s->length);
5461 memcpy (as2, as, written);
5470 * mono_string_to_utf8_image_ignore:
5471 * @s: a System.String
5473 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5476 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5478 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5482 * mono_string_to_utf8_mp_ignore:
5483 * @s: a System.String
5485 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5488 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5490 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5495 * mono_string_to_utf16:
5498 * Return an null-terminated array of the utf-16 chars
5499 * contained in @s. The result must be freed with g_free().
5500 * This is a temporary helper until our string implementation
5501 * is reworked to always include the null terminating char.
5504 mono_string_to_utf16 (MonoString *s)
5511 as = g_malloc ((s->length * 2) + 2);
5512 as [(s->length * 2)] = '\0';
5513 as [(s->length * 2) + 1] = '\0';
5516 return (gunichar2 *)(as);
5519 memcpy (as, mono_string_chars(s), s->length * 2);
5520 return (gunichar2 *)(as);
5524 * mono_string_from_utf16:
5525 * @data: the UTF16 string (LPWSTR) to convert
5527 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5529 * Returns: a MonoString.
5532 mono_string_from_utf16 (gunichar2 *data)
5534 MonoDomain *domain = mono_domain_get ();
5540 while (data [len]) len++;
5542 return mono_string_new_utf16 (domain, data, len);
5547 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5554 r = mono_string_to_utf8_ignore (s);
5556 r = mono_string_to_utf8_checked (s, error);
5557 if (!mono_error_ok (error))
5564 len = strlen (r) + 1;
5566 mp_s = mono_mempool_alloc (mp, len);
5568 mp_s = mono_image_alloc (image, len);
5570 memcpy (mp_s, r, len);
5578 * mono_string_to_utf8_image:
5579 * @s: a System.String
5581 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5584 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5586 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5590 * mono_string_to_utf8_mp:
5591 * @s: a System.String
5593 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5596 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5598 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5602 default_ex_handler (MonoException *ex)
5604 MonoObject *o = (MonoObject*)ex;
5605 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5609 static MonoExceptionFunc ex_handler = default_ex_handler;
5612 * mono_install_handler:
5613 * @func: exception handler
5615 * This is an internal JIT routine used to install the handler for exceptions
5619 mono_install_handler (MonoExceptionFunc func)
5621 ex_handler = func? func: default_ex_handler;
5625 * mono_raise_exception:
5626 * @ex: exception object
5628 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5631 mono_raise_exception (MonoException *ex)
5634 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5635 * that will cause gcc to omit the function epilog, causing problems when
5636 * the JIT tries to walk the stack, since the return address on the stack
5637 * will point into the next function in the executable, not this one.
5640 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5641 MonoInternalThread *thread = mono_thread_internal_current ();
5642 g_assert (ex->object.vtable->domain == mono_domain_get ());
5643 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5650 * mono_wait_handle_new:
5651 * @domain: Domain where the object will be created
5652 * @handle: Handle for the wait handle
5654 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5657 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5659 MonoWaitHandle *res;
5660 gpointer params [1];
5661 static MonoMethod *handle_set;
5663 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5665 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5667 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5669 params [0] = &handle;
5670 mono_runtime_invoke (handle_set, res, params, NULL);
5676 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5678 static MonoClassField *f_os_handle;
5679 static MonoClassField *f_safe_handle;
5681 if (!f_os_handle && !f_safe_handle) {
5682 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5683 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5688 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5692 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5699 mono_runtime_capture_context (MonoDomain *domain)
5701 RuntimeInvokeFunction runtime_invoke;
5703 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5704 MonoMethod *method = mono_get_context_capture_method ();
5705 MonoMethod *wrapper;
5708 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5709 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5710 domain->capture_context_method = mono_compile_method (method);
5713 runtime_invoke = domain->capture_context_runtime_invoke;
5715 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5718 * mono_async_result_new:
5719 * @domain:domain where the object will be created.
5720 * @handle: wait handle.
5721 * @state: state to pass to AsyncResult
5722 * @data: C closure data.
5724 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5725 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5729 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5731 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5732 MonoObject *context = mono_runtime_capture_context (domain);
5733 /* we must capture the execution context from the original thread */
5735 MONO_OBJECT_SETREF (res, execution_context, context);
5736 /* note: result may be null if the flow is suppressed */
5740 MONO_OBJECT_SETREF (res, object_data, object_data);
5741 MONO_OBJECT_SETREF (res, async_state, state);
5743 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5745 res->sync_completed = FALSE;
5746 res->completed = FALSE;
5752 mono_message_init (MonoDomain *domain,
5753 MonoMethodMessage *this,
5754 MonoReflectionMethod *method,
5755 MonoArray *out_args)
5757 static MonoClass *object_array_klass;
5758 static MonoClass *byte_array_klass;
5759 static MonoClass *string_array_klass;
5760 MonoMethodSignature *sig = mono_method_signature (method->method);
5766 if (!object_array_klass) {
5769 klass = mono_array_class_get (mono_defaults.object_class, 1);
5772 mono_memory_barrier ();
5773 object_array_klass = klass;
5775 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5778 mono_memory_barrier ();
5779 byte_array_klass = klass;
5781 klass = mono_array_class_get (mono_defaults.string_class, 1);
5784 mono_memory_barrier ();
5785 string_array_klass = klass;
5788 MONO_OBJECT_SETREF (this, method, method);
5790 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5791 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5792 this->async_result = NULL;
5793 this->call_type = CallType_Sync;
5795 names = g_new (char *, sig->param_count);
5796 mono_method_get_param_names (method->method, (const char **) names);
5797 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5799 for (i = 0; i < sig->param_count; i++) {
5800 name = mono_string_new (domain, names [i]);
5801 mono_array_setref (this->names, i, name);
5805 for (i = 0, j = 0; i < sig->param_count; i++) {
5806 if (sig->params [i]->byref) {
5808 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5809 mono_array_setref (this->args, i, arg);
5813 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5817 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5820 mono_array_set (this->arg_types, guint8, i, arg_type);
5825 * mono_remoting_invoke:
5826 * @real_proxy: pointer to a RealProxy object
5827 * @msg: The MonoMethodMessage to execute
5828 * @exc: used to store exceptions
5829 * @out_args: used to store output arguments
5831 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5832 * IMessage interface and it is not trivial to extract results from there. So
5833 * we call an helper method PrivateInvoke instead of calling
5834 * RealProxy::Invoke() directly.
5836 * Returns: the result object.
5839 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5840 MonoObject **exc, MonoArray **out_args)
5842 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5845 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5848 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5850 real_proxy->vtable->domain->private_invoke_method = im;
5853 pa [0] = real_proxy;
5858 return mono_runtime_invoke (im, NULL, pa, exc);
5862 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5863 MonoObject **exc, MonoArray **out_args)
5865 static MonoClass *object_array_klass;
5868 MonoMethodSignature *sig;
5870 int i, j, outarg_count = 0;
5872 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5874 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5875 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5876 target = tp->rp->unwrapped_server;
5878 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5882 domain = mono_domain_get ();
5883 method = msg->method->method;
5884 sig = mono_method_signature (method);
5886 for (i = 0; i < sig->param_count; i++) {
5887 if (sig->params [i]->byref)
5891 if (!object_array_klass) {
5894 klass = mono_array_class_get (mono_defaults.object_class, 1);
5897 mono_memory_barrier ();
5898 object_array_klass = klass;
5901 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5902 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5905 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5907 for (i = 0, j = 0; i < sig->param_count; i++) {
5908 if (sig->params [i]->byref) {
5910 arg = mono_array_get (msg->args, gpointer, i);
5911 mono_array_setref (*out_args, j, arg);
5920 * mono_object_to_string:
5922 * @exc: Any exception thrown by ToString (). May be NULL.
5924 * Returns: the result of calling ToString () on an object.
5927 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5929 static MonoMethod *to_string = NULL;
5935 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5937 method = mono_object_get_virtual_method (obj, to_string);
5939 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5943 * mono_print_unhandled_exception:
5944 * @exc: The exception
5946 * Prints the unhandled exception.
5949 mono_print_unhandled_exception (MonoObject *exc)
5952 char *message = (char*)"";
5953 gboolean free_message = FALSE;
5956 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5957 message = g_strdup ("OutOfMemoryException");
5959 str = mono_object_to_string (exc, NULL);
5961 message = mono_string_to_utf8_checked (str, &error);
5962 if (!mono_error_ok (&error)) {
5963 mono_error_cleanup (&error);
5964 message = (char *) "";
5966 free_message = TRUE;
5972 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5973 * exc->vtable->klass->name, message);
5975 g_printerr ("\nUnhandled Exception: %s\n", message);
5982 * mono_delegate_ctor:
5983 * @this: pointer to an uninitialized delegate object
5984 * @target: target object
5985 * @addr: pointer to native code
5988 * Initialize a delegate and sets a specific method, not the one
5989 * associated with addr. This is useful when sharing generic code.
5990 * In that case addr will most probably not be associated with the
5991 * correct instantiation of the method.
5994 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5996 MonoDelegate *delegate = (MonoDelegate *)this;
6003 delegate->method = method;
6005 class = this->vtable->klass;
6006 mono_stats.delegate_creations++;
6008 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6010 method = mono_marshal_get_remoting_invoke (method);
6011 delegate->method_ptr = mono_compile_method (method);
6012 MONO_OBJECT_SETREF (delegate, target, target);
6013 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
6014 method = mono_marshal_get_unbox_wrapper (method);
6015 delegate->method_ptr = mono_compile_method (method);
6016 MONO_OBJECT_SETREF (delegate, target, target);
6018 delegate->method_ptr = addr;
6019 MONO_OBJECT_SETREF (delegate, target, target);
6022 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
6026 * mono_delegate_ctor:
6027 * @this: pointer to an uninitialized delegate object
6028 * @target: target object
6029 * @addr: pointer to native code
6031 * This is used to initialize a delegate.
6034 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6036 MonoDomain *domain = mono_domain_get ();
6038 MonoMethod *method = NULL;
6042 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
6043 method = ji->method;
6044 g_assert (!method->klass->generic_container);
6047 mono_delegate_ctor_with_method (this, target, addr, method);
6051 * mono_method_call_message_new:
6052 * @method: method to encapsulate
6053 * @params: parameters to the method
6054 * @invoke: optional, delegate invoke.
6055 * @cb: async callback delegate.
6056 * @state: state passed to the async callback.
6058 * Translates arguments pointers into a MonoMethodMessage.
6061 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6062 MonoDelegate **cb, MonoObject **state)
6064 MonoDomain *domain = mono_domain_get ();
6065 MonoMethodSignature *sig = mono_method_signature (method);
6066 MonoMethodMessage *msg;
6069 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6072 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6073 count = sig->param_count - 2;
6075 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6076 count = sig->param_count;
6079 for (i = 0; i < count; i++) {
6084 if (sig->params [i]->byref)
6085 vpos = *((gpointer *)params [i]);
6089 type = sig->params [i]->type;
6090 class = mono_class_from_mono_type (sig->params [i]);
6092 if (class->valuetype)
6093 arg = mono_value_box (domain, class, vpos);
6095 arg = *((MonoObject **)vpos);
6097 mono_array_setref (msg->args, i, arg);
6100 if (cb != NULL && state != NULL) {
6101 *cb = *((MonoDelegate **)params [i]);
6103 *state = *((MonoObject **)params [i]);
6110 * mono_method_return_message_restore:
6112 * Restore results from message based processing back to arguments pointers
6115 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6117 MonoMethodSignature *sig = mono_method_signature (method);
6118 int i, j, type, size, out_len;
6120 if (out_args == NULL)
6122 out_len = mono_array_length (out_args);
6126 for (i = 0, j = 0; i < sig->param_count; i++) {
6127 MonoType *pt = sig->params [i];
6132 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6134 arg = mono_array_get (out_args, gpointer, j);
6137 g_assert (type != MONO_TYPE_VOID);
6139 if (MONO_TYPE_IS_REFERENCE (pt)) {
6140 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6143 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6144 size = mono_class_value_size (class, NULL);
6145 if (class->has_references)
6146 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6148 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6150 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6151 memset (*((gpointer *)params [i]), 0, size);
6161 * mono_load_remote_field:
6162 * @this: pointer to an object
6163 * @klass: klass of the object containing @field
6164 * @field: the field to load
6165 * @res: a storage to store the result
6167 * This method is called by the runtime on attempts to load fields of
6168 * transparent proxy objects. @this points to such TP, @klass is the class of
6169 * the object containing @field. @res is a storage location which can be
6170 * used to store the result.
6172 * Returns: an address pointing to the value of field.
6175 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6177 static MonoMethod *getter = NULL;
6178 MonoDomain *domain = mono_domain_get ();
6179 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6180 MonoClass *field_class;
6181 MonoMethodMessage *msg;
6182 MonoArray *out_args;
6186 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6187 g_assert (res != NULL);
6189 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6190 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6195 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6199 field_class = mono_class_from_mono_type (field->type);
6201 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6202 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6203 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6205 full_name = mono_type_get_full_name (klass);
6206 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6207 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6210 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6212 if (exc) mono_raise_exception ((MonoException *)exc);
6214 if (mono_array_length (out_args) == 0)
6217 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6219 if (field_class->valuetype) {
6220 return ((char *)*res) + sizeof (MonoObject);
6226 * mono_load_remote_field_new:
6231 * Missing documentation.
6234 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6236 static MonoMethod *getter = NULL;
6237 MonoDomain *domain = mono_domain_get ();
6238 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6239 MonoClass *field_class;
6240 MonoMethodMessage *msg;
6241 MonoArray *out_args;
6242 MonoObject *exc, *res;
6245 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6247 field_class = mono_class_from_mono_type (field->type);
6249 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6251 if (field_class->valuetype) {
6252 res = mono_object_new (domain, field_class);
6253 val = ((gchar *) res) + sizeof (MonoObject);
6257 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6262 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6266 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6267 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6269 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6271 full_name = mono_type_get_full_name (klass);
6272 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6273 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6276 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6278 if (exc) mono_raise_exception ((MonoException *)exc);
6280 if (mono_array_length (out_args) == 0)
6283 res = mono_array_get (out_args, MonoObject *, 0);
6289 * mono_store_remote_field:
6290 * @this: pointer to an object
6291 * @klass: klass of the object containing @field
6292 * @field: the field to load
6293 * @val: the value/object to store
6295 * This method is called by the runtime on attempts to store fields of
6296 * transparent proxy objects. @this points to such TP, @klass is the class of
6297 * the object containing @field. @val is the new value to store in @field.
6300 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6302 static MonoMethod *setter = NULL;
6303 MonoDomain *domain = mono_domain_get ();
6304 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6305 MonoClass *field_class;
6306 MonoMethodMessage *msg;
6307 MonoArray *out_args;
6312 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6314 field_class = mono_class_from_mono_type (field->type);
6316 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6317 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6318 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6323 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6327 if (field_class->valuetype)
6328 arg = mono_value_box (domain, field_class, val);
6330 arg = *((MonoObject **)val);
6333 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6334 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6336 full_name = mono_type_get_full_name (klass);
6337 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6338 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6339 mono_array_setref (msg->args, 2, arg);
6342 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6344 if (exc) mono_raise_exception ((MonoException *)exc);
6348 * mono_store_remote_field_new:
6354 * Missing documentation
6357 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6359 static MonoMethod *setter = NULL;
6360 MonoDomain *domain = mono_domain_get ();
6361 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6362 MonoClass *field_class;
6363 MonoMethodMessage *msg;
6364 MonoArray *out_args;
6368 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6370 field_class = mono_class_from_mono_type (field->type);
6372 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6373 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6374 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6379 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6383 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6384 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6386 full_name = mono_type_get_full_name (klass);
6387 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6388 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6389 mono_array_setref (msg->args, 2, arg);
6392 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6394 if (exc) mono_raise_exception ((MonoException *)exc);
6398 * mono_create_ftnptr:
6400 * Given a function address, create a function descriptor for it.
6401 * This is only needed on some platforms.
6404 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6406 return callbacks.create_ftnptr (domain, addr);
6410 * mono_get_addr_from_ftnptr:
6412 * Given a pointer to a function descriptor, return the function address.
6413 * This is only needed on some platforms.
6416 mono_get_addr_from_ftnptr (gpointer descr)
6418 return callbacks.get_addr_from_ftnptr (descr);
6422 * mono_string_chars:
6425 * Returns a pointer to the UCS16 characters stored in the MonoString
6428 mono_string_chars (MonoString *s)
6434 * mono_string_length:
6437 * Returns the lenght in characters of the string
6440 mono_string_length (MonoString *s)
6446 * mono_array_length:
6447 * @array: a MonoArray*
6449 * Returns the total number of elements in the array. This works for
6450 * both vectors and multidimensional arrays.
6453 mono_array_length (MonoArray *array)
6455 return array->max_length;
6459 * mono_array_addr_with_size:
6460 * @array: a MonoArray*
6461 * @size: size of the array elements
6462 * @idx: index into the array
6464 * Returns the address of the @idx element in the array.
6467 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6469 return ((char*)(array)->vector) + size * idx;