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);
85 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
86 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
87 static CRITICAL_SECTION ldstr_section;
89 static gboolean profile_allocs = TRUE;
92 mono_runtime_object_init (MonoObject *this)
94 MonoMethod *method = NULL;
95 MonoClass *klass = this->vtable->klass;
97 method = mono_class_get_method_from_name (klass, ".ctor", 0);
100 if (method->klass->valuetype)
101 this = mono_object_unbox (this);
102 mono_runtime_invoke (method, this, NULL, NULL);
105 /* The pseudo algorithm for type initialization from the spec
106 Note it doesn't say anything about domains - only threads.
108 2. If the type is initialized you are done.
109 2.1. If the type is not yet initialized, try to take an
111 2.2. If successful, record this thread as responsible for
112 initializing the type and proceed to step 2.3.
113 2.2.1. If not, see whether this thread or any thread
114 waiting for this thread to complete already holds the lock.
115 2.2.2. If so, return since blocking would create a deadlock. This thread
116 will now see an incompletely initialized state for the type,
117 but no deadlock will arise.
118 2.2.3 If not, block until the type is initialized then return.
119 2.3 Initialize the parent type and then all interfaces implemented
121 2.4 Execute the type initialization code for this type.
122 2.5 Mark the type as initialized, release the initialization lock,
123 awaken any threads waiting for this type to be initialized,
130 guint32 initializing_tid;
131 guint32 waiting_count;
133 CRITICAL_SECTION initialization_section;
134 } TypeInitializationLock;
136 /* for locking access to type_initialization_hash and blocked_thread_hash */
137 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
138 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
139 static CRITICAL_SECTION type_initialization_section;
141 /* from vtable to lock */
142 static GHashTable *type_initialization_hash;
144 /* from thread id to thread id being waited on */
145 static GHashTable *blocked_thread_hash;
148 static MonoThread *main_thread;
150 /* Functions supplied by the runtime */
151 static MonoRuntimeCallbacks callbacks;
154 * mono_thread_set_main:
155 * @thread: thread to set as the main thread
157 * This function can be used to instruct the runtime to treat @thread
158 * as the main thread, ie, the thread that would normally execute the Main()
159 * method. This basically means that at the end of @thread, the runtime will
160 * wait for the existing foreground threads to quit and other such details.
163 mono_thread_set_main (MonoThread *thread)
165 main_thread = thread;
169 mono_thread_get_main (void)
175 mono_type_initialization_init (void)
177 InitializeCriticalSection (&type_initialization_section);
178 type_initialization_hash = g_hash_table_new (NULL, NULL);
179 blocked_thread_hash = g_hash_table_new (NULL, NULL);
180 InitializeCriticalSection (&ldstr_section);
184 mono_type_initialization_cleanup (void)
187 /* This is causing race conditions with
188 * mono_release_type_locks
190 DeleteCriticalSection (&type_initialization_section);
191 g_hash_table_destroy (type_initialization_hash);
192 type_initialization_hash = NULL;
194 DeleteCriticalSection (&ldstr_section);
195 g_hash_table_destroy (blocked_thread_hash);
196 blocked_thread_hash = NULL;
202 * get_type_init_exception_for_vtable:
204 * Return the stored type initialization exception for VTABLE.
206 static MonoException*
207 get_type_init_exception_for_vtable (MonoVTable *vtable)
209 MonoDomain *domain = vtable->domain;
210 MonoClass *klass = vtable->klass;
214 g_assert (vtable->init_failed);
217 * If the initializing thread was rudely aborted, the exception is not stored
221 mono_domain_lock (domain);
222 if (domain->type_init_exception_hash)
223 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
224 mono_domain_unlock (domain);
227 if (klass->name_space && *klass->name_space)
228 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
230 full_name = g_strdup (klass->name);
231 ex = mono_get_exception_type_initialization (full_name, NULL);
238 * mono_runtime_class_init:
239 * @vtable: vtable that needs to be initialized
241 * This routine calls the class constructor for @vtable.
244 mono_runtime_class_init (MonoVTable *vtable)
246 mono_runtime_class_init_full (vtable, TRUE);
250 * mono_runtime_class_init_full:
251 * @vtable that neeeds to be initialized
252 * @raise_exception is TRUE, exceptions are raised intead of returned
256 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
259 MonoException *exc_to_throw;
260 MonoMethod *method = NULL;
266 if (vtable->initialized)
270 klass = vtable->klass;
272 if (!klass->image->checked_module_cctor) {
273 mono_image_check_for_module_cctor (klass->image);
274 if (klass->image->has_module_cctor) {
275 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
276 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
279 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
284 method = mono_class_get_cctor (klass);
287 MonoDomain *domain = vtable->domain;
288 TypeInitializationLock *lock;
289 guint32 tid = GetCurrentThreadId();
290 int do_initialization = 0;
291 MonoDomain *last_domain = NULL;
293 mono_type_initialization_lock ();
294 /* double check... */
295 if (vtable->initialized) {
296 mono_type_initialization_unlock ();
299 if (vtable->init_failed) {
300 mono_type_initialization_unlock ();
302 /* The type initialization already failed once, rethrow the same exception */
304 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
305 return get_type_init_exception_for_vtable (vtable);
307 lock = g_hash_table_lookup (type_initialization_hash, vtable);
309 /* This thread will get to do the initialization */
310 if (mono_domain_get () != domain) {
311 /* Transfer into the target domain */
312 last_domain = mono_domain_get ();
313 if (!mono_domain_set (domain, FALSE)) {
314 vtable->initialized = 1;
315 mono_type_initialization_unlock ();
317 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
318 return mono_get_exception_appdomain_unloaded ();
321 lock = g_malloc (sizeof(TypeInitializationLock));
322 InitializeCriticalSection (&lock->initialization_section);
323 lock->initializing_tid = tid;
324 lock->waiting_count = 1;
326 /* grab the vtable lock while this thread still owns type_initialization_section */
327 EnterCriticalSection (&lock->initialization_section);
328 g_hash_table_insert (type_initialization_hash, vtable, lock);
329 do_initialization = 1;
332 TypeInitializationLock *pending_lock;
334 if (lock->initializing_tid == tid || lock->done) {
335 mono_type_initialization_unlock ();
338 /* see if the thread doing the initialization is already blocked on this thread */
339 blocked = GUINT_TO_POINTER (lock->initializing_tid);
340 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
341 if (pending_lock->initializing_tid == tid) {
342 if (!pending_lock->done) {
343 mono_type_initialization_unlock ();
346 /* the thread doing the initialization is blocked on this thread,
347 but on a lock that has already been freed. It just hasn't got
352 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
354 ++lock->waiting_count;
355 /* record the fact that we are waiting on the initializing thread */
356 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
358 mono_type_initialization_unlock ();
360 if (do_initialization) {
361 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
363 /* If the initialization failed, mark the class as unusable. */
364 /* Avoid infinite loops */
366 (klass->image == mono_defaults.corlib &&
367 !strcmp (klass->name_space, "System") &&
368 !strcmp (klass->name, "TypeInitializationException")))) {
369 vtable->init_failed = 1;
371 if (klass->name_space && *klass->name_space)
372 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
374 full_name = g_strdup (klass->name);
375 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
379 * Store the exception object so it could be thrown on subsequent
382 mono_domain_lock (domain);
383 if (!domain->type_init_exception_hash)
384 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
385 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
386 mono_domain_unlock (domain);
390 mono_domain_set (last_domain, TRUE);
392 LeaveCriticalSection (&lock->initialization_section);
394 /* this just blocks until the initializing thread is done */
395 EnterCriticalSection (&lock->initialization_section);
396 LeaveCriticalSection (&lock->initialization_section);
399 mono_type_initialization_lock ();
400 if (lock->initializing_tid != tid)
401 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
402 --lock->waiting_count;
403 if (lock->waiting_count == 0) {
404 DeleteCriticalSection (&lock->initialization_section);
405 g_hash_table_remove (type_initialization_hash, vtable);
408 if (!vtable->init_failed)
409 vtable->initialized = 1;
410 mono_type_initialization_unlock ();
412 if (vtable->init_failed) {
413 /* Either we were the initializing thread or we waited for the initialization */
415 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
416 return get_type_init_exception_for_vtable (vtable);
419 vtable->initialized = 1;
426 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
428 MonoVTable *vtable = (MonoVTable*)key;
430 TypeInitializationLock *lock = (TypeInitializationLock*) value;
431 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
434 * Have to set this since it cannot be set by the normal code in
435 * mono_runtime_class_init (). In this case, the exception object is not stored,
436 * and get_type_init_exception_for_class () needs to be aware of this.
438 vtable->init_failed = 1;
439 LeaveCriticalSection (&lock->initialization_section);
440 --lock->waiting_count;
441 if (lock->waiting_count == 0) {
442 DeleteCriticalSection (&lock->initialization_section);
451 mono_release_type_locks (MonoInternalThread *thread)
453 mono_type_initialization_lock ();
454 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
455 mono_type_initialization_unlock ();
459 default_trampoline (MonoMethod *method)
465 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
467 g_assert_not_reached ();
473 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
475 g_error ("remoting not installed");
480 default_delegate_trampoline (MonoClass *klass)
482 g_assert_not_reached ();
486 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
487 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
488 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
489 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
490 static MonoImtThunkBuilder imt_thunk_builder = NULL;
491 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
492 #if (MONO_IMT_SIZE > 32)
493 #error "MONO_IMT_SIZE cannot be larger than 32"
497 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
499 memcpy (&callbacks, cbs, sizeof (*cbs));
502 MonoRuntimeCallbacks*
503 mono_get_runtime_callbacks (void)
509 mono_install_trampoline (MonoTrampoline func)
511 arch_create_jit_trampoline = func? func: default_trampoline;
515 mono_install_jump_trampoline (MonoJumpTrampoline func)
517 arch_create_jump_trampoline = func? func: default_jump_trampoline;
521 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
523 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
527 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
529 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
533 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
534 imt_thunk_builder = func;
537 static MonoCompileFunc default_mono_compile_method = NULL;
540 * mono_install_compile_method:
541 * @func: function to install
543 * This is a VM internal routine
546 mono_install_compile_method (MonoCompileFunc func)
548 default_mono_compile_method = func;
552 * mono_compile_method:
553 * @method: The method to compile.
555 * This JIT-compiles the method, and returns the pointer to the native code
559 mono_compile_method (MonoMethod *method)
561 if (!default_mono_compile_method) {
562 g_error ("compile method called on uninitialized runtime");
565 return default_mono_compile_method (method);
569 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
571 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
575 mono_runtime_create_delegate_trampoline (MonoClass *klass)
577 return arch_create_delegate_trampoline (klass);
580 static MonoFreeMethodFunc default_mono_free_method = NULL;
583 * mono_install_free_method:
584 * @func: pointer to the MonoFreeMethodFunc used to release a method
586 * This is an internal VM routine, it is used for the engines to
587 * register a handler to release the resources associated with a method.
589 * Methods are freed when no more references to the delegate that holds
593 mono_install_free_method (MonoFreeMethodFunc func)
595 default_mono_free_method = func;
599 * mono_runtime_free_method:
600 * @domain; domain where the method is hosted
601 * @method: method to release
603 * This routine is invoked to free the resources associated with
604 * a method that has been JIT compiled. This is used to discard
605 * methods that were used only temporarily (for example, used in marshalling)
609 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
611 if (default_mono_free_method != NULL)
612 default_mono_free_method (domain, method);
614 mono_method_clear_object (domain, method);
616 mono_free_method (method);
620 * The vtables in the root appdomain are assumed to be reachable by other
621 * roots, and we don't use typed allocation in the other domains.
624 /* The sync block is no longer a GC pointer */
625 #define GC_HEADER_BITMAP (0)
627 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
630 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
632 MonoClassField *field;
638 max_size = mono_class_data_size (class) / sizeof (gpointer);
640 max_size = class->instance_size / sizeof (gpointer);
641 if (max_size > size) {
642 g_assert (offset <= 0);
643 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
648 /*An Ephemeron cannot be marked by sgen*/
649 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
651 memset (bitmap, 0, size / 8);
656 for (p = class; p != NULL; p = p->parent) {
657 gpointer iter = NULL;
658 while ((field = mono_class_get_fields (p, &iter))) {
662 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
664 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
667 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
670 /* FIXME: should not happen, flag as type load error */
671 if (field->type->byref)
674 if (static_fields && field->offset == -1)
678 pos = field->offset / sizeof (gpointer);
681 type = mono_type_get_underlying_type (field->type);
682 switch (type->type) {
685 case MONO_TYPE_FNPTR:
687 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
692 if (class->image != mono_defaults.corlib)
695 case MONO_TYPE_STRING:
696 case MONO_TYPE_SZARRAY:
697 case MONO_TYPE_CLASS:
698 case MONO_TYPE_OBJECT:
699 case MONO_TYPE_ARRAY:
700 g_assert ((field->offset % sizeof(gpointer)) == 0);
702 g_assert (pos < size || pos <= max_size);
703 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
704 *max_set = MAX (*max_set, pos);
706 case MONO_TYPE_GENERICINST:
707 if (!mono_type_generic_inst_is_valuetype (type)) {
708 g_assert ((field->offset % sizeof(gpointer)) == 0);
710 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
711 *max_set = MAX (*max_set, pos);
716 case MONO_TYPE_VALUETYPE: {
717 MonoClass *fclass = mono_class_from_mono_type (field->type);
718 if (fclass->has_references) {
719 /* remove the object header */
720 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
734 case MONO_TYPE_BOOLEAN:
738 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
750 * similar to the above, but sets the bits in the bitmap for any non-ref field
751 * and ignores static fields
754 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
756 MonoClassField *field;
761 max_size = class->instance_size / sizeof (gpointer);
762 if (max_size >= size) {
763 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
766 for (p = class; p != NULL; p = p->parent) {
767 gpointer iter = NULL;
768 while ((field = mono_class_get_fields (p, &iter))) {
771 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
773 /* FIXME: should not happen, flag as type load error */
774 if (field->type->byref)
777 pos = field->offset / sizeof (gpointer);
780 type = mono_type_get_underlying_type (field->type);
781 switch (type->type) {
782 #if SIZEOF_VOID_P == 8
786 case MONO_TYPE_FNPTR:
791 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
792 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
793 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
796 #if SIZEOF_VOID_P == 4
800 case MONO_TYPE_FNPTR:
805 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
806 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
807 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
813 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
814 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
815 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
818 case MONO_TYPE_BOOLEAN:
821 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
823 case MONO_TYPE_STRING:
824 case MONO_TYPE_SZARRAY:
825 case MONO_TYPE_CLASS:
826 case MONO_TYPE_OBJECT:
827 case MONO_TYPE_ARRAY:
829 case MONO_TYPE_GENERICINST:
830 if (!mono_type_generic_inst_is_valuetype (type)) {
835 case MONO_TYPE_VALUETYPE: {
836 MonoClass *fclass = mono_class_from_mono_type (field->type);
837 /* remove the object header */
838 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
842 g_assert_not_reached ();
851 * mono_class_insecure_overlapping:
852 * check if a class with explicit layout has references and non-references
853 * fields overlapping.
855 * Returns: TRUE if it is insecure to load the type.
858 mono_class_insecure_overlapping (MonoClass *klass)
862 gsize default_bitmap [4] = {0};
864 gsize default_nrbitmap [4] = {0};
865 int i, insecure = FALSE;
868 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
869 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
871 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
872 int idx = i % (sizeof (bitmap [0]) * 8);
873 if (bitmap [idx] & nrbitmap [idx]) {
878 if (bitmap != default_bitmap)
880 if (nrbitmap != default_nrbitmap)
883 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
891 mono_string_alloc (int length)
893 return mono_string_new_size (mono_domain_get (), length);
897 mono_class_compute_gc_descriptor (MonoClass *class)
901 gsize default_bitmap [4] = {0};
902 static gboolean gcj_inited = FALSE;
907 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
908 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
909 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
910 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
912 #ifdef HAVE_GC_GCJ_MALLOC
914 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
918 #ifdef GC_REDIRECT_TO_LOCAL
919 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
920 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
922 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
923 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
928 mono_loader_unlock ();
932 mono_class_init (class);
934 if (class->gc_descr_inited)
937 class->gc_descr_inited = TRUE;
938 class->gc_descr = GC_NO_DESCRIPTOR;
940 bitmap = default_bitmap;
941 if (class == mono_defaults.string_class) {
942 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
943 } else if (class->rank) {
944 mono_class_compute_gc_descriptor (class->element_class);
945 if (!class->element_class->valuetype) {
947 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
948 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
949 class->name_space, class->name);*/
951 /* remove the object header */
952 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
953 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
954 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
955 class->name_space, class->name);*/
956 if (bitmap != default_bitmap)
960 /*static int count = 0;
963 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
964 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
966 if (class->gc_descr == GC_NO_DESCRIPTOR)
967 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
969 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
970 if (bitmap != default_bitmap)
976 * field_is_special_static:
977 * @fklass: The MonoClass to look up.
978 * @field: The MonoClassField describing the field.
980 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
981 * SPECIAL_STATIC_NONE otherwise.
984 field_is_special_static (MonoClass *fklass, MonoClassField *field)
986 MonoCustomAttrInfo *ainfo;
988 ainfo = mono_custom_attrs_from_field (fklass, field);
991 for (i = 0; i < ainfo->num_attrs; ++i) {
992 MonoClass *klass = ainfo->attrs [i].ctor->klass;
993 if (klass->image == mono_defaults.corlib) {
994 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
995 mono_custom_attrs_free (ainfo);
996 return SPECIAL_STATIC_THREAD;
998 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
999 mono_custom_attrs_free (ainfo);
1000 return SPECIAL_STATIC_CONTEXT;
1004 mono_custom_attrs_free (ainfo);
1005 return SPECIAL_STATIC_NONE;
1008 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1009 #define mix(a,b,c) { \
1010 a -= c; a ^= rot(c, 4); c += b; \
1011 b -= a; b ^= rot(a, 6); a += c; \
1012 c -= b; c ^= rot(b, 8); b += a; \
1013 a -= c; a ^= rot(c,16); c += b; \
1014 b -= a; b ^= rot(a,19); a += c; \
1015 c -= b; c ^= rot(b, 4); b += a; \
1017 #define final(a,b,c) { \
1018 c ^= b; c -= rot(b,14); \
1019 a ^= c; a -= rot(c,11); \
1020 b ^= a; b -= rot(a,25); \
1021 c ^= b; c -= rot(b,16); \
1022 a ^= c; a -= rot(c,4); \
1023 b ^= a; b -= rot(a,14); \
1024 c ^= b; c -= rot(b,24); \
1028 * mono_method_get_imt_slot:
1030 * The IMT slot is embedded into AOTed code, so this must return the same value
1031 * for the same method across all executions. This means:
1032 * - pointers shouldn't be used as hash values.
1033 * - mono_metadata_str_hash () should be used for hashing strings.
1036 mono_method_get_imt_slot (MonoMethod *method)
1038 MonoMethodSignature *sig;
1040 guint32 *hashes_start, *hashes;
1044 /* This can be used to stress tests the collision code */
1048 * We do this to simplify generic sharing. It will hurt
1049 * performance in cases where a class implements two different
1050 * instantiations of the same generic interface.
1051 * The code in build_imt_slots () depends on this.
1053 if (method->is_inflated)
1054 method = ((MonoMethodInflated*)method)->declaring;
1056 sig = mono_method_signature (method);
1057 hashes_count = sig->param_count + 4;
1058 hashes_start = malloc (hashes_count * sizeof (guint32));
1059 hashes = hashes_start;
1061 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1062 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1063 method->klass->name_space, method->klass->name, method->name);
1064 g_assert_not_reached ();
1067 /* Initialize hashes */
1068 hashes [0] = mono_metadata_str_hash (method->klass->name);
1069 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1070 hashes [2] = mono_metadata_str_hash (method->name);
1071 hashes [3] = mono_metadata_type_hash (sig->ret);
1072 for (i = 0; i < sig->param_count; i++) {
1073 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1076 /* Setup internal state */
1077 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1079 /* Handle most of the hashes */
1080 while (hashes_count > 3) {
1089 /* Handle the last 3 hashes (all the case statements fall through) */
1090 switch (hashes_count) {
1091 case 3 : c += hashes [2];
1092 case 2 : b += hashes [1];
1093 case 1 : a += hashes [0];
1095 case 0: /* nothing left to add */
1099 free (hashes_start);
1100 /* Report the result */
1101 return c % MONO_IMT_SIZE;
1110 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1111 guint32 imt_slot = mono_method_get_imt_slot (method);
1112 MonoImtBuilderEntry *entry;
1114 if (slot_num >= 0 && imt_slot != slot_num) {
1115 /* we build just a single imt slot and this is not it */
1119 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1120 entry->key = method;
1121 entry->value.vtable_slot = vtable_slot;
1122 entry->next = imt_builder [imt_slot];
1123 if (imt_builder [imt_slot] != NULL) {
1124 entry->children = imt_builder [imt_slot]->children + 1;
1125 if (entry->children == 1) {
1126 mono_stats.imt_slots_with_collisions++;
1127 *imt_collisions_bitmap |= (1 << imt_slot);
1130 entry->children = 0;
1131 mono_stats.imt_used_slots++;
1133 imt_builder [imt_slot] = entry;
1136 char *method_name = mono_method_full_name (method, TRUE);
1137 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1138 method, method_name, imt_slot, vtable_slot, entry->children);
1139 g_free (method_name);
1146 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1148 MonoMethod *method = e->key;
1149 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1153 method->klass->name_space,
1154 method->klass->name,
1157 printf (" * %s: NULL\n", message);
1163 compare_imt_builder_entries (const void *p1, const void *p2) {
1164 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1165 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1167 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1171 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1173 int count = end - start;
1174 int chunk_start = out_array->len;
1177 for (i = start; i < end; ++i) {
1178 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1179 item->key = sorted_array [i]->key;
1180 item->value = sorted_array [i]->value;
1181 item->has_target_code = sorted_array [i]->has_target_code;
1182 item->is_equals = TRUE;
1184 item->check_target_idx = out_array->len + 1;
1186 item->check_target_idx = 0;
1187 g_ptr_array_add (out_array, item);
1190 int middle = start + count / 2;
1191 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1193 item->key = sorted_array [middle]->key;
1194 item->is_equals = FALSE;
1195 g_ptr_array_add (out_array, item);
1196 imt_emit_ir (sorted_array, start, middle, out_array);
1197 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1203 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1204 int number_of_entries = entries->children + 1;
1205 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1206 GPtrArray *result = g_ptr_array_new ();
1207 MonoImtBuilderEntry *current_entry;
1210 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1211 sorted_array [i] = current_entry;
1213 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1215 /*for (i = 0; i < number_of_entries; i++) {
1216 print_imt_entry (" sorted array:", sorted_array [i], i);
1219 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1221 free (sorted_array);
1226 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1228 if (imt_builder_entry != NULL) {
1229 if (imt_builder_entry->children == 0 && !fail_tramp) {
1230 /* No collision, return the vtable slot contents */
1231 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1233 /* Collision, build the thunk */
1234 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1237 result = imt_thunk_builder (vtable, domain,
1238 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1239 for (i = 0; i < imt_ir->len; ++i)
1240 g_free (g_ptr_array_index (imt_ir, i));
1241 g_ptr_array_free (imt_ir, TRUE);
1253 static MonoImtBuilderEntry*
1254 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1257 * LOCKING: requires the loader and domain locks.
1261 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1265 guint32 imt_collisions_bitmap = 0;
1266 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1267 int method_count = 0;
1268 gboolean record_method_count_for_max_collisions = FALSE;
1269 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1272 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1274 for (i = 0; i < klass->interface_offsets_count; ++i) {
1275 MonoClass *iface = klass->interfaces_packed [i];
1276 int interface_offset = klass->interface_offsets_packed [i];
1277 int method_slot_in_interface, vt_slot;
1279 if (mono_class_has_variant_generic_params (iface))
1280 has_variant_iface = TRUE;
1282 vt_slot = interface_offset;
1283 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1286 if (slot_num >= 0 && iface->is_inflated) {
1288 * The imt slot of the method is the same as for its declaring method,
1289 * see the comment in mono_method_get_imt_slot (), so we can
1290 * avoid inflating methods which will be discarded by
1291 * add_imt_builder_entry anyway.
1293 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1294 if (mono_method_get_imt_slot (method) != slot_num) {
1299 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1300 if (method->is_generic) {
1301 has_generic_virtual = TRUE;
1306 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1307 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1312 if (extra_interfaces) {
1313 int interface_offset = klass->vtable_size;
1315 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1316 MonoClass* iface = list_item->data;
1317 int method_slot_in_interface;
1318 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1319 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1320 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1322 interface_offset += iface->method.count;
1325 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1326 /* overwrite the imt slot only if we're building all the entries or if
1327 * we're building this specific one
1329 if (slot_num < 0 || i == slot_num) {
1330 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1333 if (imt_builder [i]) {
1334 MonoImtBuilderEntry *entry;
1336 /* Link entries with imt_builder [i] */
1337 for (entry = entries; entry->next; entry = entry->next) {
1339 MonoMethod *method = (MonoMethod*)entry->key;
1340 char *method_name = mono_method_full_name (method, TRUE);
1341 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1342 g_free (method_name);
1345 entry->next = imt_builder [i];
1346 entries->children += imt_builder [i]->children + 1;
1348 imt_builder [i] = entries;
1351 if (has_generic_virtual || has_variant_iface) {
1353 * There might be collisions later when the the thunk is expanded.
1355 imt_collisions_bitmap |= (1 << i);
1358 * The IMT thunk might be called with an instance of one of the
1359 * generic virtual methods, so has to fallback to the IMT trampoline.
1361 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1363 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1366 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1370 if (imt_builder [i] != NULL) {
1371 int methods_in_slot = imt_builder [i]->children + 1;
1372 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1373 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1374 record_method_count_for_max_collisions = TRUE;
1376 method_count += methods_in_slot;
1380 mono_stats.imt_number_of_methods += method_count;
1381 if (record_method_count_for_max_collisions) {
1382 mono_stats.imt_method_count_when_max_collisions = method_count;
1385 for (i = 0; i < MONO_IMT_SIZE; i++) {
1386 MonoImtBuilderEntry* entry = imt_builder [i];
1387 while (entry != NULL) {
1388 MonoImtBuilderEntry* next = entry->next;
1394 /* we OR the bitmap since we may build just a single imt slot at a time */
1395 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1399 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1400 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1404 * mono_vtable_build_imt_slot:
1405 * @vtable: virtual object table struct
1406 * @imt_slot: slot in the IMT table
1408 * Fill the given @imt_slot in the IMT table of @vtable with
1409 * a trampoline or a thunk for the case of collisions.
1410 * This is part of the internal mono API.
1412 * LOCKING: Take the domain lock.
1415 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1417 gpointer *imt = (gpointer*)vtable;
1418 imt -= MONO_IMT_SIZE;
1419 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1421 /* no support for extra interfaces: the proxy objects will need
1422 * to build the complete IMT
1423 * Update and heck needs to ahppen inside the proper domain lock, as all
1424 * the changes made to a MonoVTable.
1426 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1427 mono_domain_lock (vtable->domain);
1428 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1429 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1430 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1431 mono_domain_unlock (vtable->domain);
1432 mono_loader_unlock ();
1437 * The first two free list entries both belong to the wait list: The
1438 * first entry is the pointer to the head of the list and the second
1439 * entry points to the last element. That way appending and removing
1440 * the first element are both O(1) operations.
1442 #ifdef MONO_SMALL_CONFIG
1443 #define NUM_FREE_LISTS 6
1445 #define NUM_FREE_LISTS 12
1447 #define FIRST_FREE_LIST_SIZE 64
1448 #define MAX_WAIT_LENGTH 50
1449 #define THUNK_THRESHOLD 10
1452 * LOCKING: The domain lock must be held.
1455 init_thunk_free_lists (MonoDomain *domain)
1457 if (domain->thunk_free_lists)
1459 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1463 list_index_for_size (int item_size)
1466 int size = FIRST_FREE_LIST_SIZE;
1468 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1477 * mono_method_alloc_generic_virtual_thunk:
1479 * @size: size in bytes
1481 * Allocs size bytes to be used for the code of a generic virtual
1482 * thunk. It's either allocated from the domain's code manager or
1483 * reused from a previously invalidated piece.
1485 * LOCKING: The domain lock must be held.
1488 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1490 static gboolean inited = FALSE;
1491 static int generic_virtual_thunks_size = 0;
1495 MonoThunkFreeList **l;
1497 init_thunk_free_lists (domain);
1499 size += sizeof (guint32);
1500 if (size < sizeof (MonoThunkFreeList))
1501 size = sizeof (MonoThunkFreeList);
1503 i = list_index_for_size (size);
1504 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1505 if ((*l)->size >= size) {
1506 MonoThunkFreeList *item = *l;
1508 return ((guint32*)item) + 1;
1512 /* no suitable item found - search lists of larger sizes */
1513 while (++i < NUM_FREE_LISTS) {
1514 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1517 g_assert (item->size > size);
1518 domain->thunk_free_lists [i] = item->next;
1519 return ((guint32*)item) + 1;
1522 /* still nothing found - allocate it */
1524 mono_counters_register ("Generic virtual thunk bytes",
1525 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1528 generic_virtual_thunks_size += size;
1530 p = mono_domain_code_reserve (domain, size);
1537 * LOCKING: The domain lock must be held.
1540 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1543 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1545 init_thunk_free_lists (domain);
1547 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1548 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1549 int length = item->length;
1552 /* unlink the first item from the wait list */
1553 domain->thunk_free_lists [0] = item->next;
1554 domain->thunk_free_lists [0]->length = length - 1;
1556 i = list_index_for_size (item->size);
1558 /* put it in the free list */
1559 item->next = domain->thunk_free_lists [i];
1560 domain->thunk_free_lists [i] = item;
1564 if (domain->thunk_free_lists [1]) {
1565 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1566 domain->thunk_free_lists [0]->length++;
1568 g_assert (!domain->thunk_free_lists [0]);
1570 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1571 domain->thunk_free_lists [0]->length = 1;
1575 typedef struct _GenericVirtualCase {
1579 struct _GenericVirtualCase *next;
1580 } GenericVirtualCase;
1583 * get_generic_virtual_entries:
1585 * Return IMT entries for the generic virtual method instances and
1586 * variant interface methods for vtable slot
1589 static MonoImtBuilderEntry*
1590 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1592 GenericVirtualCase *list;
1593 MonoImtBuilderEntry *entries;
1595 mono_domain_lock (domain);
1596 if (!domain->generic_virtual_cases)
1597 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1599 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1602 for (; list; list = list->next) {
1603 MonoImtBuilderEntry *entry;
1605 if (list->count < THUNK_THRESHOLD)
1608 entry = g_new0 (MonoImtBuilderEntry, 1);
1609 entry->key = list->method;
1610 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1611 entry->has_target_code = 1;
1613 entry->children = entries->children + 1;
1614 entry->next = entries;
1618 mono_domain_unlock (domain);
1620 /* FIXME: Leaking memory ? */
1625 * mono_method_add_generic_virtual_invocation:
1627 * @vtable_slot: pointer to the vtable slot
1628 * @method: the inflated generic virtual method
1629 * @code: the method's code
1631 * Registers a call via unmanaged code to a generic virtual method
1632 * instantiation or variant interface method. If the number of calls reaches a threshold
1633 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1634 * virtual method thunk.
1637 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1638 gpointer *vtable_slot,
1639 MonoMethod *method, gpointer code)
1641 static gboolean inited = FALSE;
1642 static int num_added = 0;
1644 GenericVirtualCase *gvc, *list;
1645 MonoImtBuilderEntry *entries;
1649 mono_domain_lock (domain);
1650 if (!domain->generic_virtual_cases)
1651 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1653 /* Check whether the case was already added */
1654 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1657 if (gvc->method == method)
1662 /* If not found, make a new one */
1664 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1665 gvc->method = method;
1668 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1670 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1673 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1679 if (++gvc->count == THUNK_THRESHOLD) {
1680 gpointer *old_thunk = *vtable_slot;
1681 gpointer vtable_trampoline = NULL;
1682 gpointer imt_trampoline = NULL;
1684 if ((gpointer)vtable_slot < (gpointer)vtable) {
1685 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1686 int imt_slot = MONO_IMT_SIZE + displacement;
1688 /* Force the rebuild of the thunk at the next call */
1689 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1690 *vtable_slot = imt_trampoline;
1692 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1694 entries = get_generic_virtual_entries (domain, vtable_slot);
1696 sorted = imt_sort_slot_entries (entries);
1698 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1702 MonoImtBuilderEntry *next = entries->next;
1707 for (i = 0; i < sorted->len; ++i)
1708 g_free (g_ptr_array_index (sorted, i));
1709 g_ptr_array_free (sorted, TRUE);
1712 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1713 invalidate_generic_virtual_thunk (domain, old_thunk);
1716 mono_domain_unlock (domain);
1719 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1722 * mono_class_vtable:
1723 * @domain: the application domain
1724 * @class: the class to initialize
1726 * VTables are domain specific because we create domain specific code, and
1727 * they contain the domain specific static class data.
1728 * On failure, NULL is returned, and class->exception_type is set.
1731 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1733 return mono_class_vtable_full (domain, class, FALSE);
1737 * mono_class_vtable_full:
1738 * @domain: the application domain
1739 * @class: the class to initialize
1740 * @raise_on_error if an exception should be raised on failure or not
1742 * VTables are domain specific because we create domain specific code, and
1743 * they contain the domain specific static class data.
1746 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1748 MonoClassRuntimeInfo *runtime_info;
1752 if (class->exception_type) {
1754 mono_raise_exception (mono_class_get_exception_for_failure (class));
1758 /* this check can be inlined in jitted code, too */
1759 runtime_info = class->runtime_info;
1760 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1761 return runtime_info->domain_vtables [domain->domain_id];
1762 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1766 * mono_class_try_get_vtable:
1767 * @domain: the application domain
1768 * @class: the class to initialize
1770 * This function tries to get the associated vtable from @class if
1771 * it was already created.
1774 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1776 MonoClassRuntimeInfo *runtime_info;
1780 runtime_info = class->runtime_info;
1781 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1782 return runtime_info->domain_vtables [domain->domain_id];
1787 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1790 MonoClassRuntimeInfo *runtime_info, *old_info;
1791 MonoClassField *field;
1794 int imt_table_bytes = 0;
1795 guint32 vtable_size, class_size;
1798 gpointer *interface_offsets;
1800 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1801 mono_domain_lock (domain);
1802 runtime_info = class->runtime_info;
1803 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1804 mono_domain_unlock (domain);
1805 mono_loader_unlock ();
1806 return runtime_info->domain_vtables [domain->domain_id];
1808 if (!class->inited || class->exception_type) {
1809 if (!mono_class_init (class) || class->exception_type) {
1810 mono_domain_unlock (domain);
1811 mono_loader_unlock ();
1813 mono_raise_exception (mono_class_get_exception_for_failure (class));
1818 /* Array types require that their element type be valid*/
1819 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1820 MonoClass *element_class = class->element_class;
1821 if (!element_class->inited)
1822 mono_class_init (element_class);
1824 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1825 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1826 mono_class_setup_vtable (element_class);
1828 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1829 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1830 if (class->exception_type == MONO_EXCEPTION_NONE)
1831 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1832 mono_domain_unlock (domain);
1833 mono_loader_unlock ();
1835 mono_raise_exception (mono_class_get_exception_for_failure (class));
1841 * For some classes, mono_class_init () already computed class->vtable_size, and
1842 * that is all that is needed because of the vtable trampolines.
1844 if (!class->vtable_size)
1845 mono_class_setup_vtable (class);
1847 if (class->generic_class && !class->vtable)
1848 mono_class_check_vtable_constraints (class, NULL);
1850 if (class->exception_type) {
1851 mono_domain_unlock (domain);
1852 mono_loader_unlock ();
1854 mono_raise_exception (mono_class_get_exception_for_failure (class));
1859 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1860 if (class->interface_offsets_count) {
1861 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1862 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1863 mono_stats.imt_number_of_tables++;
1864 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1867 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1868 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1871 mono_stats.used_class_count++;
1872 mono_stats.class_vtable_size += vtable_size;
1873 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1876 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1878 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1880 vt->rank = class->rank;
1881 vt->domain = domain;
1883 mono_class_compute_gc_descriptor (class);
1885 * We can't use typed allocation in the non-root domains, since the
1886 * collector needs the GC descriptor stored in the vtable even after
1887 * the mempool containing the vtable is destroyed when the domain is
1888 * unloaded. An alternative might be to allocate vtables in the GC
1889 * heap, but this does not seem to work (it leads to crashes inside
1890 * libgc). If that approach is tried, two gc descriptors need to be
1891 * allocated for each class: one for the root domain, and one for all
1892 * other domains. The second descriptor should contain a bit for the
1893 * vtable field in MonoObject, since we can no longer assume the
1894 * vtable is reachable by other roots after the appdomain is unloaded.
1896 #ifdef HAVE_BOEHM_GC
1897 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1898 vt->gc_descr = GC_NO_DESCRIPTOR;
1901 vt->gc_descr = class->gc_descr;
1903 if ((class_size = mono_class_data_size (class))) {
1904 if (class->has_static_refs) {
1905 gpointer statics_gc_descr;
1907 gsize default_bitmap [4] = {0};
1910 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1911 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1912 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1913 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1914 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1915 if (bitmap != default_bitmap)
1918 vt->data = mono_domain_alloc0 (domain, class_size);
1920 mono_stats.class_static_data_size += class_size;
1925 while ((field = mono_class_get_fields (class, &iter))) {
1926 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1928 if (mono_field_is_deleted (field))
1930 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1931 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1932 if (special_static != SPECIAL_STATIC_NONE) {
1933 guint32 size, offset;
1935 gsize default_bitmap [4] = {0};
1939 if (mono_type_is_reference (field->type)) {
1940 default_bitmap [0] = 1;
1942 bitmap = default_bitmap;
1943 } else if (mono_type_is_struct (field->type)) {
1944 fclass = mono_class_from_mono_type (field->type);
1945 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1947 default_bitmap [0] = 0;
1949 bitmap = default_bitmap;
1951 size = mono_type_size (field->type, &align);
1952 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1953 if (!domain->special_static_fields)
1954 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1955 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1956 if (bitmap != default_bitmap)
1959 * This marks the field as special static to speed up the
1960 * checks in mono_field_static_get/set_value ().
1966 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1967 MonoClass *fklass = mono_class_from_mono_type (field->type);
1968 const char *data = mono_field_get_data (field);
1970 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1971 t = (char*)vt->data + field->offset;
1972 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1975 if (fklass->valuetype) {
1976 memcpy (t, data, mono_class_value_size (fklass, NULL));
1978 /* it's a pointer type: add check */
1979 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1986 vt->max_interface_id = class->max_interface_id;
1987 vt->interface_bitmap = class->interface_bitmap;
1989 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1990 // class->name, class->interface_offsets_count);
1992 if (! ARCH_USE_IMT) {
1993 /* initialize interface offsets */
1994 for (i = 0; i < class->interface_offsets_count; ++i) {
1995 int interface_id = class->interfaces_packed [i]->interface_id;
1996 int slot = class->interface_offsets_packed [i];
1997 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2001 /* class_vtable_array keeps an array of created vtables
2003 g_ptr_array_add (domain->class_vtable_array, vt);
2004 /* class->runtime_info is protected by the loader lock, both when
2005 * it it enlarged and when it is stored info.
2008 old_info = class->runtime_info;
2009 if (old_info && old_info->max_domain >= domain->domain_id) {
2010 /* someone already created a large enough runtime info */
2011 mono_memory_barrier ();
2012 old_info->domain_vtables [domain->domain_id] = vt;
2014 int new_size = domain->domain_id;
2016 new_size = MAX (new_size, old_info->max_domain);
2018 /* make the new size a power of two */
2020 while (new_size > i)
2023 /* this is a bounded memory retention issue: may want to
2024 * handle it differently when we'll have a rcu-like system.
2026 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2027 runtime_info->max_domain = new_size - 1;
2028 /* copy the stuff from the older info */
2030 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2032 runtime_info->domain_vtables [domain->domain_id] = vt;
2034 mono_memory_barrier ();
2035 class->runtime_info = runtime_info;
2038 /* Initialize vtable */
2039 if (callbacks.get_vtable_trampoline) {
2040 // This also covers the AOT case
2041 for (i = 0; i < class->vtable_size; ++i) {
2042 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2045 mono_class_setup_vtable (class);
2047 for (i = 0; i < class->vtable_size; ++i) {
2050 if ((cm = class->vtable [i]))
2051 vt->vtable [i] = arch_create_jit_trampoline (cm);
2055 if (ARCH_USE_IMT && imt_table_bytes) {
2056 /* Now that the vtable is full, we can actually fill up the IMT */
2057 if (callbacks.get_imt_trampoline) {
2058 /* lazy construction of the IMT entries enabled */
2059 for (i = 0; i < MONO_IMT_SIZE; ++i)
2060 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2062 build_imt (class, vt, domain, interface_offsets, NULL);
2066 mono_domain_unlock (domain);
2067 mono_loader_unlock ();
2069 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2070 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2071 mono_raise_exception (mono_class_get_exception_for_failure (class));
2073 /* make sure the parent is initialized */
2074 /*FIXME shouldn't this fail the current type?*/
2076 mono_class_vtable_full (domain, class->parent, raise_on_error);
2078 /*FIXME check for OOM*/
2079 vt->type = mono_type_get_object (domain, &class->byval_arg);
2081 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2082 static void *type_desc = NULL;
2086 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2089 /* This is unregistered in
2090 unregister_vtable_reflection_type() in
2092 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2095 if (class->contextbound)
2104 * mono_class_proxy_vtable:
2105 * @domain: the application domain
2106 * @remove_class: the remote class
2108 * Creates a vtable for transparent proxies. It is basically
2109 * a copy of the real vtable of the class wrapped in @remote_class,
2110 * but all function pointers invoke the remoting functions, and
2111 * vtable->klass points to the transparent proxy class, and not to @class.
2114 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2117 MonoVTable *vt, *pvt;
2118 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2120 GSList *extra_interfaces = NULL;
2121 MonoClass *class = remote_class->proxy_class;
2122 gpointer *interface_offsets;
2126 #ifdef COMPRESSED_INTERFACE_BITMAP
2130 vt = mono_class_vtable (domain, class);
2131 g_assert (vt); /*FIXME property handle failure*/
2132 max_interface_id = vt->max_interface_id;
2134 /* Calculate vtable space for extra interfaces */
2135 for (j = 0; j < remote_class->interface_count; j++) {
2136 MonoClass* iclass = remote_class->interfaces[j];
2140 /*FIXME test for interfaces with variant generic arguments*/
2141 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2142 continue; /* interface implemented by the class */
2143 if (g_slist_find (extra_interfaces, iclass))
2146 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2148 method_count = mono_class_num_methods (iclass);
2150 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2151 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2153 for (i = 0; i < ifaces->len; ++i) {
2154 MonoClass *ic = g_ptr_array_index (ifaces, i);
2155 /*FIXME test for interfaces with variant generic arguments*/
2156 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2157 continue; /* interface implemented by the class */
2158 if (g_slist_find (extra_interfaces, ic))
2160 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2161 method_count += mono_class_num_methods (ic);
2163 g_ptr_array_free (ifaces, TRUE);
2166 extra_interface_vtsize += method_count * sizeof (gpointer);
2167 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2171 mono_stats.imt_number_of_tables++;
2172 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2173 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2174 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2176 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2177 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2180 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2182 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2184 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2186 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2187 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2189 pvt->klass = mono_defaults.transparent_proxy_class;
2190 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2191 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2193 /* initialize vtable */
2194 mono_class_setup_vtable (class);
2195 for (i = 0; i < class->vtable_size; ++i) {
2198 if ((cm = class->vtable [i]))
2199 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2201 pvt->vtable [i] = NULL;
2204 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2205 /* create trampolines for abstract methods */
2206 for (k = class; k; k = k->parent) {
2208 gpointer iter = NULL;
2209 while ((m = mono_class_get_methods (k, &iter)))
2210 if (!pvt->vtable [m->slot])
2211 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2215 pvt->max_interface_id = max_interface_id;
2216 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2217 #ifdef COMPRESSED_INTERFACE_BITMAP
2218 bitmap = g_malloc0 (bsize);
2220 bitmap = mono_domain_alloc0 (domain, bsize);
2223 if (! ARCH_USE_IMT) {
2224 /* initialize interface offsets */
2225 for (i = 0; i < class->interface_offsets_count; ++i) {
2226 int interface_id = class->interfaces_packed [i]->interface_id;
2227 int slot = class->interface_offsets_packed [i];
2228 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2231 for (i = 0; i < class->interface_offsets_count; ++i) {
2232 int interface_id = class->interfaces_packed [i]->interface_id;
2233 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2236 if (extra_interfaces) {
2237 int slot = class->vtable_size;
2243 /* Create trampolines for the methods of the interfaces */
2244 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2245 interf = list_item->data;
2247 if (! ARCH_USE_IMT) {
2248 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2250 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2254 while ((cm = mono_class_get_methods (interf, &iter)))
2255 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2257 slot += mono_class_num_methods (interf);
2259 if (! ARCH_USE_IMT) {
2260 g_slist_free (extra_interfaces);
2265 /* Now that the vtable is full, we can actually fill up the IMT */
2266 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2267 if (extra_interfaces) {
2268 g_slist_free (extra_interfaces);
2272 #ifdef COMPRESSED_INTERFACE_BITMAP
2273 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2274 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2275 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2278 pvt->interface_bitmap = bitmap;
2284 * mono_class_field_is_special_static:
2286 * Returns whether @field is a thread/context static field.
2289 mono_class_field_is_special_static (MonoClassField *field)
2291 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2293 if (mono_field_is_deleted (field))
2295 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2296 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2303 * mono_class_has_special_static_fields:
2305 * Returns whenever @klass has any thread/context static fields.
2308 mono_class_has_special_static_fields (MonoClass *klass)
2310 MonoClassField *field;
2314 while ((field = mono_class_get_fields (klass, &iter))) {
2315 g_assert (field->parent == klass);
2316 if (mono_class_field_is_special_static (field))
2324 * create_remote_class_key:
2325 * Creates an array of pointers that can be used as a hash key for a remote class.
2326 * The first element of the array is the number of pointers.
2329 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2334 if (remote_class == NULL) {
2335 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2336 key = g_malloc (sizeof(gpointer) * 3);
2337 key [0] = GINT_TO_POINTER (2);
2338 key [1] = mono_defaults.marshalbyrefobject_class;
2339 key [2] = extra_class;
2341 key = g_malloc (sizeof(gpointer) * 2);
2342 key [0] = GINT_TO_POINTER (1);
2343 key [1] = extra_class;
2346 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2347 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2348 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2349 key [1] = remote_class->proxy_class;
2351 // Keep the list of interfaces sorted
2352 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2353 if (extra_class && remote_class->interfaces [i] > extra_class) {
2354 key [j++] = extra_class;
2357 key [j] = remote_class->interfaces [i];
2360 key [j] = extra_class;
2362 // Replace the old class. The interface list is the same
2363 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2364 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2365 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2366 for (i = 0; i < remote_class->interface_count; i++)
2367 key [2 + i] = remote_class->interfaces [i];
2375 * copy_remote_class_key:
2377 * Make a copy of KEY in the domain and return the copy.
2380 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2382 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2383 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2385 memcpy (mp_key, key, key_size);
2391 * mono_remote_class:
2392 * @domain: the application domain
2393 * @class_name: name of the remote class
2395 * Creates and initializes a MonoRemoteClass object for a remote type.
2397 * Can raise an exception on failure.
2400 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2403 MonoRemoteClass *rc;
2404 gpointer* key, *mp_key;
2407 key = create_remote_class_key (NULL, proxy_class);
2409 mono_domain_lock (domain);
2410 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2414 mono_domain_unlock (domain);
2418 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2419 if (!mono_error_ok (&error)) {
2421 mono_domain_unlock (domain);
2422 mono_error_raise_exception (&error);
2425 mp_key = copy_remote_class_key (domain, key);
2429 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2430 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2431 rc->interface_count = 1;
2432 rc->interfaces [0] = proxy_class;
2433 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2435 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2436 rc->interface_count = 0;
2437 rc->proxy_class = proxy_class;
2440 rc->default_vtable = NULL;
2441 rc->xdomain_vtable = NULL;
2442 rc->proxy_class_name = name;
2443 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2445 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2447 mono_domain_unlock (domain);
2452 * clone_remote_class:
2453 * Creates a copy of the remote_class, adding the provided class or interface
2455 static MonoRemoteClass*
2456 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2458 MonoRemoteClass *rc;
2459 gpointer* key, *mp_key;
2461 key = create_remote_class_key (remote_class, extra_class);
2462 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2468 mp_key = copy_remote_class_key (domain, key);
2472 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2474 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2475 rc->proxy_class = remote_class->proxy_class;
2476 rc->interface_count = remote_class->interface_count + 1;
2478 // Keep the list of interfaces sorted, since the hash key of
2479 // the remote class depends on this
2480 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2481 if (remote_class->interfaces [i] > extra_class && i == j)
2482 rc->interfaces [j++] = extra_class;
2483 rc->interfaces [j] = remote_class->interfaces [i];
2486 rc->interfaces [j] = extra_class;
2488 // Replace the old class. The interface array is the same
2489 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2490 rc->proxy_class = extra_class;
2491 rc->interface_count = remote_class->interface_count;
2492 if (rc->interface_count > 0)
2493 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2496 rc->default_vtable = NULL;
2497 rc->xdomain_vtable = NULL;
2498 rc->proxy_class_name = remote_class->proxy_class_name;
2500 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2506 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2508 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2509 mono_domain_lock (domain);
2510 if (rp->target_domain_id != -1) {
2511 if (remote_class->xdomain_vtable == NULL)
2512 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2513 mono_domain_unlock (domain);
2514 mono_loader_unlock ();
2515 return remote_class->xdomain_vtable;
2517 if (remote_class->default_vtable == NULL) {
2520 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2521 klass = mono_class_from_mono_type (type);
2522 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2523 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2525 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2528 mono_domain_unlock (domain);
2529 mono_loader_unlock ();
2530 return remote_class->default_vtable;
2534 * mono_upgrade_remote_class:
2535 * @domain: the application domain
2536 * @tproxy: the proxy whose remote class has to be upgraded.
2537 * @klass: class to which the remote class can be casted.
2539 * Updates the vtable of the remote class by adding the necessary method slots
2540 * and interface offsets so it can be safely casted to klass. klass can be a
2541 * class or an interface.
2544 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2546 MonoTransparentProxy *tproxy;
2547 MonoRemoteClass *remote_class;
2548 gboolean redo_vtable;
2550 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2551 mono_domain_lock (domain);
2553 tproxy = (MonoTransparentProxy*) proxy_object;
2554 remote_class = tproxy->remote_class;
2556 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2559 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2560 if (remote_class->interfaces [i] == klass)
2561 redo_vtable = FALSE;
2564 redo_vtable = (remote_class->proxy_class != klass);
2568 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2569 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2572 mono_domain_unlock (domain);
2573 mono_loader_unlock ();
2578 * mono_object_get_virtual_method:
2579 * @obj: object to operate on.
2582 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2583 * the instance of a callvirt of method.
2586 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2589 MonoMethod **vtable;
2591 MonoMethod *res = NULL;
2593 klass = mono_object_class (obj);
2594 if (klass == mono_defaults.transparent_proxy_class) {
2595 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2601 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2604 mono_class_setup_vtable (klass);
2605 vtable = klass->vtable;
2607 if (method->slot == -1) {
2608 /* method->slot might not be set for instances of generic methods */
2609 if (method->is_inflated) {
2610 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2611 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2614 g_assert_not_reached ();
2618 /* check method->slot is a valid index: perform isinstance? */
2619 if (method->slot != -1) {
2620 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2622 gboolean variance_used = FALSE;
2623 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2624 g_assert (iface_offset > 0);
2625 res = vtable [iface_offset + method->slot];
2628 res = vtable [method->slot];
2633 /* It may be an interface, abstract class method or generic method */
2634 if (!res || mono_method_signature (res)->generic_param_count)
2637 /* generic methods demand invoke_with_check */
2638 if (mono_method_signature (res)->generic_param_count)
2639 res = mono_marshal_get_remoting_invoke_with_check (res);
2642 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2643 res = mono_cominterop_get_invoke (res);
2646 res = mono_marshal_get_remoting_invoke (res);
2649 if (method->is_inflated) {
2650 /* Have to inflate the result */
2651 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2661 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2663 g_error ("runtime invoke called on uninitialized runtime");
2667 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2670 * mono_runtime_invoke:
2671 * @method: method to invoke
2672 * @obJ: object instance
2673 * @params: arguments to the method
2674 * @exc: exception information.
2676 * Invokes the method represented by @method on the object @obj.
2678 * obj is the 'this' pointer, it should be NULL for static
2679 * methods, a MonoObject* for object instances and a pointer to
2680 * the value type for value types.
2682 * The params array contains the arguments to the method with the
2683 * same convention: MonoObject* pointers for object instances and
2684 * pointers to the value type otherwise.
2686 * From unmanaged code you'll usually use the
2687 * mono_runtime_invoke() variant.
2689 * Note that this function doesn't handle virtual methods for
2690 * you, it will exec the exact method you pass: we still need to
2691 * expose a function to lookup the derived class implementation
2692 * of a virtual method (there are examples of this in the code,
2695 * You can pass NULL as the exc argument if you don't want to
2696 * catch exceptions, otherwise, *exc will be set to the exception
2697 * thrown, if any. if an exception is thrown, you can't use the
2698 * MonoObject* result from the function.
2700 * If the method returns a value type, it is boxed in an object
2704 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2708 if (mono_runtime_get_no_exec ())
2709 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2711 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2712 mono_profiler_method_start_invoke (method);
2714 result = default_mono_runtime_invoke (method, obj, params, exc);
2716 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2717 mono_profiler_method_end_invoke (method);
2723 * mono_method_get_unmanaged_thunk:
2724 * @method: method to generate a thunk for.
2726 * Returns an unmanaged->managed thunk that can be used to call
2727 * a managed method directly from C.
2729 * The thunk's C signature closely matches the managed signature:
2731 * C#: public bool Equals (object obj);
2732 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2733 * MonoObject*, MonoException**);
2735 * The 1st ("this") parameter must not be used with static methods:
2737 * C#: public static bool ReferenceEquals (object a, object b);
2738 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2741 * The last argument must be a non-null pointer of a MonoException* pointer.
2742 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2743 * exception has been thrown in managed code. Otherwise it will point
2744 * to the MonoException* caught by the thunk. In this case, the result of
2745 * the thunk is undefined:
2747 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2748 * MonoException *ex = NULL;
2749 * Equals func = mono_method_get_unmanaged_thunk (method);
2750 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2752 * // handle exception
2755 * The calling convention of the thunk matches the platform's default
2756 * convention. This means that under Windows, C declarations must
2757 * contain the __stdcall attribute:
2759 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2760 * MonoObject*, MonoException**);
2764 * Value type arguments and return values are treated as they were objects:
2766 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2767 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2769 * Arguments must be properly boxed upon trunk's invocation, while return
2770 * values must be unboxed.
2773 mono_method_get_unmanaged_thunk (MonoMethod *method)
2775 method = mono_marshal_get_thunk_invoke_wrapper (method);
2776 return mono_compile_method (method);
2780 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2784 /* object fields cannot be byref, so we don't need a
2786 gpointer *p = (gpointer*)dest;
2793 case MONO_TYPE_BOOLEAN:
2795 case MONO_TYPE_U1: {
2796 guint8 *p = (guint8*)dest;
2797 *p = value ? *(guint8*)value : 0;
2802 case MONO_TYPE_CHAR: {
2803 guint16 *p = (guint16*)dest;
2804 *p = value ? *(guint16*)value : 0;
2807 #if SIZEOF_VOID_P == 4
2812 case MONO_TYPE_U4: {
2813 gint32 *p = (gint32*)dest;
2814 *p = value ? *(gint32*)value : 0;
2817 #if SIZEOF_VOID_P == 8
2822 case MONO_TYPE_U8: {
2823 gint64 *p = (gint64*)dest;
2824 *p = value ? *(gint64*)value : 0;
2827 case MONO_TYPE_R4: {
2828 float *p = (float*)dest;
2829 *p = value ? *(float*)value : 0;
2832 case MONO_TYPE_R8: {
2833 double *p = (double*)dest;
2834 *p = value ? *(double*)value : 0;
2837 case MONO_TYPE_STRING:
2838 case MONO_TYPE_SZARRAY:
2839 case MONO_TYPE_CLASS:
2840 case MONO_TYPE_OBJECT:
2841 case MONO_TYPE_ARRAY:
2842 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2844 case MONO_TYPE_FNPTR:
2845 case MONO_TYPE_PTR: {
2846 gpointer *p = (gpointer*)dest;
2847 *p = deref_pointer? *(gpointer*)value: value;
2850 case MONO_TYPE_VALUETYPE:
2851 /* note that 't' and 'type->type' can be different */
2852 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2853 t = mono_class_enum_basetype (type->data.klass)->type;
2856 MonoClass *class = mono_class_from_mono_type (type);
2857 int size = mono_class_value_size (class, NULL);
2859 memset (dest, 0, size);
2861 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2864 case MONO_TYPE_GENERICINST:
2865 t = type->data.generic_class->container_class->byval_arg.type;
2868 g_warning ("got type %x", type->type);
2869 g_assert_not_reached ();
2874 * mono_field_set_value:
2875 * @obj: Instance object
2876 * @field: MonoClassField describing the field to set
2877 * @value: The value to be set
2879 * Sets the value of the field described by @field in the object instance @obj
2880 * to the value passed in @value. This method should only be used for instance
2881 * fields. For static fields, use mono_field_static_set_value.
2883 * The value must be on the native format of the field type.
2886 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2890 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2892 dest = (char*)obj + field->offset;
2893 set_value (field->type, dest, value, FALSE);
2897 * mono_field_static_set_value:
2898 * @field: MonoClassField describing the field to set
2899 * @value: The value to be set
2901 * Sets the value of the static field described by @field
2902 * to the value passed in @value.
2904 * The value must be on the native format of the field type.
2907 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2911 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2912 /* you cant set a constant! */
2913 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2915 if (field->offset == -1) {
2916 /* Special static */
2917 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2918 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2920 dest = (char*)vt->data + field->offset;
2922 set_value (field->type, dest, value, FALSE);
2925 /* Used by the debugger */
2927 mono_vtable_get_static_field_data (MonoVTable *vt)
2933 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2937 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2938 if (field->offset == -1) {
2939 /* Special static */
2940 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2941 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2943 src = (guint8*)vt->data + field->offset;
2946 src = (guint8*)obj + field->offset;
2953 * mono_field_get_value:
2954 * @obj: Object instance
2955 * @field: MonoClassField describing the field to fetch information from
2956 * @value: pointer to the location where the value will be stored
2958 * Use this routine to get the value of the field @field in the object
2961 * The pointer provided by value must be of the field type, for reference
2962 * types this is a MonoObject*, for value types its the actual pointer to
2967 * mono_field_get_value (obj, int_field, &i);
2970 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2976 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2978 src = (char*)obj + field->offset;
2979 set_value (field->type, value, src, TRUE);
2983 * mono_field_get_value_object:
2984 * @domain: domain where the object will be created (if boxing)
2985 * @field: MonoClassField describing the field to fetch information from
2986 * @obj: The object instance for the field.
2988 * Returns: a new MonoObject with the value from the given field. If the
2989 * field represents a value type, the value is boxed.
2993 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2997 MonoVTable *vtable = NULL;
2999 gboolean is_static = FALSE;
3000 gboolean is_ref = FALSE;
3001 gboolean is_literal = FALSE;
3002 gboolean is_ptr = FALSE;
3004 MonoType *type = mono_field_get_type_checked (field, &error);
3006 if (!mono_error_ok (&error))
3007 mono_error_raise_exception (&error);
3009 switch (type->type) {
3010 case MONO_TYPE_STRING:
3011 case MONO_TYPE_OBJECT:
3012 case MONO_TYPE_CLASS:
3013 case MONO_TYPE_ARRAY:
3014 case MONO_TYPE_SZARRAY:
3019 case MONO_TYPE_BOOLEAN:
3022 case MONO_TYPE_CHAR:
3031 case MONO_TYPE_VALUETYPE:
3032 is_ref = type->byref;
3034 case MONO_TYPE_GENERICINST:
3035 is_ref = !mono_type_generic_inst_is_valuetype (type);
3041 g_error ("type 0x%x not handled in "
3042 "mono_field_get_value_object", type->type);
3046 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3049 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3053 vtable = mono_class_vtable (domain, field->parent);
3055 char *name = mono_type_get_full_name (field->parent);
3056 /*FIXME extend this to use the MonoError api*/
3057 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3061 if (!vtable->initialized)
3062 mono_runtime_class_init (vtable);
3070 get_default_field_value (domain, field, &o);
3071 } else if (is_static) {
3072 mono_field_static_get_value (vtable, field, &o);
3074 mono_field_get_value (obj, field, &o);
3080 static MonoMethod *m;
3086 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3087 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3093 get_default_field_value (domain, field, v);
3094 } else if (is_static) {
3095 mono_field_static_get_value (vtable, field, v);
3097 mono_field_get_value (obj, field, v);
3100 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3102 args [1] = mono_type_get_object (mono_domain_get (), type);
3104 return mono_runtime_invoke (m, NULL, args, NULL);
3107 /* boxed value type */
3108 klass = mono_class_from_mono_type (type);
3110 if (mono_class_is_nullable (klass))
3111 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3113 o = mono_object_new (domain, klass);
3114 v = ((gchar *) o) + sizeof (MonoObject);
3117 get_default_field_value (domain, field, v);
3118 } else if (is_static) {
3119 mono_field_static_get_value (vtable, field, v);
3121 mono_field_get_value (obj, field, v);
3128 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3131 const char *p = blob;
3132 mono_metadata_decode_blob_size (p, &p);
3135 case MONO_TYPE_BOOLEAN:
3138 *(guint8 *) value = *p;
3140 case MONO_TYPE_CHAR:
3143 *(guint16*) value = read16 (p);
3147 *(guint32*) value = read32 (p);
3151 *(guint64*) value = read64 (p);
3154 readr4 (p, (float*) value);
3157 readr8 (p, (double*) value);
3159 case MONO_TYPE_STRING:
3160 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3162 case MONO_TYPE_CLASS:
3163 *(gpointer*) value = NULL;
3167 g_warning ("type 0x%02x should not be in constant table", type);
3173 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3175 MonoTypeEnum def_type;
3178 data = mono_class_get_field_default_value (field, &def_type);
3179 mono_get_constant_value_from_blob (domain, def_type, data, value);
3183 * mono_field_static_get_value:
3184 * @vt: vtable to the object
3185 * @field: MonoClassField describing the field to fetch information from
3186 * @value: where the value is returned
3188 * Use this routine to get the value of the static field @field value.
3190 * The pointer provided by value must be of the field type, for reference
3191 * types this is a MonoObject*, for value types its the actual pointer to
3196 * mono_field_static_get_value (vt, int_field, &i);
3199 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3203 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3205 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3206 get_default_field_value (vt->domain, field, value);
3210 if (field->offset == -1) {
3211 /* Special static */
3212 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3213 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3215 src = (char*)vt->data + field->offset;
3217 set_value (field->type, value, src, TRUE);
3221 * mono_property_set_value:
3222 * @prop: MonoProperty to set
3223 * @obj: instance object on which to act
3224 * @params: parameters to pass to the propery
3225 * @exc: optional exception
3227 * Invokes the property's set method with the given arguments on the
3228 * object instance obj (or NULL for static properties).
3230 * You can pass NULL as the exc argument if you don't want to
3231 * catch exceptions, otherwise, *exc will be set to the exception
3232 * thrown, if any. if an exception is thrown, you can't use the
3233 * MonoObject* result from the function.
3236 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3238 default_mono_runtime_invoke (prop->set, obj, params, exc);
3242 * mono_property_get_value:
3243 * @prop: MonoProperty to fetch
3244 * @obj: instance object on which to act
3245 * @params: parameters to pass to the propery
3246 * @exc: optional exception
3248 * Invokes the property's get method with the given arguments on the
3249 * object instance obj (or NULL for static properties).
3251 * You can pass NULL as the exc argument if you don't want to
3252 * catch exceptions, otherwise, *exc will be set to the exception
3253 * thrown, if any. if an exception is thrown, you can't use the
3254 * MonoObject* result from the function.
3256 * Returns: the value from invoking the get method on the property.
3259 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3261 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3265 * mono_nullable_init:
3266 * @buf: The nullable structure to initialize.
3267 * @value: the value to initialize from
3268 * @klass: the type for the object
3270 * Initialize the nullable structure pointed to by @buf from @value which
3271 * should be a boxed value type. The size of @buf should be able to hold
3272 * as much data as the @klass->instance_size (which is the number of bytes
3273 * that will be copies).
3275 * Since Nullables have variable structure, we can not define a C
3276 * structure for them.
3279 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3281 MonoClass *param_class = klass->cast_class;
3283 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3284 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3286 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3288 if (param_class->has_references)
3289 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3291 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3293 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3298 * mono_nullable_box:
3299 * @buf: The buffer representing the data to be boxed
3300 * @klass: the type to box it as.
3302 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3306 mono_nullable_box (guint8 *buf, MonoClass *klass)
3308 MonoClass *param_class = klass->cast_class;
3310 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3311 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3313 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3314 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3315 if (param_class->has_references)
3316 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3318 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3326 * mono_get_delegate_invoke:
3327 * @klass: The delegate class
3329 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3332 mono_get_delegate_invoke (MonoClass *klass)
3336 /* This is called at runtime, so avoid the slower search in metadata */
3337 mono_class_setup_methods (klass);
3338 if (klass->exception_type)
3340 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3345 * mono_runtime_delegate_invoke:
3346 * @delegate: pointer to a delegate object.
3347 * @params: parameters for the delegate.
3348 * @exc: Pointer to the exception result.
3350 * Invokes the delegate method @delegate with the parameters provided.
3352 * You can pass NULL as the exc argument if you don't want to
3353 * catch exceptions, otherwise, *exc will be set to the exception
3354 * thrown, if any. if an exception is thrown, you can't use the
3355 * MonoObject* result from the function.
3358 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3362 im = mono_get_delegate_invoke (delegate->vtable->klass);
3365 return mono_runtime_invoke (im, delegate, params, exc);
3368 static char **main_args = NULL;
3369 static int num_main_args;
3372 * mono_runtime_get_main_args:
3374 * Returns: a MonoArray with the arguments passed to the main program
3377 mono_runtime_get_main_args (void)
3381 MonoDomain *domain = mono_domain_get ();
3386 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3388 for (i = 0; i < num_main_args; ++i)
3389 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3395 free_main_args (void)
3399 for (i = 0; i < num_main_args; ++i)
3400 g_free (main_args [i]);
3405 * mono_runtime_run_main:
3406 * @method: the method to start the application with (usually Main)
3407 * @argc: number of arguments from the command line
3408 * @argv: array of strings from the command line
3409 * @exc: excetption results
3411 * Execute a standard Main() method (argc/argv contains the
3412 * executable name). This method also sets the command line argument value
3413 * needed by System.Environment.
3418 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3422 MonoArray *args = NULL;
3423 MonoDomain *domain = mono_domain_get ();
3424 gchar *utf8_fullpath;
3425 MonoMethodSignature *sig;
3427 g_assert (method != NULL);
3429 mono_thread_set_main (mono_thread_current ());
3431 main_args = g_new0 (char*, argc);
3432 num_main_args = argc;
3434 if (!g_path_is_absolute (argv [0])) {
3435 gchar *basename = g_path_get_basename (argv [0]);
3436 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3440 utf8_fullpath = mono_utf8_from_external (fullpath);
3441 if(utf8_fullpath == NULL) {
3442 /* Printing the arg text will cause glib to
3443 * whinge about "Invalid UTF-8", but at least
3444 * its relevant, and shows the problem text
3447 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3448 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3455 utf8_fullpath = mono_utf8_from_external (argv[0]);
3456 if(utf8_fullpath == NULL) {
3457 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3458 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3463 main_args [0] = utf8_fullpath;
3465 for (i = 1; i < argc; ++i) {
3468 utf8_arg=mono_utf8_from_external (argv[i]);
3469 if(utf8_arg==NULL) {
3470 /* Ditto the comment about Invalid UTF-8 here */
3471 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3472 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3476 main_args [i] = utf8_arg;
3481 sig = mono_method_signature (method);
3483 g_print ("Unable to load Main method.\n");
3487 if (sig->param_count) {
3488 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3489 for (i = 0; i < argc; ++i) {
3490 /* The encodings should all work, given that
3491 * we've checked all these args for the
3494 gchar *str = mono_utf8_from_external (argv [i]);
3495 MonoString *arg = mono_string_new (domain, str);
3496 mono_array_setref (args, i, arg);
3500 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3503 mono_assembly_set_main (method->klass->image->assembly);
3505 return mono_runtime_exec_main (method, args, exc);
3509 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3511 static MonoMethod *serialize_method;
3516 if (!serialize_method) {
3517 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3518 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3521 if (!serialize_method) {
3526 g_assert (!mono_object_class (obj)->marshalbyref);
3530 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3538 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3540 static MonoMethod *deserialize_method;
3545 if (!deserialize_method) {
3546 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3547 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3549 if (!deserialize_method) {
3556 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3564 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3566 static MonoMethod *get_proxy_method;
3568 MonoDomain *domain = mono_domain_get ();
3569 MonoRealProxy *real_proxy;
3570 MonoReflectionType *reflection_type;
3571 MonoTransparentProxy *transparent_proxy;
3573 if (!get_proxy_method)
3574 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3576 g_assert (obj->vtable->klass->marshalbyref);
3578 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3579 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3581 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3582 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3585 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3589 return (MonoObject*) transparent_proxy;
3593 * mono_object_xdomain_representation
3595 * @target_domain: a domain
3596 * @exc: pointer to a MonoObject*
3598 * Creates a representation of obj in the domain target_domain. This
3599 * is either a copy of obj arrived through via serialization and
3600 * deserialization or a proxy, depending on whether the object is
3601 * serializable or marshal by ref. obj must not be in target_domain.
3603 * If the object cannot be represented in target_domain, NULL is
3604 * returned and *exc is set to an appropriate exception.
3607 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3609 MonoObject *deserialized = NULL;
3610 gboolean failure = FALSE;
3614 if (mono_object_class (obj)->marshalbyref) {
3615 deserialized = make_transparent_proxy (obj, &failure, exc);
3617 MonoDomain *domain = mono_domain_get ();
3618 MonoObject *serialized;
3620 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3621 serialized = serialize_object (obj, &failure, exc);
3622 mono_domain_set_internal_with_options (target_domain, FALSE);
3624 deserialized = deserialize_object (serialized, &failure, exc);
3625 if (domain != target_domain)
3626 mono_domain_set_internal_with_options (domain, FALSE);
3629 return deserialized;
3632 /* Used in call_unhandled_exception_delegate */
3634 create_unhandled_exception_eventargs (MonoObject *exc)
3638 MonoMethod *method = NULL;
3639 MonoBoolean is_terminating = TRUE;
3642 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3645 mono_class_init (klass);
3647 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3648 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3652 args [1] = &is_terminating;
3654 obj = mono_object_new (mono_domain_get (), klass);
3655 mono_runtime_invoke (method, obj, args, NULL);
3660 /* Used in mono_unhandled_exception */
3662 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3663 MonoObject *e = NULL;
3665 MonoDomain *current_domain = mono_domain_get ();
3667 if (domain != current_domain)
3668 mono_domain_set_internal_with_options (domain, FALSE);
3670 g_assert (domain == mono_object_domain (domain->domain));
3672 if (mono_object_domain (exc) != domain) {
3673 MonoObject *serialization_exc;
3675 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3677 if (serialization_exc) {
3679 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3682 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3683 "System.Runtime.Serialization", "SerializationException",
3684 "Could not serialize unhandled exception.");
3688 g_assert (mono_object_domain (exc) == domain);
3690 pa [0] = domain->domain;
3691 pa [1] = create_unhandled_exception_eventargs (exc);
3692 mono_runtime_delegate_invoke (delegate, pa, &e);
3694 if (domain != current_domain)
3695 mono_domain_set_internal_with_options (current_domain, FALSE);
3699 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3700 if (!mono_error_ok (&error)) {
3701 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3702 mono_error_cleanup (&error);
3704 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3710 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3713 * mono_runtime_unhandled_exception_policy_set:
3714 * @policy: the new policy
3716 * This is a VM internal routine.
3718 * Sets the runtime policy for handling unhandled exceptions.
3721 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3722 runtime_unhandled_exception_policy = policy;
3726 * mono_runtime_unhandled_exception_policy_get:
3728 * This is a VM internal routine.
3730 * Gets the runtime policy for handling unhandled exceptions.
3732 MonoRuntimeUnhandledExceptionPolicy
3733 mono_runtime_unhandled_exception_policy_get (void) {
3734 return runtime_unhandled_exception_policy;
3738 * mono_unhandled_exception:
3739 * @exc: exception thrown
3741 * This is a VM internal routine.
3743 * We call this function when we detect an unhandled exception
3744 * in the default domain.
3746 * It invokes the * UnhandledException event in AppDomain or prints
3747 * a warning to the console
3750 mono_unhandled_exception (MonoObject *exc)
3752 MonoDomain *current_domain = mono_domain_get ();
3753 MonoDomain *root_domain = mono_get_root_domain ();
3754 MonoClassField *field;
3755 MonoObject *current_appdomain_delegate;
3756 MonoObject *root_appdomain_delegate;
3758 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3759 "UnhandledException");
3762 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3763 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3764 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3765 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3766 if (current_domain != root_domain) {
3767 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3769 current_appdomain_delegate = NULL;
3772 /* set exitcode only if we will abort the process */
3774 mono_environment_exitcode_set (1);
3775 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3776 mono_print_unhandled_exception (exc);
3778 if (root_appdomain_delegate) {
3779 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3781 if (current_appdomain_delegate) {
3782 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3789 * mono_runtime_exec_managed_code:
3790 * @domain: Application domain
3791 * @main_func: function to invoke from the execution thread
3792 * @main_args: parameter to the main_func
3794 * Launch a new thread to execute a function
3796 * main_func is called back from the thread with main_args as the
3797 * parameter. The callback function is expected to start Main()
3798 * eventually. This function then waits for all managed threads to
3800 * It is not necesseray anymore to execute managed code in a subthread,
3801 * so this function should not be used anymore by default: just
3802 * execute the code and then call mono_thread_manage ().
3805 mono_runtime_exec_managed_code (MonoDomain *domain,
3806 MonoMainThreadFunc main_func,
3809 mono_thread_create (domain, main_func, main_args);
3811 mono_thread_manage ();
3815 * Execute a standard Main() method (args doesn't contain the
3819 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3824 MonoCustomAttrInfo* cinfo;
3825 gboolean has_stathread_attribute;
3826 MonoInternalThread* thread = mono_thread_internal_current ();
3832 domain = mono_object_domain (args);
3833 if (!domain->entry_assembly) {
3835 MonoAssembly *assembly;
3837 assembly = method->klass->image->assembly;
3838 domain->entry_assembly = assembly;
3839 /* Domains created from another domain already have application_base and configuration_file set */
3840 if (domain->setup->application_base == NULL) {
3841 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3844 if (domain->setup->configuration_file == NULL) {
3845 str = g_strconcat (assembly->image->name, ".config", NULL);
3846 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3848 mono_set_private_bin_path_from_config (domain);
3852 cinfo = mono_custom_attrs_from_method (method);
3854 static MonoClass *stathread_attribute = NULL;
3855 if (!stathread_attribute)
3856 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3857 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3859 mono_custom_attrs_free (cinfo);
3861 has_stathread_attribute = FALSE;
3863 if (has_stathread_attribute) {
3864 thread->apartment_state = ThreadApartmentState_STA;
3866 thread->apartment_state = ThreadApartmentState_MTA;
3868 mono_thread_init_apartment_state ();
3870 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3872 /* FIXME: check signature of method */
3873 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3875 res = mono_runtime_invoke (method, NULL, pa, exc);
3877 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3881 mono_environment_exitcode_set (rval);
3883 mono_runtime_invoke (method, NULL, pa, exc);
3887 /* If the return type of Main is void, only
3888 * set the exitcode if an exception was thrown
3889 * (we don't want to blow away an
3890 * explicitly-set exit code)
3893 mono_environment_exitcode_set (rval);
3897 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3903 * mono_install_runtime_invoke:
3904 * @func: Function to install
3906 * This is a VM internal routine
3909 mono_install_runtime_invoke (MonoInvokeFunc func)
3911 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3916 * mono_runtime_invoke_array:
3917 * @method: method to invoke
3918 * @obJ: object instance
3919 * @params: arguments to the method
3920 * @exc: exception information.
3922 * Invokes the method represented by @method on the object @obj.
3924 * obj is the 'this' pointer, it should be NULL for static
3925 * methods, a MonoObject* for object instances and a pointer to
3926 * the value type for value types.
3928 * The params array contains the arguments to the method with the
3929 * same convention: MonoObject* pointers for object instances and
3930 * pointers to the value type otherwise. The _invoke_array
3931 * variant takes a C# object[] as the params argument (MonoArray
3932 * *params): in this case the value types are boxed inside the
3933 * respective reference representation.
3935 * From unmanaged code you'll usually use the
3936 * mono_runtime_invoke() variant.
3938 * Note that this function doesn't handle virtual methods for
3939 * you, it will exec the exact method you pass: we still need to
3940 * expose a function to lookup the derived class implementation
3941 * of a virtual method (there are examples of this in the code,
3944 * You can pass NULL as the exc argument if you don't want to
3945 * catch exceptions, otherwise, *exc will be set to the exception
3946 * thrown, if any. if an exception is thrown, you can't use the
3947 * MonoObject* result from the function.
3949 * If the method returns a value type, it is boxed in an object
3953 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3956 MonoMethodSignature *sig = mono_method_signature (method);
3957 gpointer *pa = NULL;
3960 gboolean has_byref_nullables = FALSE;
3962 if (NULL != params) {
3963 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3964 for (i = 0; i < mono_array_length (params); i++) {
3965 MonoType *t = sig->params [i];
3971 case MONO_TYPE_BOOLEAN:
3974 case MONO_TYPE_CHAR:
3983 case MONO_TYPE_VALUETYPE:
3984 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3985 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3986 pa [i] = mono_array_get (params, MonoObject*, i);
3988 has_byref_nullables = TRUE;
3990 /* MS seems to create the objects if a null is passed in */
3991 if (!mono_array_get (params, MonoObject*, i))
3992 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3996 * We can't pass the unboxed vtype byref to the callee, since
3997 * that would mean the callee would be able to modify boxed
3998 * primitive types. So we (and MS) make a copy of the boxed
3999 * object, pass that to the callee, and replace the original
4000 * boxed object in the arg array with the copy.
4002 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4003 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4004 mono_array_setref (params, i, copy);
4007 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4010 case MONO_TYPE_STRING:
4011 case MONO_TYPE_OBJECT:
4012 case MONO_TYPE_CLASS:
4013 case MONO_TYPE_ARRAY:
4014 case MONO_TYPE_SZARRAY:
4016 pa [i] = mono_array_addr (params, MonoObject*, i);
4017 // FIXME: I need to check this code path
4019 pa [i] = mono_array_get (params, MonoObject*, i);
4021 case MONO_TYPE_GENERICINST:
4023 t = &t->data.generic_class->container_class->this_arg;
4025 t = &t->data.generic_class->container_class->byval_arg;
4027 case MONO_TYPE_PTR: {
4030 /* The argument should be an IntPtr */
4031 arg = mono_array_get (params, MonoObject*, i);
4035 g_assert (arg->vtable->klass == mono_defaults.int_class);
4036 pa [i] = ((MonoIntPtr*)arg)->m_value;
4041 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4046 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4049 if (mono_class_is_nullable (method->klass)) {
4050 /* Need to create a boxed vtype instead */
4056 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4060 obj = mono_object_new (mono_domain_get (), method->klass);
4061 g_assert (obj); /*maybe we should raise a TLE instead?*/
4062 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4063 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4065 if (method->klass->valuetype)
4066 o = mono_object_unbox (obj);
4069 } else if (method->klass->valuetype) {
4070 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4073 mono_runtime_invoke (method, o, pa, exc);
4076 if (mono_class_is_nullable (method->klass)) {
4077 MonoObject *nullable;
4079 /* Convert the unboxed vtype into a Nullable structure */
4080 nullable = mono_object_new (mono_domain_get (), method->klass);
4082 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4083 obj = mono_object_unbox (nullable);
4086 /* obj must be already unboxed if needed */
4087 res = mono_runtime_invoke (method, obj, pa, exc);
4089 if (sig->ret->type == MONO_TYPE_PTR) {
4090 MonoClass *pointer_class;
4091 static MonoMethod *box_method;
4093 MonoObject *box_exc;
4096 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4097 * convert it to a Pointer object.
4099 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4101 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4103 g_assert (res->vtable->klass == mono_defaults.int_class);
4104 box_args [0] = ((MonoIntPtr*)res)->m_value;
4105 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4106 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4107 g_assert (!box_exc);
4110 if (has_byref_nullables) {
4112 * The runtime invoke wrapper already converted byref nullables back,
4113 * and stored them in pa, we just need to copy them back to the
4116 for (i = 0; i < mono_array_length (params); i++) {
4117 MonoType *t = sig->params [i];
4119 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4120 mono_array_setref (params, i, pa [i]);
4129 arith_overflow (void)
4131 mono_raise_exception (mono_get_exception_overflow ());
4135 * mono_object_allocate:
4136 * @size: number of bytes to allocate
4138 * This is a very simplistic routine until we have our GC-aware
4141 * Returns: an allocated object of size @size, or NULL on failure.
4143 static inline void *
4144 mono_object_allocate (size_t size, MonoVTable *vtable)
4147 mono_stats.new_object_count++;
4148 ALLOC_OBJECT (o, vtable, size);
4154 * mono_object_allocate_ptrfree:
4155 * @size: number of bytes to allocate
4157 * Note that the memory allocated is not zeroed.
4158 * Returns: an allocated object of size @size, or NULL on failure.
4160 static inline void *
4161 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4164 mono_stats.new_object_count++;
4165 ALLOC_PTRFREE (o, vtable, size);
4169 static inline void *
4170 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4173 ALLOC_TYPED (o, size, vtable);
4174 mono_stats.new_object_count++;
4181 * @klass: the class of the object that we want to create
4183 * Returns: a newly created object whose definition is
4184 * looked up using @klass. This will not invoke any constructors,
4185 * so the consumer of this routine has to invoke any constructors on
4186 * its own to initialize the object.
4188 * It returns NULL on failure.
4191 mono_object_new (MonoDomain *domain, MonoClass *klass)
4195 MONO_ARCH_SAVE_REGS;
4196 vtable = mono_class_vtable (domain, klass);
4199 return mono_object_new_specific (vtable);
4203 * mono_object_new_specific:
4204 * @vtable: the vtable of the object that we want to create
4206 * Returns: A newly created object with class and domain specified
4210 mono_object_new_specific (MonoVTable *vtable)
4214 MONO_ARCH_SAVE_REGS;
4216 /* check for is_com_object for COM Interop */
4217 if (vtable->remote || vtable->klass->is_com_object)
4220 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4223 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4226 mono_class_init (klass);
4228 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4230 vtable->domain->create_proxy_for_type_method = im;
4233 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4235 o = mono_runtime_invoke (im, NULL, pa, NULL);
4236 if (o != NULL) return o;
4239 return mono_object_new_alloc_specific (vtable);
4243 mono_object_new_alloc_specific (MonoVTable *vtable)
4247 if (!vtable->klass->has_references) {
4248 o = mono_object_new_ptrfree (vtable);
4249 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4250 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4252 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4253 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4255 if (G_UNLIKELY (vtable->klass->has_finalize))
4256 mono_object_register_finalizer (o);
4258 if (G_UNLIKELY (profile_allocs))
4259 mono_profiler_allocation (o, vtable->klass);
4264 mono_object_new_fast (MonoVTable *vtable)
4267 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4272 mono_object_new_ptrfree (MonoVTable *vtable)
4275 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4276 #if NEED_TO_ZERO_PTRFREE
4277 /* an inline memset is much faster for the common vcase of small objects
4278 * note we assume the allocated size is a multiple of sizeof (void*).
4280 if (vtable->klass->instance_size < 128) {
4282 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4283 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4289 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4296 mono_object_new_ptrfree_box (MonoVTable *vtable)
4299 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4300 /* the object will be boxed right away, no need to memzero it */
4305 * mono_class_get_allocation_ftn:
4307 * @for_box: the object will be used for boxing
4308 * @pass_size_in_words:
4310 * Return the allocation function appropriate for the given class.
4314 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4316 *pass_size_in_words = FALSE;
4318 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4319 profile_allocs = FALSE;
4321 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4322 return mono_object_new_specific;
4324 if (!vtable->klass->has_references) {
4325 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4327 return mono_object_new_ptrfree_box;
4328 return mono_object_new_ptrfree;
4331 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4333 return mono_object_new_fast;
4336 * FIXME: This is actually slower than mono_object_new_fast, because
4337 * of the overhead of parameter passing.
4340 *pass_size_in_words = TRUE;
4341 #ifdef GC_REDIRECT_TO_LOCAL
4342 return GC_local_gcj_fast_malloc;
4344 return GC_gcj_fast_malloc;
4349 return mono_object_new_specific;
4353 * mono_object_new_from_token:
4354 * @image: Context where the type_token is hosted
4355 * @token: a token of the type that we want to create
4357 * Returns: A newly created object whose definition is
4358 * looked up using @token in the @image image
4361 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4365 class = mono_class_get (image, token);
4367 return mono_object_new (domain, class);
4372 * mono_object_clone:
4373 * @obj: the object to clone
4375 * Returns: A newly created object who is a shallow copy of @obj
4378 mono_object_clone (MonoObject *obj)
4381 int size = obj->vtable->klass->instance_size;
4383 o = mono_object_allocate (size, obj->vtable);
4385 if (obj->vtable->klass->has_references) {
4386 mono_gc_wbarrier_object_copy (o, obj);
4388 int size = obj->vtable->klass->instance_size;
4389 /* do not copy the sync state */
4390 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4392 if (G_UNLIKELY (profile_allocs))
4393 mono_profiler_allocation (o, obj->vtable->klass);
4395 if (obj->vtable->klass->has_finalize)
4396 mono_object_register_finalizer (o);
4401 * mono_array_full_copy:
4402 * @src: source array to copy
4403 * @dest: destination array
4405 * Copies the content of one array to another with exactly the same type and size.
4408 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4411 MonoClass *klass = src->obj.vtable->klass;
4413 MONO_ARCH_SAVE_REGS;
4415 g_assert (klass == dest->obj.vtable->klass);
4417 size = mono_array_length (src);
4418 g_assert (size == mono_array_length (dest));
4419 size *= mono_array_element_size (klass);
4421 if (klass->element_class->valuetype) {
4422 if (klass->element_class->has_references)
4423 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4425 memcpy (&dest->vector, &src->vector, size);
4427 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4430 memcpy (&dest->vector, &src->vector, size);
4435 * mono_array_clone_in_domain:
4436 * @domain: the domain in which the array will be cloned into
4437 * @array: the array to clone
4439 * This routine returns a copy of the array that is hosted on the
4440 * specified MonoDomain.
4443 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4448 MonoClass *klass = array->obj.vtable->klass;
4450 MONO_ARCH_SAVE_REGS;
4452 if (array->bounds == NULL) {
4453 size = mono_array_length (array);
4454 o = mono_array_new_full (domain, klass, &size, NULL);
4456 size *= mono_array_element_size (klass);
4458 if (klass->element_class->valuetype) {
4459 if (klass->element_class->has_references)
4460 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4462 memcpy (&o->vector, &array->vector, size);
4464 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4467 memcpy (&o->vector, &array->vector, size);
4472 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4473 size = mono_array_element_size (klass);
4474 for (i = 0; i < klass->rank; ++i) {
4475 sizes [i] = array->bounds [i].length;
4476 size *= array->bounds [i].length;
4477 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4479 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4481 if (klass->element_class->valuetype) {
4482 if (klass->element_class->has_references)
4483 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4485 memcpy (&o->vector, &array->vector, size);
4487 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4490 memcpy (&o->vector, &array->vector, size);
4498 * @array: the array to clone
4500 * Returns: A newly created array who is a shallow copy of @array
4503 mono_array_clone (MonoArray *array)
4505 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4508 /* helper macros to check for overflow when calculating the size of arrays */
4509 #ifdef MONO_BIG_ARRAYS
4510 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4511 #define MYGUINT_MAX MYGUINT64_MAX
4512 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4513 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4514 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4515 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4516 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4518 #define MYGUINT32_MAX 4294967295U
4519 #define MYGUINT_MAX MYGUINT32_MAX
4520 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4521 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4522 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4523 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4524 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4528 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4532 byte_len = mono_array_element_size (class);
4533 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4536 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4538 byte_len += sizeof (MonoArray);
4546 * mono_array_new_full:
4547 * @domain: domain where the object is created
4548 * @array_class: array class
4549 * @lengths: lengths for each dimension in the array
4550 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4552 * This routine creates a new array objects with the given dimensions,
4553 * lower bounds and type.
4556 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4558 uintptr_t byte_len, len, bounds_size;
4561 MonoArrayBounds *bounds;
4565 if (!array_class->inited)
4566 mono_class_init (array_class);
4570 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4571 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4573 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4577 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4579 for (i = 0; i < array_class->rank; ++i) {
4580 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4582 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4583 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4588 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4589 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4593 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4594 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4595 byte_len = (byte_len + 3) & ~3;
4596 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4597 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4598 byte_len += bounds_size;
4601 * Following three lines almost taken from mono_object_new ():
4602 * they need to be kept in sync.
4604 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4605 #ifndef HAVE_SGEN_GC
4606 if (!array_class->has_references) {
4607 o = mono_object_allocate_ptrfree (byte_len, vtable);
4608 #if NEED_TO_ZERO_PTRFREE
4609 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4611 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4612 o = mono_object_allocate_spec (byte_len, vtable);
4614 o = mono_object_allocate (byte_len, vtable);
4617 array = (MonoArray*)o;
4618 array->max_length = len;
4621 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4622 array->bounds = bounds;
4626 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4628 o = mono_gc_alloc_vector (vtable, byte_len, len);
4629 array = (MonoArray*)o;
4630 mono_stats.new_object_count++;
4632 bounds = array->bounds;
4636 for (i = 0; i < array_class->rank; ++i) {
4637 bounds [i].length = lengths [i];
4639 bounds [i].lower_bound = lower_bounds [i];
4643 if (G_UNLIKELY (profile_allocs))
4644 mono_profiler_allocation (o, array_class);
4651 * @domain: domain where the object is created
4652 * @eclass: element class
4653 * @n: number of array elements
4655 * This routine creates a new szarray with @n elements of type @eclass.
4658 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4662 MONO_ARCH_SAVE_REGS;
4664 ac = mono_array_class_get (eclass, 1);
4667 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4671 * mono_array_new_specific:
4672 * @vtable: a vtable in the appropriate domain for an initialized class
4673 * @n: number of array elements
4675 * This routine is a fast alternative to mono_array_new() for code which
4676 * can be sure about the domain it operates in.
4679 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4685 MONO_ARCH_SAVE_REGS;
4687 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4692 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4693 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4696 #ifndef HAVE_SGEN_GC
4697 if (!vtable->klass->has_references) {
4698 o = mono_object_allocate_ptrfree (byte_len, vtable);
4699 #if NEED_TO_ZERO_PTRFREE
4700 ((MonoArray*)o)->bounds = NULL;
4701 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4703 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4704 o = mono_object_allocate_spec (byte_len, vtable);
4706 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4707 o = mono_object_allocate (byte_len, vtable);
4710 ao = (MonoArray *)o;
4713 o = mono_gc_alloc_vector (vtable, byte_len, n);
4715 mono_stats.new_object_count++;
4718 if (G_UNLIKELY (profile_allocs))
4719 mono_profiler_allocation (o, vtable->klass);
4725 * mono_string_new_utf16:
4726 * @text: a pointer to an utf16 string
4727 * @len: the length of the string
4729 * Returns: A newly created string object which contains @text.
4732 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4736 s = mono_string_new_size (domain, len);
4737 g_assert (s != NULL);
4739 memcpy (mono_string_chars (s), text, len * 2);
4745 * mono_string_new_size:
4746 * @text: a pointer to an utf16 string
4747 * @len: the length of the string
4749 * Returns: A newly created string object of @len
4752 mono_string_new_size (MonoDomain *domain, gint32 len)
4756 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4758 /* overflow ? can't fit it, can't allocate it! */
4760 mono_gc_out_of_memory (-1);
4762 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4765 #ifndef HAVE_SGEN_GC
4766 s = mono_object_allocate_ptrfree (size, vtable);
4770 s = mono_gc_alloc_string (vtable, size, len);
4772 #if NEED_TO_ZERO_PTRFREE
4775 if (G_UNLIKELY (profile_allocs))
4776 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4782 * mono_string_new_len:
4783 * @text: a pointer to an utf8 string
4784 * @length: number of bytes in @text to consider
4786 * Returns: A newly created string object which contains @text.
4789 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4791 GError *error = NULL;
4792 MonoString *o = NULL;
4794 glong items_written;
4796 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4799 o = mono_string_new_utf16 (domain, ut, items_written);
4801 g_error_free (error);
4810 * @text: a pointer to an utf8 string
4812 * Returns: A newly created string object which contains @text.
4815 mono_string_new (MonoDomain *domain, const char *text)
4817 GError *error = NULL;
4818 MonoString *o = NULL;
4820 glong items_written;
4825 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4828 o = mono_string_new_utf16 (domain, ut, items_written);
4830 g_error_free (error);
4833 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4838 MonoString *o = NULL;
4840 if (!g_utf8_validate (text, -1, &end))
4843 len = g_utf8_strlen (text, -1);
4844 o = mono_string_new_size (domain, len);
4845 str = mono_string_chars (o);
4847 while (text < end) {
4848 *str++ = g_utf8_get_char (text);
4849 text = g_utf8_next_char (text);
4856 * mono_string_new_wrapper:
4857 * @text: pointer to utf8 characters.
4859 * Helper function to create a string object from @text in the current domain.
4862 mono_string_new_wrapper (const char *text)
4864 MonoDomain *domain = mono_domain_get ();
4866 MONO_ARCH_SAVE_REGS;
4869 return mono_string_new (domain, text);
4876 * @class: the class of the value
4877 * @value: a pointer to the unboxed data
4879 * Returns: A newly created object which contains @value.
4882 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4888 g_assert (class->valuetype);
4889 if (mono_class_is_nullable (class))
4890 return mono_nullable_box (value, class);
4892 vtable = mono_class_vtable (domain, class);
4895 size = mono_class_instance_size (class);
4896 res = mono_object_new_alloc_specific (vtable);
4897 if (G_UNLIKELY (profile_allocs))
4898 mono_profiler_allocation (res, class);
4900 size = size - sizeof (MonoObject);
4903 g_assert (size == mono_class_value_size (class, NULL));
4904 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4906 #if NO_UNALIGNED_ACCESS
4907 memcpy ((char *)res + sizeof (MonoObject), value, size);
4911 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4914 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4917 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4920 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4923 memcpy ((char *)res + sizeof (MonoObject), value, size);
4927 if (class->has_finalize)
4928 mono_object_register_finalizer (res);
4934 * @dest: destination pointer
4935 * @src: source pointer
4936 * @klass: a valuetype class
4938 * Copy a valuetype from @src to @dest. This function must be used
4939 * when @klass contains references fields.
4942 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4944 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4948 * mono_value_copy_array:
4949 * @dest: destination array
4950 * @dest_idx: index in the @dest array
4951 * @src: source pointer
4952 * @count: number of items
4954 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4955 * This function must be used when @klass contains references fields.
4956 * Overlap is handled.
4959 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4961 int size = mono_array_element_size (dest->obj.vtable->klass);
4962 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4963 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4964 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4968 * mono_object_get_domain:
4969 * @obj: object to query
4971 * Returns: the MonoDomain where the object is hosted
4974 mono_object_get_domain (MonoObject *obj)
4976 return mono_object_domain (obj);
4980 * mono_object_get_class:
4981 * @obj: object to query
4983 * Returns: the MonOClass of the object.
4986 mono_object_get_class (MonoObject *obj)
4988 return mono_object_class (obj);
4991 * mono_object_get_size:
4992 * @o: object to query
4994 * Returns: the size, in bytes, of @o
4997 mono_object_get_size (MonoObject* o)
4999 MonoClass* klass = mono_object_class (o);
5000 if (klass == mono_defaults.string_class) {
5001 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5002 } else if (o->vtable->rank) {
5003 MonoArray *array = (MonoArray*)o;
5004 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5005 if (array->bounds) {
5008 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5012 return mono_class_instance_size (klass);
5017 * mono_object_unbox:
5018 * @obj: object to unbox
5020 * Returns: a pointer to the start of the valuetype boxed in this
5023 * This method will assert if the object passed is not a valuetype.
5026 mono_object_unbox (MonoObject *obj)
5028 /* add assert for valuetypes? */
5029 g_assert (obj->vtable->klass->valuetype);
5030 return ((char*)obj) + sizeof (MonoObject);
5034 * mono_object_isinst:
5036 * @klass: a pointer to a class
5038 * Returns: @obj if @obj is derived from @klass
5041 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5044 mono_class_init (klass);
5046 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5047 return mono_object_isinst_mbyref (obj, klass);
5052 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5056 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5065 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5066 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5070 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5071 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5074 MonoClass *oklass = vt->klass;
5075 if ((oklass == mono_defaults.transparent_proxy_class))
5076 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5078 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5082 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5084 MonoDomain *domain = mono_domain_get ();
5086 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5087 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5088 MonoMethod *im = NULL;
5091 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5092 im = mono_object_get_virtual_method (rp, im);
5095 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5098 res = mono_runtime_invoke (im, rp, pa, NULL);
5100 if (*(MonoBoolean *) mono_object_unbox(res)) {
5101 /* Update the vtable of the remote type, so it can safely cast to this new type */
5102 mono_upgrade_remote_class (domain, obj, klass);
5111 * mono_object_castclass_mbyref:
5113 * @klass: a pointer to a class
5115 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5118 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5120 if (!obj) return NULL;
5121 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5123 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5125 "InvalidCastException"));
5130 MonoDomain *orig_domain;
5136 str_lookup (MonoDomain *domain, gpointer user_data)
5138 LDStrInfo *info = user_data;
5139 if (info->res || domain == info->orig_domain)
5141 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5147 mono_string_get_pinned (MonoString *str)
5151 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5152 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5153 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5154 news->length = mono_string_length (str);
5159 #define mono_string_get_pinned(str) (str)
5163 mono_string_is_interned_lookup (MonoString *str, int insert)
5165 MonoGHashTable *ldstr_table;
5169 domain = ((MonoObject *)str)->vtable->domain;
5170 ldstr_table = domain->ldstr_table;
5172 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5177 str = mono_string_get_pinned (str);
5178 mono_g_hash_table_insert (ldstr_table, str, str);
5182 LDStrInfo ldstr_info;
5183 ldstr_info.orig_domain = domain;
5184 ldstr_info.ins = str;
5185 ldstr_info.res = NULL;
5187 mono_domain_foreach (str_lookup, &ldstr_info);
5188 if (ldstr_info.res) {
5190 * the string was already interned in some other domain:
5191 * intern it in the current one as well.
5193 mono_g_hash_table_insert (ldstr_table, str, str);
5203 * mono_string_is_interned:
5204 * @o: String to probe
5206 * Returns whether the string has been interned.
5209 mono_string_is_interned (MonoString *o)
5211 return mono_string_is_interned_lookup (o, FALSE);
5215 * mono_string_intern:
5216 * @o: String to intern
5218 * Interns the string passed.
5219 * Returns: The interned string.
5222 mono_string_intern (MonoString *str)
5224 return mono_string_is_interned_lookup (str, TRUE);
5229 * @domain: the domain where the string will be used.
5230 * @image: a metadata context
5231 * @idx: index into the user string table.
5233 * Implementation for the ldstr opcode.
5234 * Returns: a loaded string from the @image/@idx combination.
5237 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5239 MONO_ARCH_SAVE_REGS;
5241 if (image->dynamic) {
5242 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5245 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5246 return NULL; /*FIXME we should probably be raising an exception here*/
5247 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5252 * mono_ldstr_metadata_sig
5253 * @domain: the domain for the string
5254 * @sig: the signature of a metadata string
5256 * Returns: a MonoString for a string stored in the metadata
5259 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5261 const char *str = sig;
5262 MonoString *o, *interned;
5265 len2 = mono_metadata_decode_blob_size (str, &str);
5268 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5269 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5272 guint16 *p2 = (guint16*)mono_string_chars (o);
5273 for (i = 0; i < len2; ++i) {
5274 *p2 = GUINT16_FROM_LE (*p2);
5280 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5282 /* o will get garbage collected */
5286 o = mono_string_get_pinned (o);
5287 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5294 * mono_string_to_utf8:
5295 * @s: a System.String
5297 * Returns the UTF8 representation for @s.
5298 * The resulting buffer needs to be freed with mono_free().
5300 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5303 mono_string_to_utf8 (MonoString *s)
5306 char *result = mono_string_to_utf8_checked (s, &error);
5308 if (!mono_error_ok (&error))
5309 mono_error_raise_exception (&error);
5314 * mono_string_to_utf8_checked:
5315 * @s: a System.String
5316 * @error: a MonoError.
5318 * Converts a MonoString to its UTF8 representation. May fail; check
5319 * @error to determine whether the conversion was successful.
5320 * The resulting buffer should be freed with mono_free().
5323 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5327 GError *gerror = NULL;
5329 mono_error_init (error);
5335 return g_strdup ("");
5337 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5339 mono_error_set_argument (error, "string", "%s", gerror->message);
5340 g_error_free (gerror);
5343 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5344 if (s->length > written) {
5345 /* allocate the total length and copy the part of the string that has been converted */
5346 char *as2 = g_malloc0 (s->length);
5347 memcpy (as2, as, written);
5356 * mono_string_to_utf16:
5359 * Return an null-terminated array of the utf-16 chars
5360 * contained in @s. The result must be freed with g_free().
5361 * This is a temporary helper until our string implementation
5362 * is reworked to always include the null terminating char.
5365 mono_string_to_utf16 (MonoString *s)
5372 as = g_malloc ((s->length * 2) + 2);
5373 as [(s->length * 2)] = '\0';
5374 as [(s->length * 2) + 1] = '\0';
5377 return (gunichar2 *)(as);
5380 memcpy (as, mono_string_chars(s), s->length * 2);
5381 return (gunichar2 *)(as);
5385 * mono_string_from_utf16:
5386 * @data: the UTF16 string (LPWSTR) to convert
5388 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5390 * Returns: a MonoString.
5393 mono_string_from_utf16 (gunichar2 *data)
5395 MonoDomain *domain = mono_domain_get ();
5401 while (data [len]) len++;
5403 return mono_string_new_utf16 (domain, data, len);
5408 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5414 r = mono_string_to_utf8_checked (s, error);
5415 if (!mono_error_ok (error))
5421 len = strlen (r) + 1;
5423 mp_s = mono_mempool_alloc (mp, len);
5425 mp_s = mono_image_alloc (image, len);
5427 memcpy (mp_s, r, len);
5435 * mono_string_to_utf8_image:
5436 * @s: a System.String
5438 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5441 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5443 return mono_string_to_utf8_internal (NULL, image, s, error);
5447 * mono_string_to_utf8_mp:
5448 * @s: a System.String
5450 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5453 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5455 return mono_string_to_utf8_internal (mp, NULL, s, error);
5459 default_ex_handler (MonoException *ex)
5461 MonoObject *o = (MonoObject*)ex;
5462 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5466 static MonoExceptionFunc ex_handler = default_ex_handler;
5469 * mono_install_handler:
5470 * @func: exception handler
5472 * This is an internal JIT routine used to install the handler for exceptions
5476 mono_install_handler (MonoExceptionFunc func)
5478 ex_handler = func? func: default_ex_handler;
5482 * mono_raise_exception:
5483 * @ex: exception object
5485 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5488 mono_raise_exception (MonoException *ex)
5491 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5492 * that will cause gcc to omit the function epilog, causing problems when
5493 * the JIT tries to walk the stack, since the return address on the stack
5494 * will point into the next function in the executable, not this one.
5497 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5498 MonoInternalThread *thread = mono_thread_internal_current ();
5499 g_assert (ex->object.vtable->domain == mono_domain_get ());
5500 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5507 * mono_wait_handle_new:
5508 * @domain: Domain where the object will be created
5509 * @handle: Handle for the wait handle
5511 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5514 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5516 MonoWaitHandle *res;
5517 gpointer params [1];
5518 static MonoMethod *handle_set;
5520 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5522 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5524 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5526 params [0] = &handle;
5527 mono_runtime_invoke (handle_set, res, params, NULL);
5533 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5535 static MonoClassField *f_os_handle;
5536 static MonoClassField *f_safe_handle;
5538 if (!f_os_handle && !f_safe_handle) {
5539 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5540 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5545 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5549 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5556 mono_runtime_capture_context (MonoDomain *domain)
5558 RuntimeInvokeFunction runtime_invoke;
5560 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5561 MonoMethod *method = mono_get_context_capture_method ();
5562 MonoMethod *wrapper;
5565 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5566 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5567 domain->capture_context_method = mono_compile_method (method);
5570 runtime_invoke = domain->capture_context_runtime_invoke;
5572 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5575 * mono_async_result_new:
5576 * @domain:domain where the object will be created.
5577 * @handle: wait handle.
5578 * @state: state to pass to AsyncResult
5579 * @data: C closure data.
5581 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5582 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5586 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5588 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5589 MonoObject *context = mono_runtime_capture_context (domain);
5590 /* we must capture the execution context from the original thread */
5592 MONO_OBJECT_SETREF (res, execution_context, context);
5593 /* note: result may be null if the flow is suppressed */
5597 MONO_OBJECT_SETREF (res, object_data, object_data);
5598 MONO_OBJECT_SETREF (res, async_state, state);
5600 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5602 res->sync_completed = FALSE;
5603 res->completed = FALSE;
5609 mono_message_init (MonoDomain *domain,
5610 MonoMethodMessage *this,
5611 MonoReflectionMethod *method,
5612 MonoArray *out_args)
5614 static MonoClass *object_array_klass;
5615 static MonoClass *byte_array_klass;
5616 static MonoClass *string_array_klass;
5617 MonoMethodSignature *sig = mono_method_signature (method->method);
5623 if (!object_array_klass) {
5626 klass = mono_array_class_get (mono_defaults.object_class, 1);
5629 mono_memory_barrier ();
5630 object_array_klass = klass;
5632 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5635 mono_memory_barrier ();
5636 byte_array_klass = klass;
5638 klass = mono_array_class_get (mono_defaults.string_class, 1);
5641 mono_memory_barrier ();
5642 string_array_klass = klass;
5645 MONO_OBJECT_SETREF (this, method, method);
5647 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5648 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5649 this->async_result = NULL;
5650 this->call_type = CallType_Sync;
5652 names = g_new (char *, sig->param_count);
5653 mono_method_get_param_names (method->method, (const char **) names);
5654 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5656 for (i = 0; i < sig->param_count; i++) {
5657 name = mono_string_new (domain, names [i]);
5658 mono_array_setref (this->names, i, name);
5662 for (i = 0, j = 0; i < sig->param_count; i++) {
5663 if (sig->params [i]->byref) {
5665 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5666 mono_array_setref (this->args, i, arg);
5670 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5674 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5677 mono_array_set (this->arg_types, guint8, i, arg_type);
5682 * mono_remoting_invoke:
5683 * @real_proxy: pointer to a RealProxy object
5684 * @msg: The MonoMethodMessage to execute
5685 * @exc: used to store exceptions
5686 * @out_args: used to store output arguments
5688 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5689 * IMessage interface and it is not trivial to extract results from there. So
5690 * we call an helper method PrivateInvoke instead of calling
5691 * RealProxy::Invoke() directly.
5693 * Returns: the result object.
5696 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5697 MonoObject **exc, MonoArray **out_args)
5699 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5702 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5705 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5707 real_proxy->vtable->domain->private_invoke_method = im;
5710 pa [0] = real_proxy;
5715 return mono_runtime_invoke (im, NULL, pa, exc);
5719 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5720 MonoObject **exc, MonoArray **out_args)
5722 static MonoClass *object_array_klass;
5725 MonoMethodSignature *sig;
5727 int i, j, outarg_count = 0;
5729 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5731 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5732 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5733 target = tp->rp->unwrapped_server;
5735 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5739 domain = mono_domain_get ();
5740 method = msg->method->method;
5741 sig = mono_method_signature (method);
5743 for (i = 0; i < sig->param_count; i++) {
5744 if (sig->params [i]->byref)
5748 if (!object_array_klass) {
5751 klass = mono_array_class_get (mono_defaults.object_class, 1);
5754 mono_memory_barrier ();
5755 object_array_klass = klass;
5758 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5759 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5762 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5764 for (i = 0, j = 0; i < sig->param_count; i++) {
5765 if (sig->params [i]->byref) {
5767 arg = mono_array_get (msg->args, gpointer, i);
5768 mono_array_setref (*out_args, j, arg);
5777 * mono_object_to_string:
5779 * @exc: Any exception thrown by ToString (). May be NULL.
5781 * Returns: the result of calling ToString () on an object.
5784 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5786 static MonoMethod *to_string = NULL;
5792 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5794 method = mono_object_get_virtual_method (obj, to_string);
5796 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5800 * mono_print_unhandled_exception:
5801 * @exc: The exception
5803 * Prints the unhandled exception.
5806 mono_print_unhandled_exception (MonoObject *exc)
5809 char *message = (char*)"";
5810 gboolean free_message = FALSE;
5813 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5814 message = g_strdup ("OutOfMemoryException");
5816 str = mono_object_to_string (exc, NULL);
5818 message = mono_string_to_utf8_checked (str, &error);
5819 if (!mono_error_ok (&error)) {
5820 mono_error_cleanup (&error);
5821 message = (char *) "";
5823 free_message = TRUE;
5829 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5830 * exc->vtable->klass->name, message);
5832 g_printerr ("\nUnhandled Exception: %s\n", message);
5839 * mono_delegate_ctor:
5840 * @this: pointer to an uninitialized delegate object
5841 * @target: target object
5842 * @addr: pointer to native code
5845 * Initialize a delegate and sets a specific method, not the one
5846 * associated with addr. This is useful when sharing generic code.
5847 * In that case addr will most probably not be associated with the
5848 * correct instantiation of the method.
5851 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5853 MonoDelegate *delegate = (MonoDelegate *)this;
5860 delegate->method = method;
5862 class = this->vtable->klass;
5863 mono_stats.delegate_creations++;
5865 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5867 method = mono_marshal_get_remoting_invoke (method);
5868 delegate->method_ptr = mono_compile_method (method);
5869 MONO_OBJECT_SETREF (delegate, target, target);
5870 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5871 method = mono_marshal_get_unbox_wrapper (method);
5872 delegate->method_ptr = mono_compile_method (method);
5873 MONO_OBJECT_SETREF (delegate, target, target);
5875 delegate->method_ptr = addr;
5876 MONO_OBJECT_SETREF (delegate, target, target);
5879 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5883 * mono_delegate_ctor:
5884 * @this: pointer to an uninitialized delegate object
5885 * @target: target object
5886 * @addr: pointer to native code
5888 * This is used to initialize a delegate.
5891 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5893 MonoDomain *domain = mono_domain_get ();
5895 MonoMethod *method = NULL;
5899 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5900 method = ji->method;
5901 g_assert (!method->klass->generic_container);
5904 mono_delegate_ctor_with_method (this, target, addr, method);
5908 * mono_method_call_message_new:
5909 * @method: method to encapsulate
5910 * @params: parameters to the method
5911 * @invoke: optional, delegate invoke.
5912 * @cb: async callback delegate.
5913 * @state: state passed to the async callback.
5915 * Translates arguments pointers into a MonoMethodMessage.
5918 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5919 MonoDelegate **cb, MonoObject **state)
5921 MonoDomain *domain = mono_domain_get ();
5922 MonoMethodSignature *sig = mono_method_signature (method);
5923 MonoMethodMessage *msg;
5926 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5929 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5930 count = sig->param_count - 2;
5932 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5933 count = sig->param_count;
5936 for (i = 0; i < count; i++) {
5941 if (sig->params [i]->byref)
5942 vpos = *((gpointer *)params [i]);
5946 type = sig->params [i]->type;
5947 class = mono_class_from_mono_type (sig->params [i]);
5949 if (class->valuetype)
5950 arg = mono_value_box (domain, class, vpos);
5952 arg = *((MonoObject **)vpos);
5954 mono_array_setref (msg->args, i, arg);
5957 if (cb != NULL && state != NULL) {
5958 *cb = *((MonoDelegate **)params [i]);
5960 *state = *((MonoObject **)params [i]);
5967 * mono_method_return_message_restore:
5969 * Restore results from message based processing back to arguments pointers
5972 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5974 MonoMethodSignature *sig = mono_method_signature (method);
5975 int i, j, type, size, out_len;
5977 if (out_args == NULL)
5979 out_len = mono_array_length (out_args);
5983 for (i = 0, j = 0; i < sig->param_count; i++) {
5984 MonoType *pt = sig->params [i];
5989 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5991 arg = mono_array_get (out_args, gpointer, j);
5994 g_assert (type != MONO_TYPE_VOID);
5996 if (MONO_TYPE_IS_REFERENCE (pt)) {
5997 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6000 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6001 size = mono_class_value_size (class, NULL);
6002 if (class->has_references)
6003 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6005 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6007 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6008 memset (*((gpointer *)params [i]), 0, size);
6018 * mono_load_remote_field:
6019 * @this: pointer to an object
6020 * @klass: klass of the object containing @field
6021 * @field: the field to load
6022 * @res: a storage to store the result
6024 * This method is called by the runtime on attempts to load fields of
6025 * transparent proxy objects. @this points to such TP, @klass is the class of
6026 * the object containing @field. @res is a storage location which can be
6027 * used to store the result.
6029 * Returns: an address pointing to the value of field.
6032 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6034 static MonoMethod *getter = NULL;
6035 MonoDomain *domain = mono_domain_get ();
6036 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6037 MonoClass *field_class;
6038 MonoMethodMessage *msg;
6039 MonoArray *out_args;
6043 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6044 g_assert (res != NULL);
6046 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6047 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6052 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6056 field_class = mono_class_from_mono_type (field->type);
6058 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6059 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6060 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6062 full_name = mono_type_get_full_name (klass);
6063 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6064 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6067 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6069 if (exc) mono_raise_exception ((MonoException *)exc);
6071 if (mono_array_length (out_args) == 0)
6074 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6076 if (field_class->valuetype) {
6077 return ((char *)*res) + sizeof (MonoObject);
6083 * mono_load_remote_field_new:
6088 * Missing documentation.
6091 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6093 static MonoMethod *getter = NULL;
6094 MonoDomain *domain = mono_domain_get ();
6095 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6096 MonoClass *field_class;
6097 MonoMethodMessage *msg;
6098 MonoArray *out_args;
6099 MonoObject *exc, *res;
6102 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6104 field_class = mono_class_from_mono_type (field->type);
6106 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6108 if (field_class->valuetype) {
6109 res = mono_object_new (domain, field_class);
6110 val = ((gchar *) res) + sizeof (MonoObject);
6114 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6119 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6123 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6124 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6126 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6128 full_name = mono_type_get_full_name (klass);
6129 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6130 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6133 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6135 if (exc) mono_raise_exception ((MonoException *)exc);
6137 if (mono_array_length (out_args) == 0)
6140 res = mono_array_get (out_args, MonoObject *, 0);
6146 * mono_store_remote_field:
6147 * @this: pointer to an object
6148 * @klass: klass of the object containing @field
6149 * @field: the field to load
6150 * @val: the value/object to store
6152 * This method is called by the runtime on attempts to store fields of
6153 * transparent proxy objects. @this points to such TP, @klass is the class of
6154 * the object containing @field. @val is the new value to store in @field.
6157 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6159 static MonoMethod *setter = NULL;
6160 MonoDomain *domain = mono_domain_get ();
6161 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6162 MonoClass *field_class;
6163 MonoMethodMessage *msg;
6164 MonoArray *out_args;
6169 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6171 field_class = mono_class_from_mono_type (field->type);
6173 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6174 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6175 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6180 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6184 if (field_class->valuetype)
6185 arg = mono_value_box (domain, field_class, val);
6187 arg = *((MonoObject **)val);
6190 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6191 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6193 full_name = mono_type_get_full_name (klass);
6194 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6195 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6196 mono_array_setref (msg->args, 2, arg);
6199 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6201 if (exc) mono_raise_exception ((MonoException *)exc);
6205 * mono_store_remote_field_new:
6211 * Missing documentation
6214 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6216 static MonoMethod *setter = NULL;
6217 MonoDomain *domain = mono_domain_get ();
6218 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6219 MonoClass *field_class;
6220 MonoMethodMessage *msg;
6221 MonoArray *out_args;
6225 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6227 field_class = mono_class_from_mono_type (field->type);
6229 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6230 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6231 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6236 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6240 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6241 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6243 full_name = mono_type_get_full_name (klass);
6244 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6245 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6246 mono_array_setref (msg->args, 2, arg);
6249 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6251 if (exc) mono_raise_exception ((MonoException *)exc);
6255 * mono_create_ftnptr:
6257 * Given a function address, create a function descriptor for it.
6258 * This is only needed on some platforms.
6261 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6263 return callbacks.create_ftnptr (domain, addr);
6267 * mono_get_addr_from_ftnptr:
6269 * Given a pointer to a function descriptor, return the function address.
6270 * This is only needed on some platforms.
6273 mono_get_addr_from_ftnptr (gpointer descr)
6275 return callbacks.get_addr_from_ftnptr (descr);
6279 * mono_string_chars:
6282 * Returns a pointer to the UCS16 characters stored in the MonoString
6285 mono_string_chars (MonoString *s)
6291 * mono_string_length:
6294 * Returns the lenght in characters of the string
6297 mono_string_length (MonoString *s)
6303 * mono_array_length:
6304 * @array: a MonoArray*
6306 * Returns the total number of elements in the array. This works for
6307 * both vectors and multidimensional arrays.
6310 mono_array_length (MonoArray *array)
6312 return array->max_length;
6316 * mono_array_addr_with_size:
6317 * @array: a MonoArray*
6318 * @size: size of the array elements
6319 * @idx: index into the array
6321 * Returns the address of the @idx element in the array.
6324 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6326 return ((char*)(array)->vector) + size * idx;