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 #ifndef __native_client__
1713 /* We don't re-use any thunks as there is a lot of overhead */
1714 /* to deleting and re-using code in Native Client. */
1715 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1716 invalidate_generic_virtual_thunk (domain, old_thunk);
1720 mono_domain_unlock (domain);
1723 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1726 * mono_class_vtable:
1727 * @domain: the application domain
1728 * @class: the class to initialize
1730 * VTables are domain specific because we create domain specific code, and
1731 * they contain the domain specific static class data.
1732 * On failure, NULL is returned, and class->exception_type is set.
1735 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1737 return mono_class_vtable_full (domain, class, FALSE);
1741 * mono_class_vtable_full:
1742 * @domain: the application domain
1743 * @class: the class to initialize
1744 * @raise_on_error if an exception should be raised on failure or not
1746 * VTables are domain specific because we create domain specific code, and
1747 * they contain the domain specific static class data.
1750 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1752 MonoClassRuntimeInfo *runtime_info;
1756 if (class->exception_type) {
1758 mono_raise_exception (mono_class_get_exception_for_failure (class));
1762 /* this check can be inlined in jitted code, too */
1763 runtime_info = class->runtime_info;
1764 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1765 return runtime_info->domain_vtables [domain->domain_id];
1766 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1770 * mono_class_try_get_vtable:
1771 * @domain: the application domain
1772 * @class: the class to initialize
1774 * This function tries to get the associated vtable from @class if
1775 * it was already created.
1778 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1780 MonoClassRuntimeInfo *runtime_info;
1784 runtime_info = class->runtime_info;
1785 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1786 return runtime_info->domain_vtables [domain->domain_id];
1791 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1794 MonoClassRuntimeInfo *runtime_info, *old_info;
1795 MonoClassField *field;
1798 int imt_table_bytes = 0;
1799 guint32 vtable_size, class_size;
1802 gpointer *interface_offsets;
1804 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1805 mono_domain_lock (domain);
1806 runtime_info = class->runtime_info;
1807 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1808 mono_domain_unlock (domain);
1809 mono_loader_unlock ();
1810 return runtime_info->domain_vtables [domain->domain_id];
1812 if (!class->inited || class->exception_type) {
1813 if (!mono_class_init (class) || class->exception_type) {
1814 mono_domain_unlock (domain);
1815 mono_loader_unlock ();
1817 mono_raise_exception (mono_class_get_exception_for_failure (class));
1822 /* Array types require that their element type be valid*/
1823 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1824 MonoClass *element_class = class->element_class;
1825 if (!element_class->inited)
1826 mono_class_init (element_class);
1828 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1829 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1830 mono_class_setup_vtable (element_class);
1832 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1833 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1834 if (class->exception_type == MONO_EXCEPTION_NONE)
1835 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1836 mono_domain_unlock (domain);
1837 mono_loader_unlock ();
1839 mono_raise_exception (mono_class_get_exception_for_failure (class));
1845 * For some classes, mono_class_init () already computed class->vtable_size, and
1846 * that is all that is needed because of the vtable trampolines.
1848 if (!class->vtable_size)
1849 mono_class_setup_vtable (class);
1851 if (class->generic_class && !class->vtable)
1852 mono_class_check_vtable_constraints (class, NULL);
1854 if (class->exception_type) {
1855 mono_domain_unlock (domain);
1856 mono_loader_unlock ();
1858 mono_raise_exception (mono_class_get_exception_for_failure (class));
1863 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1864 if (class->interface_offsets_count) {
1865 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1866 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1867 mono_stats.imt_number_of_tables++;
1868 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1871 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1872 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1875 mono_stats.used_class_count++;
1876 mono_stats.class_vtable_size += vtable_size;
1877 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1880 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1882 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1884 vt->rank = class->rank;
1885 vt->domain = domain;
1887 mono_class_compute_gc_descriptor (class);
1889 * We can't use typed allocation in the non-root domains, since the
1890 * collector needs the GC descriptor stored in the vtable even after
1891 * the mempool containing the vtable is destroyed when the domain is
1892 * unloaded. An alternative might be to allocate vtables in the GC
1893 * heap, but this does not seem to work (it leads to crashes inside
1894 * libgc). If that approach is tried, two gc descriptors need to be
1895 * allocated for each class: one for the root domain, and one for all
1896 * other domains. The second descriptor should contain a bit for the
1897 * vtable field in MonoObject, since we can no longer assume the
1898 * vtable is reachable by other roots after the appdomain is unloaded.
1900 #ifdef HAVE_BOEHM_GC
1901 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1902 vt->gc_descr = GC_NO_DESCRIPTOR;
1905 vt->gc_descr = class->gc_descr;
1907 if ((class_size = mono_class_data_size (class))) {
1908 if (class->has_static_refs) {
1909 gpointer statics_gc_descr;
1911 gsize default_bitmap [4] = {0};
1914 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1915 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1916 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1917 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1918 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1919 if (bitmap != default_bitmap)
1922 vt->data = mono_domain_alloc0 (domain, class_size);
1924 mono_stats.class_static_data_size += class_size;
1929 while ((field = mono_class_get_fields (class, &iter))) {
1930 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1932 if (mono_field_is_deleted (field))
1934 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1935 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1936 if (special_static != SPECIAL_STATIC_NONE) {
1937 guint32 size, offset;
1939 gsize default_bitmap [4] = {0};
1943 if (mono_type_is_reference (field->type)) {
1944 default_bitmap [0] = 1;
1946 bitmap = default_bitmap;
1947 } else if (mono_type_is_struct (field->type)) {
1948 fclass = mono_class_from_mono_type (field->type);
1949 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1951 default_bitmap [0] = 0;
1953 bitmap = default_bitmap;
1955 size = mono_type_size (field->type, &align);
1956 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1957 if (!domain->special_static_fields)
1958 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1959 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1960 if (bitmap != default_bitmap)
1963 * This marks the field as special static to speed up the
1964 * checks in mono_field_static_get/set_value ().
1970 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1971 MonoClass *fklass = mono_class_from_mono_type (field->type);
1972 const char *data = mono_field_get_data (field);
1974 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1975 t = (char*)vt->data + field->offset;
1976 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1979 if (fklass->valuetype) {
1980 memcpy (t, data, mono_class_value_size (fklass, NULL));
1982 /* it's a pointer type: add check */
1983 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1990 vt->max_interface_id = class->max_interface_id;
1991 vt->interface_bitmap = class->interface_bitmap;
1993 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1994 // class->name, class->interface_offsets_count);
1996 if (! ARCH_USE_IMT) {
1997 /* initialize interface offsets */
1998 for (i = 0; i < class->interface_offsets_count; ++i) {
1999 int interface_id = class->interfaces_packed [i]->interface_id;
2000 int slot = class->interface_offsets_packed [i];
2001 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2005 /* class_vtable_array keeps an array of created vtables
2007 g_ptr_array_add (domain->class_vtable_array, vt);
2008 /* class->runtime_info is protected by the loader lock, both when
2009 * it it enlarged and when it is stored info.
2012 old_info = class->runtime_info;
2013 if (old_info && old_info->max_domain >= domain->domain_id) {
2014 /* someone already created a large enough runtime info */
2015 mono_memory_barrier ();
2016 old_info->domain_vtables [domain->domain_id] = vt;
2018 int new_size = domain->domain_id;
2020 new_size = MAX (new_size, old_info->max_domain);
2022 /* make the new size a power of two */
2024 while (new_size > i)
2027 /* this is a bounded memory retention issue: may want to
2028 * handle it differently when we'll have a rcu-like system.
2030 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2031 runtime_info->max_domain = new_size - 1;
2032 /* copy the stuff from the older info */
2034 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2036 runtime_info->domain_vtables [domain->domain_id] = vt;
2038 mono_memory_barrier ();
2039 class->runtime_info = runtime_info;
2042 /* Initialize vtable */
2043 if (callbacks.get_vtable_trampoline) {
2044 // This also covers the AOT case
2045 for (i = 0; i < class->vtable_size; ++i) {
2046 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2049 mono_class_setup_vtable (class);
2051 for (i = 0; i < class->vtable_size; ++i) {
2054 if ((cm = class->vtable [i]))
2055 vt->vtable [i] = arch_create_jit_trampoline (cm);
2059 if (ARCH_USE_IMT && imt_table_bytes) {
2060 /* Now that the vtable is full, we can actually fill up the IMT */
2061 if (callbacks.get_imt_trampoline) {
2062 /* lazy construction of the IMT entries enabled */
2063 for (i = 0; i < MONO_IMT_SIZE; ++i)
2064 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2066 build_imt (class, vt, domain, interface_offsets, NULL);
2070 mono_domain_unlock (domain);
2071 mono_loader_unlock ();
2073 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2074 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2075 mono_raise_exception (mono_class_get_exception_for_failure (class));
2077 /* make sure the parent is initialized */
2078 /*FIXME shouldn't this fail the current type?*/
2080 mono_class_vtable_full (domain, class->parent, raise_on_error);
2082 /*FIXME check for OOM*/
2083 vt->type = mono_type_get_object (domain, &class->byval_arg);
2084 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2085 /* This is unregistered in
2086 unregister_vtable_reflection_type() in
2088 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2089 if (class->contextbound)
2098 * mono_class_proxy_vtable:
2099 * @domain: the application domain
2100 * @remove_class: the remote class
2102 * Creates a vtable for transparent proxies. It is basically
2103 * a copy of the real vtable of the class wrapped in @remote_class,
2104 * but all function pointers invoke the remoting functions, and
2105 * vtable->klass points to the transparent proxy class, and not to @class.
2108 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2111 MonoVTable *vt, *pvt;
2112 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2114 GSList *extra_interfaces = NULL;
2115 MonoClass *class = remote_class->proxy_class;
2116 gpointer *interface_offsets;
2120 #ifdef COMPRESSED_INTERFACE_BITMAP
2124 vt = mono_class_vtable (domain, class);
2125 g_assert (vt); /*FIXME property handle failure*/
2126 max_interface_id = vt->max_interface_id;
2128 /* Calculate vtable space for extra interfaces */
2129 for (j = 0; j < remote_class->interface_count; j++) {
2130 MonoClass* iclass = remote_class->interfaces[j];
2134 /*FIXME test for interfaces with variant generic arguments*/
2135 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2136 continue; /* interface implemented by the class */
2137 if (g_slist_find (extra_interfaces, iclass))
2140 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2142 method_count = mono_class_num_methods (iclass);
2144 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2145 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2147 for (i = 0; i < ifaces->len; ++i) {
2148 MonoClass *ic = g_ptr_array_index (ifaces, i);
2149 /*FIXME test for interfaces with variant generic arguments*/
2150 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2151 continue; /* interface implemented by the class */
2152 if (g_slist_find (extra_interfaces, ic))
2154 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2155 method_count += mono_class_num_methods (ic);
2157 g_ptr_array_free (ifaces, TRUE);
2160 extra_interface_vtsize += method_count * sizeof (gpointer);
2161 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2165 mono_stats.imt_number_of_tables++;
2166 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2167 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2168 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2170 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2171 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2174 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2176 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2178 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2180 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2181 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2183 pvt->klass = mono_defaults.transparent_proxy_class;
2184 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2185 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2187 /* initialize vtable */
2188 mono_class_setup_vtable (class);
2189 for (i = 0; i < class->vtable_size; ++i) {
2192 if ((cm = class->vtable [i]))
2193 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2195 pvt->vtable [i] = NULL;
2198 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2199 /* create trampolines for abstract methods */
2200 for (k = class; k; k = k->parent) {
2202 gpointer iter = NULL;
2203 while ((m = mono_class_get_methods (k, &iter)))
2204 if (!pvt->vtable [m->slot])
2205 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2209 pvt->max_interface_id = max_interface_id;
2210 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2211 #ifdef COMPRESSED_INTERFACE_BITMAP
2212 bitmap = g_malloc0 (bsize);
2214 bitmap = mono_domain_alloc0 (domain, bsize);
2217 if (! ARCH_USE_IMT) {
2218 /* initialize interface offsets */
2219 for (i = 0; i < class->interface_offsets_count; ++i) {
2220 int interface_id = class->interfaces_packed [i]->interface_id;
2221 int slot = class->interface_offsets_packed [i];
2222 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2225 for (i = 0; i < class->interface_offsets_count; ++i) {
2226 int interface_id = class->interfaces_packed [i]->interface_id;
2227 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2230 if (extra_interfaces) {
2231 int slot = class->vtable_size;
2237 /* Create trampolines for the methods of the interfaces */
2238 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2239 interf = list_item->data;
2241 if (! ARCH_USE_IMT) {
2242 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2244 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2248 while ((cm = mono_class_get_methods (interf, &iter)))
2249 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2251 slot += mono_class_num_methods (interf);
2253 if (! ARCH_USE_IMT) {
2254 g_slist_free (extra_interfaces);
2259 /* Now that the vtable is full, we can actually fill up the IMT */
2260 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2261 if (extra_interfaces) {
2262 g_slist_free (extra_interfaces);
2266 #ifdef COMPRESSED_INTERFACE_BITMAP
2267 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2268 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2269 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2272 pvt->interface_bitmap = bitmap;
2278 * mono_class_field_is_special_static:
2280 * Returns whether @field is a thread/context static field.
2283 mono_class_field_is_special_static (MonoClassField *field)
2285 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2287 if (mono_field_is_deleted (field))
2289 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2290 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2297 * mono_class_has_special_static_fields:
2299 * Returns whenever @klass has any thread/context static fields.
2302 mono_class_has_special_static_fields (MonoClass *klass)
2304 MonoClassField *field;
2308 while ((field = mono_class_get_fields (klass, &iter))) {
2309 g_assert (field->parent == klass);
2310 if (mono_class_field_is_special_static (field))
2318 * create_remote_class_key:
2319 * Creates an array of pointers that can be used as a hash key for a remote class.
2320 * The first element of the array is the number of pointers.
2323 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2328 if (remote_class == NULL) {
2329 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2330 key = g_malloc (sizeof(gpointer) * 3);
2331 key [0] = GINT_TO_POINTER (2);
2332 key [1] = mono_defaults.marshalbyrefobject_class;
2333 key [2] = extra_class;
2335 key = g_malloc (sizeof(gpointer) * 2);
2336 key [0] = GINT_TO_POINTER (1);
2337 key [1] = extra_class;
2340 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2341 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2342 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2343 key [1] = remote_class->proxy_class;
2345 // Keep the list of interfaces sorted
2346 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2347 if (extra_class && remote_class->interfaces [i] > extra_class) {
2348 key [j++] = extra_class;
2351 key [j] = remote_class->interfaces [i];
2354 key [j] = extra_class;
2356 // Replace the old class. The interface list is the same
2357 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2358 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2359 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2360 for (i = 0; i < remote_class->interface_count; i++)
2361 key [2 + i] = remote_class->interfaces [i];
2369 * copy_remote_class_key:
2371 * Make a copy of KEY in the domain and return the copy.
2374 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2376 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2377 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2379 memcpy (mp_key, key, key_size);
2385 * mono_remote_class:
2386 * @domain: the application domain
2387 * @class_name: name of the remote class
2389 * Creates and initializes a MonoRemoteClass object for a remote type.
2391 * Can raise an exception on failure.
2394 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2397 MonoRemoteClass *rc;
2398 gpointer* key, *mp_key;
2401 key = create_remote_class_key (NULL, proxy_class);
2403 mono_domain_lock (domain);
2404 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2408 mono_domain_unlock (domain);
2412 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2413 if (!mono_error_ok (&error)) {
2415 mono_domain_unlock (domain);
2416 mono_error_raise_exception (&error);
2419 mp_key = copy_remote_class_key (domain, key);
2423 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2424 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2425 rc->interface_count = 1;
2426 rc->interfaces [0] = proxy_class;
2427 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2429 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2430 rc->interface_count = 0;
2431 rc->proxy_class = proxy_class;
2434 rc->default_vtable = NULL;
2435 rc->xdomain_vtable = NULL;
2436 rc->proxy_class_name = name;
2437 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2439 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2441 mono_domain_unlock (domain);
2446 * clone_remote_class:
2447 * Creates a copy of the remote_class, adding the provided class or interface
2449 static MonoRemoteClass*
2450 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2452 MonoRemoteClass *rc;
2453 gpointer* key, *mp_key;
2455 key = create_remote_class_key (remote_class, extra_class);
2456 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2462 mp_key = copy_remote_class_key (domain, key);
2466 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2468 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2469 rc->proxy_class = remote_class->proxy_class;
2470 rc->interface_count = remote_class->interface_count + 1;
2472 // Keep the list of interfaces sorted, since the hash key of
2473 // the remote class depends on this
2474 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2475 if (remote_class->interfaces [i] > extra_class && i == j)
2476 rc->interfaces [j++] = extra_class;
2477 rc->interfaces [j] = remote_class->interfaces [i];
2480 rc->interfaces [j] = extra_class;
2482 // Replace the old class. The interface array is the same
2483 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2484 rc->proxy_class = extra_class;
2485 rc->interface_count = remote_class->interface_count;
2486 if (rc->interface_count > 0)
2487 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2490 rc->default_vtable = NULL;
2491 rc->xdomain_vtable = NULL;
2492 rc->proxy_class_name = remote_class->proxy_class_name;
2494 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2500 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2502 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2503 mono_domain_lock (domain);
2504 if (rp->target_domain_id != -1) {
2505 if (remote_class->xdomain_vtable == NULL)
2506 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2507 mono_domain_unlock (domain);
2508 mono_loader_unlock ();
2509 return remote_class->xdomain_vtable;
2511 if (remote_class->default_vtable == NULL) {
2514 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2515 klass = mono_class_from_mono_type (type);
2516 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2517 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2519 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2522 mono_domain_unlock (domain);
2523 mono_loader_unlock ();
2524 return remote_class->default_vtable;
2528 * mono_upgrade_remote_class:
2529 * @domain: the application domain
2530 * @tproxy: the proxy whose remote class has to be upgraded.
2531 * @klass: class to which the remote class can be casted.
2533 * Updates the vtable of the remote class by adding the necessary method slots
2534 * and interface offsets so it can be safely casted to klass. klass can be a
2535 * class or an interface.
2538 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2540 MonoTransparentProxy *tproxy;
2541 MonoRemoteClass *remote_class;
2542 gboolean redo_vtable;
2544 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2545 mono_domain_lock (domain);
2547 tproxy = (MonoTransparentProxy*) proxy_object;
2548 remote_class = tproxy->remote_class;
2550 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2553 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2554 if (remote_class->interfaces [i] == klass)
2555 redo_vtable = FALSE;
2558 redo_vtable = (remote_class->proxy_class != klass);
2562 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2563 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2566 mono_domain_unlock (domain);
2567 mono_loader_unlock ();
2572 * mono_object_get_virtual_method:
2573 * @obj: object to operate on.
2576 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2577 * the instance of a callvirt of method.
2580 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2583 MonoMethod **vtable;
2585 MonoMethod *res = NULL;
2587 klass = mono_object_class (obj);
2588 if (klass == mono_defaults.transparent_proxy_class) {
2589 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2595 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2598 mono_class_setup_vtable (klass);
2599 vtable = klass->vtable;
2601 if (method->slot == -1) {
2602 /* method->slot might not be set for instances of generic methods */
2603 if (method->is_inflated) {
2604 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2605 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2608 g_assert_not_reached ();
2612 /* check method->slot is a valid index: perform isinstance? */
2613 if (method->slot != -1) {
2614 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2616 gboolean variance_used = FALSE;
2617 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2618 g_assert (iface_offset > 0);
2619 res = vtable [iface_offset + method->slot];
2622 res = vtable [method->slot];
2627 /* It may be an interface, abstract class method or generic method */
2628 if (!res || mono_method_signature (res)->generic_param_count)
2631 /* generic methods demand invoke_with_check */
2632 if (mono_method_signature (res)->generic_param_count)
2633 res = mono_marshal_get_remoting_invoke_with_check (res);
2636 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2637 res = mono_cominterop_get_invoke (res);
2640 res = mono_marshal_get_remoting_invoke (res);
2643 if (method->is_inflated) {
2644 /* Have to inflate the result */
2645 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2655 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2657 g_error ("runtime invoke called on uninitialized runtime");
2661 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2664 * mono_runtime_invoke:
2665 * @method: method to invoke
2666 * @obJ: object instance
2667 * @params: arguments to the method
2668 * @exc: exception information.
2670 * Invokes the method represented by @method on the object @obj.
2672 * obj is the 'this' pointer, it should be NULL for static
2673 * methods, a MonoObject* for object instances and a pointer to
2674 * the value type for value types.
2676 * The params array contains the arguments to the method with the
2677 * same convention: MonoObject* pointers for object instances and
2678 * pointers to the value type otherwise.
2680 * From unmanaged code you'll usually use the
2681 * mono_runtime_invoke() variant.
2683 * Note that this function doesn't handle virtual methods for
2684 * you, it will exec the exact method you pass: we still need to
2685 * expose a function to lookup the derived class implementation
2686 * of a virtual method (there are examples of this in the code,
2689 * You can pass NULL as the exc argument if you don't want to
2690 * catch exceptions, otherwise, *exc will be set to the exception
2691 * thrown, if any. if an exception is thrown, you can't use the
2692 * MonoObject* result from the function.
2694 * If the method returns a value type, it is boxed in an object
2698 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2702 if (mono_runtime_get_no_exec ())
2703 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2705 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2706 mono_profiler_method_start_invoke (method);
2708 result = default_mono_runtime_invoke (method, obj, params, exc);
2710 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2711 mono_profiler_method_end_invoke (method);
2717 * mono_method_get_unmanaged_thunk:
2718 * @method: method to generate a thunk for.
2720 * Returns an unmanaged->managed thunk that can be used to call
2721 * a managed method directly from C.
2723 * The thunk's C signature closely matches the managed signature:
2725 * C#: public bool Equals (object obj);
2726 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2727 * MonoObject*, MonoException**);
2729 * The 1st ("this") parameter must not be used with static methods:
2731 * C#: public static bool ReferenceEquals (object a, object b);
2732 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2735 * The last argument must be a non-null pointer of a MonoException* pointer.
2736 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2737 * exception has been thrown in managed code. Otherwise it will point
2738 * to the MonoException* caught by the thunk. In this case, the result of
2739 * the thunk is undefined:
2741 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2742 * MonoException *ex = NULL;
2743 * Equals func = mono_method_get_unmanaged_thunk (method);
2744 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2746 * // handle exception
2749 * The calling convention of the thunk matches the platform's default
2750 * convention. This means that under Windows, C declarations must
2751 * contain the __stdcall attribute:
2753 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2754 * MonoObject*, MonoException**);
2758 * Value type arguments and return values are treated as they were objects:
2760 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2761 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2763 * Arguments must be properly boxed upon trunk's invocation, while return
2764 * values must be unboxed.
2767 mono_method_get_unmanaged_thunk (MonoMethod *method)
2769 method = mono_marshal_get_thunk_invoke_wrapper (method);
2770 return mono_compile_method (method);
2774 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2778 /* object fields cannot be byref, so we don't need a
2780 gpointer *p = (gpointer*)dest;
2787 case MONO_TYPE_BOOLEAN:
2789 case MONO_TYPE_U1: {
2790 guint8 *p = (guint8*)dest;
2791 *p = value ? *(guint8*)value : 0;
2796 case MONO_TYPE_CHAR: {
2797 guint16 *p = (guint16*)dest;
2798 *p = value ? *(guint16*)value : 0;
2801 #if SIZEOF_VOID_P == 4
2806 case MONO_TYPE_U4: {
2807 gint32 *p = (gint32*)dest;
2808 *p = value ? *(gint32*)value : 0;
2811 #if SIZEOF_VOID_P == 8
2816 case MONO_TYPE_U8: {
2817 gint64 *p = (gint64*)dest;
2818 *p = value ? *(gint64*)value : 0;
2821 case MONO_TYPE_R4: {
2822 float *p = (float*)dest;
2823 *p = value ? *(float*)value : 0;
2826 case MONO_TYPE_R8: {
2827 double *p = (double*)dest;
2828 *p = value ? *(double*)value : 0;
2831 case MONO_TYPE_STRING:
2832 case MONO_TYPE_SZARRAY:
2833 case MONO_TYPE_CLASS:
2834 case MONO_TYPE_OBJECT:
2835 case MONO_TYPE_ARRAY:
2836 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2838 case MONO_TYPE_FNPTR:
2839 case MONO_TYPE_PTR: {
2840 gpointer *p = (gpointer*)dest;
2841 *p = deref_pointer? *(gpointer*)value: value;
2844 case MONO_TYPE_VALUETYPE:
2845 /* note that 't' and 'type->type' can be different */
2846 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2847 t = mono_class_enum_basetype (type->data.klass)->type;
2850 MonoClass *class = mono_class_from_mono_type (type);
2851 int size = mono_class_value_size (class, NULL);
2853 memset (dest, 0, size);
2855 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2858 case MONO_TYPE_GENERICINST:
2859 t = type->data.generic_class->container_class->byval_arg.type;
2862 g_warning ("got type %x", type->type);
2863 g_assert_not_reached ();
2868 * mono_field_set_value:
2869 * @obj: Instance object
2870 * @field: MonoClassField describing the field to set
2871 * @value: The value to be set
2873 * Sets the value of the field described by @field in the object instance @obj
2874 * to the value passed in @value. This method should only be used for instance
2875 * fields. For static fields, use mono_field_static_set_value.
2877 * The value must be on the native format of the field type.
2880 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2884 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2886 dest = (char*)obj + field->offset;
2887 set_value (field->type, dest, value, FALSE);
2891 * mono_field_static_set_value:
2892 * @field: MonoClassField describing the field to set
2893 * @value: The value to be set
2895 * Sets the value of the static field described by @field
2896 * to the value passed in @value.
2898 * The value must be on the native format of the field type.
2901 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2905 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2906 /* you cant set a constant! */
2907 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2909 if (field->offset == -1) {
2910 /* Special static */
2911 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2912 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2914 dest = (char*)vt->data + field->offset;
2916 set_value (field->type, dest, value, FALSE);
2919 /* Used by the debugger */
2921 mono_vtable_get_static_field_data (MonoVTable *vt)
2927 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2931 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2932 if (field->offset == -1) {
2933 /* Special static */
2934 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2935 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2937 src = (guint8*)vt->data + field->offset;
2940 src = (guint8*)obj + field->offset;
2947 * mono_field_get_value:
2948 * @obj: Object instance
2949 * @field: MonoClassField describing the field to fetch information from
2950 * @value: pointer to the location where the value will be stored
2952 * Use this routine to get the value of the field @field in the object
2955 * The pointer provided by value must be of the field type, for reference
2956 * types this is a MonoObject*, for value types its the actual pointer to
2961 * mono_field_get_value (obj, int_field, &i);
2964 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2970 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2972 src = (char*)obj + field->offset;
2973 set_value (field->type, value, src, TRUE);
2977 * mono_field_get_value_object:
2978 * @domain: domain where the object will be created (if boxing)
2979 * @field: MonoClassField describing the field to fetch information from
2980 * @obj: The object instance for the field.
2982 * Returns: a new MonoObject with the value from the given field. If the
2983 * field represents a value type, the value is boxed.
2987 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2991 MonoVTable *vtable = NULL;
2993 gboolean is_static = FALSE;
2994 gboolean is_ref = FALSE;
2995 gboolean is_literal = FALSE;
2996 gboolean is_ptr = FALSE;
2998 MonoType *type = mono_field_get_type_checked (field, &error);
3000 if (!mono_error_ok (&error))
3001 mono_error_raise_exception (&error);
3003 switch (type->type) {
3004 case MONO_TYPE_STRING:
3005 case MONO_TYPE_OBJECT:
3006 case MONO_TYPE_CLASS:
3007 case MONO_TYPE_ARRAY:
3008 case MONO_TYPE_SZARRAY:
3013 case MONO_TYPE_BOOLEAN:
3016 case MONO_TYPE_CHAR:
3025 case MONO_TYPE_VALUETYPE:
3026 is_ref = type->byref;
3028 case MONO_TYPE_GENERICINST:
3029 is_ref = !mono_type_generic_inst_is_valuetype (type);
3035 g_error ("type 0x%x not handled in "
3036 "mono_field_get_value_object", type->type);
3040 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3043 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3047 vtable = mono_class_vtable (domain, field->parent);
3049 char *name = mono_type_get_full_name (field->parent);
3050 /*FIXME extend this to use the MonoError api*/
3051 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3055 if (!vtable->initialized)
3056 mono_runtime_class_init (vtable);
3064 get_default_field_value (domain, field, &o);
3065 } else if (is_static) {
3066 mono_field_static_get_value (vtable, field, &o);
3068 mono_field_get_value (obj, field, &o);
3074 static MonoMethod *m;
3080 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3081 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3087 get_default_field_value (domain, field, v);
3088 } else if (is_static) {
3089 mono_field_static_get_value (vtable, field, v);
3091 mono_field_get_value (obj, field, v);
3094 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3096 args [1] = mono_type_get_object (mono_domain_get (), type);
3098 return mono_runtime_invoke (m, NULL, args, NULL);
3101 /* boxed value type */
3102 klass = mono_class_from_mono_type (type);
3104 if (mono_class_is_nullable (klass))
3105 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3107 o = mono_object_new (domain, klass);
3108 v = ((gchar *) o) + sizeof (MonoObject);
3111 get_default_field_value (domain, field, v);
3112 } else if (is_static) {
3113 mono_field_static_get_value (vtable, field, v);
3115 mono_field_get_value (obj, field, v);
3122 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3125 const char *p = blob;
3126 mono_metadata_decode_blob_size (p, &p);
3129 case MONO_TYPE_BOOLEAN:
3132 *(guint8 *) value = *p;
3134 case MONO_TYPE_CHAR:
3137 *(guint16*) value = read16 (p);
3141 *(guint32*) value = read32 (p);
3145 *(guint64*) value = read64 (p);
3148 readr4 (p, (float*) value);
3151 readr8 (p, (double*) value);
3153 case MONO_TYPE_STRING:
3154 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3156 case MONO_TYPE_CLASS:
3157 *(gpointer*) value = NULL;
3161 g_warning ("type 0x%02x should not be in constant table", type);
3167 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3169 MonoTypeEnum def_type;
3172 data = mono_class_get_field_default_value (field, &def_type);
3173 mono_get_constant_value_from_blob (domain, def_type, data, value);
3177 * mono_field_static_get_value:
3178 * @vt: vtable to the object
3179 * @field: MonoClassField describing the field to fetch information from
3180 * @value: where the value is returned
3182 * Use this routine to get the value of the static field @field value.
3184 * The pointer provided by value must be of the field type, for reference
3185 * types this is a MonoObject*, for value types its the actual pointer to
3190 * mono_field_static_get_value (vt, int_field, &i);
3193 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3197 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3199 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3200 get_default_field_value (vt->domain, field, value);
3204 if (field->offset == -1) {
3205 /* Special static */
3206 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3207 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3209 src = (char*)vt->data + field->offset;
3211 set_value (field->type, value, src, TRUE);
3215 * mono_property_set_value:
3216 * @prop: MonoProperty to set
3217 * @obj: instance object on which to act
3218 * @params: parameters to pass to the propery
3219 * @exc: optional exception
3221 * Invokes the property's set method with the given arguments on the
3222 * object instance obj (or NULL for static properties).
3224 * You can pass NULL as the exc argument if you don't want to
3225 * catch exceptions, otherwise, *exc will be set to the exception
3226 * thrown, if any. if an exception is thrown, you can't use the
3227 * MonoObject* result from the function.
3230 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3232 default_mono_runtime_invoke (prop->set, obj, params, exc);
3236 * mono_property_get_value:
3237 * @prop: MonoProperty to fetch
3238 * @obj: instance object on which to act
3239 * @params: parameters to pass to the propery
3240 * @exc: optional exception
3242 * Invokes the property's get method with the given arguments on the
3243 * object instance obj (or NULL for static properties).
3245 * You can pass NULL as the exc argument if you don't want to
3246 * catch exceptions, otherwise, *exc will be set to the exception
3247 * thrown, if any. if an exception is thrown, you can't use the
3248 * MonoObject* result from the function.
3250 * Returns: the value from invoking the get method on the property.
3253 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3255 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3259 * mono_nullable_init:
3260 * @buf: The nullable structure to initialize.
3261 * @value: the value to initialize from
3262 * @klass: the type for the object
3264 * Initialize the nullable structure pointed to by @buf from @value which
3265 * should be a boxed value type. The size of @buf should be able to hold
3266 * as much data as the @klass->instance_size (which is the number of bytes
3267 * that will be copies).
3269 * Since Nullables have variable structure, we can not define a C
3270 * structure for them.
3273 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3275 MonoClass *param_class = klass->cast_class;
3277 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3278 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3280 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3282 if (param_class->has_references)
3283 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3285 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3287 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3292 * mono_nullable_box:
3293 * @buf: The buffer representing the data to be boxed
3294 * @klass: the type to box it as.
3296 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3300 mono_nullable_box (guint8 *buf, MonoClass *klass)
3302 MonoClass *param_class = klass->cast_class;
3304 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3305 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3307 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3308 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3309 if (param_class->has_references)
3310 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3312 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3320 * mono_get_delegate_invoke:
3321 * @klass: The delegate class
3323 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3326 mono_get_delegate_invoke (MonoClass *klass)
3330 /* This is called at runtime, so avoid the slower search in metadata */
3331 mono_class_setup_methods (klass);
3332 if (klass->exception_type)
3334 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3339 * mono_runtime_delegate_invoke:
3340 * @delegate: pointer to a delegate object.
3341 * @params: parameters for the delegate.
3342 * @exc: Pointer to the exception result.
3344 * Invokes the delegate method @delegate with the parameters provided.
3346 * You can pass NULL as the exc argument if you don't want to
3347 * catch exceptions, otherwise, *exc will be set to the exception
3348 * thrown, if any. if an exception is thrown, you can't use the
3349 * MonoObject* result from the function.
3352 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3356 im = mono_get_delegate_invoke (delegate->vtable->klass);
3359 return mono_runtime_invoke (im, delegate, params, exc);
3362 static char **main_args = NULL;
3363 static int num_main_args;
3366 * mono_runtime_get_main_args:
3368 * Returns: a MonoArray with the arguments passed to the main program
3371 mono_runtime_get_main_args (void)
3375 MonoDomain *domain = mono_domain_get ();
3380 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3382 for (i = 0; i < num_main_args; ++i)
3383 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3389 free_main_args (void)
3393 for (i = 0; i < num_main_args; ++i)
3394 g_free (main_args [i]);
3399 * mono_runtime_run_main:
3400 * @method: the method to start the application with (usually Main)
3401 * @argc: number of arguments from the command line
3402 * @argv: array of strings from the command line
3403 * @exc: excetption results
3405 * Execute a standard Main() method (argc/argv contains the
3406 * executable name). This method also sets the command line argument value
3407 * needed by System.Environment.
3412 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3416 MonoArray *args = NULL;
3417 MonoDomain *domain = mono_domain_get ();
3418 gchar *utf8_fullpath;
3419 MonoMethodSignature *sig;
3421 g_assert (method != NULL);
3423 mono_thread_set_main (mono_thread_current ());
3425 main_args = g_new0 (char*, argc);
3426 num_main_args = argc;
3428 if (!g_path_is_absolute (argv [0])) {
3429 gchar *basename = g_path_get_basename (argv [0]);
3430 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3434 utf8_fullpath = mono_utf8_from_external (fullpath);
3435 if(utf8_fullpath == NULL) {
3436 /* Printing the arg text will cause glib to
3437 * whinge about "Invalid UTF-8", but at least
3438 * its relevant, and shows the problem text
3441 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3442 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3449 utf8_fullpath = mono_utf8_from_external (argv[0]);
3450 if(utf8_fullpath == NULL) {
3451 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3452 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3457 main_args [0] = utf8_fullpath;
3459 for (i = 1; i < argc; ++i) {
3462 utf8_arg=mono_utf8_from_external (argv[i]);
3463 if(utf8_arg==NULL) {
3464 /* Ditto the comment about Invalid UTF-8 here */
3465 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3466 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3470 main_args [i] = utf8_arg;
3475 sig = mono_method_signature (method);
3477 g_print ("Unable to load Main method.\n");
3481 if (sig->param_count) {
3482 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3483 for (i = 0; i < argc; ++i) {
3484 /* The encodings should all work, given that
3485 * we've checked all these args for the
3488 gchar *str = mono_utf8_from_external (argv [i]);
3489 MonoString *arg = mono_string_new (domain, str);
3490 mono_array_setref (args, i, arg);
3494 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3497 mono_assembly_set_main (method->klass->image->assembly);
3499 return mono_runtime_exec_main (method, args, exc);
3503 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3505 static MonoMethod *serialize_method;
3510 if (!serialize_method) {
3511 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3512 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3515 if (!serialize_method) {
3520 g_assert (!mono_object_class (obj)->marshalbyref);
3524 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3532 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3534 static MonoMethod *deserialize_method;
3539 if (!deserialize_method) {
3540 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3541 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3543 if (!deserialize_method) {
3550 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3558 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3560 static MonoMethod *get_proxy_method;
3562 MonoDomain *domain = mono_domain_get ();
3563 MonoRealProxy *real_proxy;
3564 MonoReflectionType *reflection_type;
3565 MonoTransparentProxy *transparent_proxy;
3567 if (!get_proxy_method)
3568 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3570 g_assert (obj->vtable->klass->marshalbyref);
3572 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3573 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3575 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3576 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3579 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3583 return (MonoObject*) transparent_proxy;
3587 * mono_object_xdomain_representation
3589 * @target_domain: a domain
3590 * @exc: pointer to a MonoObject*
3592 * Creates a representation of obj in the domain target_domain. This
3593 * is either a copy of obj arrived through via serialization and
3594 * deserialization or a proxy, depending on whether the object is
3595 * serializable or marshal by ref. obj must not be in target_domain.
3597 * If the object cannot be represented in target_domain, NULL is
3598 * returned and *exc is set to an appropriate exception.
3601 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3603 MonoObject *deserialized = NULL;
3604 gboolean failure = FALSE;
3608 if (mono_object_class (obj)->marshalbyref) {
3609 deserialized = make_transparent_proxy (obj, &failure, exc);
3611 MonoDomain *domain = mono_domain_get ();
3612 MonoObject *serialized;
3614 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3615 serialized = serialize_object (obj, &failure, exc);
3616 mono_domain_set_internal_with_options (target_domain, FALSE);
3618 deserialized = deserialize_object (serialized, &failure, exc);
3619 if (domain != target_domain)
3620 mono_domain_set_internal_with_options (domain, FALSE);
3623 return deserialized;
3626 /* Used in call_unhandled_exception_delegate */
3628 create_unhandled_exception_eventargs (MonoObject *exc)
3632 MonoMethod *method = NULL;
3633 MonoBoolean is_terminating = TRUE;
3636 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3639 mono_class_init (klass);
3641 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3642 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3646 args [1] = &is_terminating;
3648 obj = mono_object_new (mono_domain_get (), klass);
3649 mono_runtime_invoke (method, obj, args, NULL);
3654 /* Used in mono_unhandled_exception */
3656 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3657 MonoObject *e = NULL;
3659 MonoDomain *current_domain = mono_domain_get ();
3661 if (domain != current_domain)
3662 mono_domain_set_internal_with_options (domain, FALSE);
3664 g_assert (domain == mono_object_domain (domain->domain));
3666 if (mono_object_domain (exc) != domain) {
3667 MonoObject *serialization_exc;
3669 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3671 if (serialization_exc) {
3673 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3676 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3677 "System.Runtime.Serialization", "SerializationException",
3678 "Could not serialize unhandled exception.");
3682 g_assert (mono_object_domain (exc) == domain);
3684 pa [0] = domain->domain;
3685 pa [1] = create_unhandled_exception_eventargs (exc);
3686 mono_runtime_delegate_invoke (delegate, pa, &e);
3688 if (domain != current_domain)
3689 mono_domain_set_internal_with_options (current_domain, FALSE);
3693 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3694 if (!mono_error_ok (&error)) {
3695 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3696 mono_error_cleanup (&error);
3698 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3704 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3707 * mono_runtime_unhandled_exception_policy_set:
3708 * @policy: the new policy
3710 * This is a VM internal routine.
3712 * Sets the runtime policy for handling unhandled exceptions.
3715 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3716 runtime_unhandled_exception_policy = policy;
3720 * mono_runtime_unhandled_exception_policy_get:
3722 * This is a VM internal routine.
3724 * Gets the runtime policy for handling unhandled exceptions.
3726 MonoRuntimeUnhandledExceptionPolicy
3727 mono_runtime_unhandled_exception_policy_get (void) {
3728 return runtime_unhandled_exception_policy;
3732 * mono_unhandled_exception:
3733 * @exc: exception thrown
3735 * This is a VM internal routine.
3737 * We call this function when we detect an unhandled exception
3738 * in the default domain.
3740 * It invokes the * UnhandledException event in AppDomain or prints
3741 * a warning to the console
3744 mono_unhandled_exception (MonoObject *exc)
3746 MonoDomain *current_domain = mono_domain_get ();
3747 MonoDomain *root_domain = mono_get_root_domain ();
3748 MonoClassField *field;
3749 MonoObject *current_appdomain_delegate;
3750 MonoObject *root_appdomain_delegate;
3752 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3753 "UnhandledException");
3756 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3757 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3758 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3759 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3760 if (current_domain != root_domain) {
3761 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3763 current_appdomain_delegate = NULL;
3766 /* set exitcode only if we will abort the process */
3768 mono_environment_exitcode_set (1);
3769 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3770 mono_print_unhandled_exception (exc);
3772 if (root_appdomain_delegate) {
3773 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3775 if (current_appdomain_delegate) {
3776 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3783 * mono_runtime_exec_managed_code:
3784 * @domain: Application domain
3785 * @main_func: function to invoke from the execution thread
3786 * @main_args: parameter to the main_func
3788 * Launch a new thread to execute a function
3790 * main_func is called back from the thread with main_args as the
3791 * parameter. The callback function is expected to start Main()
3792 * eventually. This function then waits for all managed threads to
3794 * It is not necesseray anymore to execute managed code in a subthread,
3795 * so this function should not be used anymore by default: just
3796 * execute the code and then call mono_thread_manage ().
3799 mono_runtime_exec_managed_code (MonoDomain *domain,
3800 MonoMainThreadFunc main_func,
3803 mono_thread_create (domain, main_func, main_args);
3805 mono_thread_manage ();
3809 * Execute a standard Main() method (args doesn't contain the
3813 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3818 MonoCustomAttrInfo* cinfo;
3819 gboolean has_stathread_attribute;
3820 MonoInternalThread* thread = mono_thread_internal_current ();
3826 domain = mono_object_domain (args);
3827 if (!domain->entry_assembly) {
3829 MonoAssembly *assembly;
3831 assembly = method->klass->image->assembly;
3832 domain->entry_assembly = assembly;
3833 /* Domains created from another domain already have application_base and configuration_file set */
3834 if (domain->setup->application_base == NULL) {
3835 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3838 if (domain->setup->configuration_file == NULL) {
3839 str = g_strconcat (assembly->image->name, ".config", NULL);
3840 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3842 mono_set_private_bin_path_from_config (domain);
3846 cinfo = mono_custom_attrs_from_method (method);
3848 static MonoClass *stathread_attribute = NULL;
3849 if (!stathread_attribute)
3850 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3851 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3853 mono_custom_attrs_free (cinfo);
3855 has_stathread_attribute = FALSE;
3857 if (has_stathread_attribute) {
3858 thread->apartment_state = ThreadApartmentState_STA;
3860 thread->apartment_state = ThreadApartmentState_MTA;
3862 mono_thread_init_apartment_state ();
3864 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3866 /* FIXME: check signature of method */
3867 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3869 res = mono_runtime_invoke (method, NULL, pa, exc);
3871 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3875 mono_environment_exitcode_set (rval);
3877 mono_runtime_invoke (method, NULL, pa, exc);
3881 /* If the return type of Main is void, only
3882 * set the exitcode if an exception was thrown
3883 * (we don't want to blow away an
3884 * explicitly-set exit code)
3887 mono_environment_exitcode_set (rval);
3891 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3897 * mono_install_runtime_invoke:
3898 * @func: Function to install
3900 * This is a VM internal routine
3903 mono_install_runtime_invoke (MonoInvokeFunc func)
3905 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3910 * mono_runtime_invoke_array:
3911 * @method: method to invoke
3912 * @obJ: object instance
3913 * @params: arguments to the method
3914 * @exc: exception information.
3916 * Invokes the method represented by @method on the object @obj.
3918 * obj is the 'this' pointer, it should be NULL for static
3919 * methods, a MonoObject* for object instances and a pointer to
3920 * the value type for value types.
3922 * The params array contains the arguments to the method with the
3923 * same convention: MonoObject* pointers for object instances and
3924 * pointers to the value type otherwise. The _invoke_array
3925 * variant takes a C# object[] as the params argument (MonoArray
3926 * *params): in this case the value types are boxed inside the
3927 * respective reference representation.
3929 * From unmanaged code you'll usually use the
3930 * mono_runtime_invoke() variant.
3932 * Note that this function doesn't handle virtual methods for
3933 * you, it will exec the exact method you pass: we still need to
3934 * expose a function to lookup the derived class implementation
3935 * of a virtual method (there are examples of this in the code,
3938 * You can pass NULL as the exc argument if you don't want to
3939 * catch exceptions, otherwise, *exc will be set to the exception
3940 * thrown, if any. if an exception is thrown, you can't use the
3941 * MonoObject* result from the function.
3943 * If the method returns a value type, it is boxed in an object
3947 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3950 MonoMethodSignature *sig = mono_method_signature (method);
3951 gpointer *pa = NULL;
3954 gboolean has_byref_nullables = FALSE;
3956 if (NULL != params) {
3957 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3958 for (i = 0; i < mono_array_length (params); i++) {
3959 MonoType *t = sig->params [i];
3965 case MONO_TYPE_BOOLEAN:
3968 case MONO_TYPE_CHAR:
3977 case MONO_TYPE_VALUETYPE:
3978 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3979 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3980 pa [i] = mono_array_get (params, MonoObject*, i);
3982 has_byref_nullables = TRUE;
3984 /* MS seems to create the objects if a null is passed in */
3985 if (!mono_array_get (params, MonoObject*, i))
3986 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3990 * We can't pass the unboxed vtype byref to the callee, since
3991 * that would mean the callee would be able to modify boxed
3992 * primitive types. So we (and MS) make a copy of the boxed
3993 * object, pass that to the callee, and replace the original
3994 * boxed object in the arg array with the copy.
3996 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3997 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3998 mono_array_setref (params, i, copy);
4001 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4004 case MONO_TYPE_STRING:
4005 case MONO_TYPE_OBJECT:
4006 case MONO_TYPE_CLASS:
4007 case MONO_TYPE_ARRAY:
4008 case MONO_TYPE_SZARRAY:
4010 pa [i] = mono_array_addr (params, MonoObject*, i);
4011 // FIXME: I need to check this code path
4013 pa [i] = mono_array_get (params, MonoObject*, i);
4015 case MONO_TYPE_GENERICINST:
4017 t = &t->data.generic_class->container_class->this_arg;
4019 t = &t->data.generic_class->container_class->byval_arg;
4021 case MONO_TYPE_PTR: {
4024 /* The argument should be an IntPtr */
4025 arg = mono_array_get (params, MonoObject*, i);
4029 g_assert (arg->vtable->klass == mono_defaults.int_class);
4030 pa [i] = ((MonoIntPtr*)arg)->m_value;
4035 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4040 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4043 if (mono_class_is_nullable (method->klass)) {
4044 /* Need to create a boxed vtype instead */
4050 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4054 obj = mono_object_new (mono_domain_get (), method->klass);
4055 g_assert (obj); /*maybe we should raise a TLE instead?*/
4056 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4057 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4059 if (method->klass->valuetype)
4060 o = mono_object_unbox (obj);
4063 } else if (method->klass->valuetype) {
4064 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4067 mono_runtime_invoke (method, o, pa, exc);
4070 if (mono_class_is_nullable (method->klass)) {
4071 MonoObject *nullable;
4073 /* Convert the unboxed vtype into a Nullable structure */
4074 nullable = mono_object_new (mono_domain_get (), method->klass);
4076 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4077 obj = mono_object_unbox (nullable);
4080 /* obj must be already unboxed if needed */
4081 res = mono_runtime_invoke (method, obj, pa, exc);
4083 if (sig->ret->type == MONO_TYPE_PTR) {
4084 MonoClass *pointer_class;
4085 static MonoMethod *box_method;
4087 MonoObject *box_exc;
4090 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4091 * convert it to a Pointer object.
4093 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4095 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4097 g_assert (res->vtable->klass == mono_defaults.int_class);
4098 box_args [0] = ((MonoIntPtr*)res)->m_value;
4099 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4100 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4101 g_assert (!box_exc);
4104 if (has_byref_nullables) {
4106 * The runtime invoke wrapper already converted byref nullables back,
4107 * and stored them in pa, we just need to copy them back to the
4110 for (i = 0; i < mono_array_length (params); i++) {
4111 MonoType *t = sig->params [i];
4113 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4114 mono_array_setref (params, i, pa [i]);
4123 arith_overflow (void)
4125 mono_raise_exception (mono_get_exception_overflow ());
4129 * mono_object_allocate:
4130 * @size: number of bytes to allocate
4132 * This is a very simplistic routine until we have our GC-aware
4135 * Returns: an allocated object of size @size, or NULL on failure.
4137 static inline void *
4138 mono_object_allocate (size_t size, MonoVTable *vtable)
4141 mono_stats.new_object_count++;
4142 ALLOC_OBJECT (o, vtable, size);
4148 * mono_object_allocate_ptrfree:
4149 * @size: number of bytes to allocate
4151 * Note that the memory allocated is not zeroed.
4152 * Returns: an allocated object of size @size, or NULL on failure.
4154 static inline void *
4155 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4158 mono_stats.new_object_count++;
4159 ALLOC_PTRFREE (o, vtable, size);
4163 static inline void *
4164 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4167 ALLOC_TYPED (o, size, vtable);
4168 mono_stats.new_object_count++;
4175 * @klass: the class of the object that we want to create
4177 * Returns: a newly created object whose definition is
4178 * looked up using @klass. This will not invoke any constructors,
4179 * so the consumer of this routine has to invoke any constructors on
4180 * its own to initialize the object.
4182 * It returns NULL on failure.
4185 mono_object_new (MonoDomain *domain, MonoClass *klass)
4189 MONO_ARCH_SAVE_REGS;
4190 vtable = mono_class_vtable (domain, klass);
4193 return mono_object_new_specific (vtable);
4197 * mono_object_new_pinned:
4199 * Same as mono_object_new, but the returned object will be pinned.
4200 * For SGEN, these objects will only be freed at appdomain unload.
4203 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4207 MONO_ARCH_SAVE_REGS;
4208 vtable = mono_class_vtable (domain, klass);
4213 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4215 return mono_object_new_specific (vtable);
4220 * mono_object_new_specific:
4221 * @vtable: the vtable of the object that we want to create
4223 * Returns: A newly created object with class and domain specified
4227 mono_object_new_specific (MonoVTable *vtable)
4231 MONO_ARCH_SAVE_REGS;
4233 /* check for is_com_object for COM Interop */
4234 if (vtable->remote || vtable->klass->is_com_object)
4237 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4240 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4243 mono_class_init (klass);
4245 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4247 vtable->domain->create_proxy_for_type_method = im;
4250 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4252 o = mono_runtime_invoke (im, NULL, pa, NULL);
4253 if (o != NULL) return o;
4256 return mono_object_new_alloc_specific (vtable);
4260 mono_object_new_alloc_specific (MonoVTable *vtable)
4264 if (!vtable->klass->has_references) {
4265 o = mono_object_new_ptrfree (vtable);
4266 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4267 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4269 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4270 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4272 if (G_UNLIKELY (vtable->klass->has_finalize))
4273 mono_object_register_finalizer (o);
4275 if (G_UNLIKELY (profile_allocs))
4276 mono_profiler_allocation (o, vtable->klass);
4281 mono_object_new_fast (MonoVTable *vtable)
4284 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4289 mono_object_new_ptrfree (MonoVTable *vtable)
4292 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4293 #if NEED_TO_ZERO_PTRFREE
4294 /* an inline memset is much faster for the common vcase of small objects
4295 * note we assume the allocated size is a multiple of sizeof (void*).
4297 if (vtable->klass->instance_size < 128) {
4299 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4300 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4306 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4313 mono_object_new_ptrfree_box (MonoVTable *vtable)
4316 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4317 /* the object will be boxed right away, no need to memzero it */
4322 * mono_class_get_allocation_ftn:
4324 * @for_box: the object will be used for boxing
4325 * @pass_size_in_words:
4327 * Return the allocation function appropriate for the given class.
4331 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4333 *pass_size_in_words = FALSE;
4335 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4336 profile_allocs = FALSE;
4338 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4339 return mono_object_new_specific;
4341 if (!vtable->klass->has_references) {
4342 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4344 return mono_object_new_ptrfree_box;
4345 return mono_object_new_ptrfree;
4348 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4350 return mono_object_new_fast;
4353 * FIXME: This is actually slower than mono_object_new_fast, because
4354 * of the overhead of parameter passing.
4357 *pass_size_in_words = TRUE;
4358 #ifdef GC_REDIRECT_TO_LOCAL
4359 return GC_local_gcj_fast_malloc;
4361 return GC_gcj_fast_malloc;
4366 return mono_object_new_specific;
4370 * mono_object_new_from_token:
4371 * @image: Context where the type_token is hosted
4372 * @token: a token of the type that we want to create
4374 * Returns: A newly created object whose definition is
4375 * looked up using @token in the @image image
4378 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4382 class = mono_class_get (image, token);
4384 return mono_object_new (domain, class);
4389 * mono_object_clone:
4390 * @obj: the object to clone
4392 * Returns: A newly created object who is a shallow copy of @obj
4395 mono_object_clone (MonoObject *obj)
4398 int size = obj->vtable->klass->instance_size;
4400 o = mono_object_allocate (size, obj->vtable);
4402 if (obj->vtable->klass->has_references) {
4403 mono_gc_wbarrier_object_copy (o, obj);
4405 int size = obj->vtable->klass->instance_size;
4406 /* do not copy the sync state */
4407 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4409 if (G_UNLIKELY (profile_allocs))
4410 mono_profiler_allocation (o, obj->vtable->klass);
4412 if (obj->vtable->klass->has_finalize)
4413 mono_object_register_finalizer (o);
4418 * mono_array_full_copy:
4419 * @src: source array to copy
4420 * @dest: destination array
4422 * Copies the content of one array to another with exactly the same type and size.
4425 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4428 MonoClass *klass = src->obj.vtable->klass;
4430 MONO_ARCH_SAVE_REGS;
4432 g_assert (klass == dest->obj.vtable->klass);
4434 size = mono_array_length (src);
4435 g_assert (size == mono_array_length (dest));
4436 size *= mono_array_element_size (klass);
4438 if (klass->element_class->valuetype) {
4439 if (klass->element_class->has_references)
4440 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4442 memcpy (&dest->vector, &src->vector, size);
4444 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4447 memcpy (&dest->vector, &src->vector, size);
4452 * mono_array_clone_in_domain:
4453 * @domain: the domain in which the array will be cloned into
4454 * @array: the array to clone
4456 * This routine returns a copy of the array that is hosted on the
4457 * specified MonoDomain.
4460 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4465 MonoClass *klass = array->obj.vtable->klass;
4467 MONO_ARCH_SAVE_REGS;
4469 if (array->bounds == NULL) {
4470 size = mono_array_length (array);
4471 o = mono_array_new_full (domain, klass, &size, NULL);
4473 size *= mono_array_element_size (klass);
4475 if (klass->element_class->valuetype) {
4476 if (klass->element_class->has_references)
4477 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4479 memcpy (&o->vector, &array->vector, size);
4481 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4484 memcpy (&o->vector, &array->vector, size);
4489 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4490 size = mono_array_element_size (klass);
4491 for (i = 0; i < klass->rank; ++i) {
4492 sizes [i] = array->bounds [i].length;
4493 size *= array->bounds [i].length;
4494 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4496 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4498 if (klass->element_class->valuetype) {
4499 if (klass->element_class->has_references)
4500 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4502 memcpy (&o->vector, &array->vector, size);
4504 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4507 memcpy (&o->vector, &array->vector, size);
4515 * @array: the array to clone
4517 * Returns: A newly created array who is a shallow copy of @array
4520 mono_array_clone (MonoArray *array)
4522 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4525 /* helper macros to check for overflow when calculating the size of arrays */
4526 #ifdef MONO_BIG_ARRAYS
4527 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4528 #define MYGUINT_MAX MYGUINT64_MAX
4529 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4530 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4531 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4532 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4533 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4535 #define MYGUINT32_MAX 4294967295U
4536 #define MYGUINT_MAX MYGUINT32_MAX
4537 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4538 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4539 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4540 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4541 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4545 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4549 byte_len = mono_array_element_size (class);
4550 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4553 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4555 byte_len += sizeof (MonoArray);
4563 * mono_array_new_full:
4564 * @domain: domain where the object is created
4565 * @array_class: array class
4566 * @lengths: lengths for each dimension in the array
4567 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4569 * This routine creates a new array objects with the given dimensions,
4570 * lower bounds and type.
4573 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4575 uintptr_t byte_len, len, bounds_size;
4578 MonoArrayBounds *bounds;
4582 if (!array_class->inited)
4583 mono_class_init (array_class);
4587 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4588 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4590 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4594 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4596 for (i = 0; i < array_class->rank; ++i) {
4597 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4599 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4600 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4605 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4606 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4610 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4611 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4612 byte_len = (byte_len + 3) & ~3;
4613 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4614 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4615 byte_len += bounds_size;
4618 * Following three lines almost taken from mono_object_new ():
4619 * they need to be kept in sync.
4621 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4622 #ifndef HAVE_SGEN_GC
4623 if (!array_class->has_references) {
4624 o = mono_object_allocate_ptrfree (byte_len, vtable);
4625 #if NEED_TO_ZERO_PTRFREE
4626 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4628 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4629 o = mono_object_allocate_spec (byte_len, vtable);
4631 o = mono_object_allocate (byte_len, vtable);
4634 array = (MonoArray*)o;
4635 array->max_length = len;
4638 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4639 array->bounds = bounds;
4643 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4645 o = mono_gc_alloc_vector (vtable, byte_len, len);
4646 array = (MonoArray*)o;
4647 mono_stats.new_object_count++;
4649 bounds = array->bounds;
4653 for (i = 0; i < array_class->rank; ++i) {
4654 bounds [i].length = lengths [i];
4656 bounds [i].lower_bound = lower_bounds [i];
4660 if (G_UNLIKELY (profile_allocs))
4661 mono_profiler_allocation (o, array_class);
4668 * @domain: domain where the object is created
4669 * @eclass: element class
4670 * @n: number of array elements
4672 * This routine creates a new szarray with @n elements of type @eclass.
4675 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4679 MONO_ARCH_SAVE_REGS;
4681 ac = mono_array_class_get (eclass, 1);
4684 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4688 * mono_array_new_specific:
4689 * @vtable: a vtable in the appropriate domain for an initialized class
4690 * @n: number of array elements
4692 * This routine is a fast alternative to mono_array_new() for code which
4693 * can be sure about the domain it operates in.
4696 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4702 MONO_ARCH_SAVE_REGS;
4704 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4709 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4710 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4713 #ifndef HAVE_SGEN_GC
4714 if (!vtable->klass->has_references) {
4715 o = mono_object_allocate_ptrfree (byte_len, vtable);
4716 #if NEED_TO_ZERO_PTRFREE
4717 ((MonoArray*)o)->bounds = NULL;
4718 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4720 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4721 o = mono_object_allocate_spec (byte_len, vtable);
4723 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4724 o = mono_object_allocate (byte_len, vtable);
4727 ao = (MonoArray *)o;
4730 o = mono_gc_alloc_vector (vtable, byte_len, n);
4732 mono_stats.new_object_count++;
4735 if (G_UNLIKELY (profile_allocs))
4736 mono_profiler_allocation (o, vtable->klass);
4742 * mono_string_new_utf16:
4743 * @text: a pointer to an utf16 string
4744 * @len: the length of the string
4746 * Returns: A newly created string object which contains @text.
4749 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4753 s = mono_string_new_size (domain, len);
4754 g_assert (s != NULL);
4756 memcpy (mono_string_chars (s), text, len * 2);
4762 * mono_string_new_size:
4763 * @text: a pointer to an utf16 string
4764 * @len: the length of the string
4766 * Returns: A newly created string object of @len
4769 mono_string_new_size (MonoDomain *domain, gint32 len)
4773 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4775 /* overflow ? can't fit it, can't allocate it! */
4777 mono_gc_out_of_memory (-1);
4779 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4782 #ifndef HAVE_SGEN_GC
4783 s = mono_object_allocate_ptrfree (size, vtable);
4787 s = mono_gc_alloc_string (vtable, size, len);
4789 #if NEED_TO_ZERO_PTRFREE
4792 if (G_UNLIKELY (profile_allocs))
4793 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4799 * mono_string_new_len:
4800 * @text: a pointer to an utf8 string
4801 * @length: number of bytes in @text to consider
4803 * Returns: A newly created string object which contains @text.
4806 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4808 GError *error = NULL;
4809 MonoString *o = NULL;
4811 glong items_written;
4813 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4816 o = mono_string_new_utf16 (domain, ut, items_written);
4818 g_error_free (error);
4827 * @text: a pointer to an utf8 string
4829 * Returns: A newly created string object which contains @text.
4832 mono_string_new (MonoDomain *domain, const char *text)
4834 GError *error = NULL;
4835 MonoString *o = NULL;
4837 glong items_written;
4842 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4845 o = mono_string_new_utf16 (domain, ut, items_written);
4847 g_error_free (error);
4850 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4855 MonoString *o = NULL;
4857 if (!g_utf8_validate (text, -1, &end))
4860 len = g_utf8_strlen (text, -1);
4861 o = mono_string_new_size (domain, len);
4862 str = mono_string_chars (o);
4864 while (text < end) {
4865 *str++ = g_utf8_get_char (text);
4866 text = g_utf8_next_char (text);
4873 * mono_string_new_wrapper:
4874 * @text: pointer to utf8 characters.
4876 * Helper function to create a string object from @text in the current domain.
4879 mono_string_new_wrapper (const char *text)
4881 MonoDomain *domain = mono_domain_get ();
4883 MONO_ARCH_SAVE_REGS;
4886 return mono_string_new (domain, text);
4893 * @class: the class of the value
4894 * @value: a pointer to the unboxed data
4896 * Returns: A newly created object which contains @value.
4899 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4905 g_assert (class->valuetype);
4906 if (mono_class_is_nullable (class))
4907 return mono_nullable_box (value, class);
4909 vtable = mono_class_vtable (domain, class);
4912 size = mono_class_instance_size (class);
4913 res = mono_object_new_alloc_specific (vtable);
4914 if (G_UNLIKELY (profile_allocs))
4915 mono_profiler_allocation (res, class);
4917 size = size - sizeof (MonoObject);
4920 g_assert (size == mono_class_value_size (class, NULL));
4921 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4923 #if NO_UNALIGNED_ACCESS
4924 memcpy ((char *)res + sizeof (MonoObject), value, size);
4928 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4931 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4934 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4937 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4940 memcpy ((char *)res + sizeof (MonoObject), value, size);
4944 if (class->has_finalize)
4945 mono_object_register_finalizer (res);
4951 * @dest: destination pointer
4952 * @src: source pointer
4953 * @klass: a valuetype class
4955 * Copy a valuetype from @src to @dest. This function must be used
4956 * when @klass contains references fields.
4959 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4961 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4965 * mono_value_copy_array:
4966 * @dest: destination array
4967 * @dest_idx: index in the @dest array
4968 * @src: source pointer
4969 * @count: number of items
4971 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4972 * This function must be used when @klass contains references fields.
4973 * Overlap is handled.
4976 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4978 int size = mono_array_element_size (dest->obj.vtable->klass);
4979 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4980 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4981 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4985 * mono_object_get_domain:
4986 * @obj: object to query
4988 * Returns: the MonoDomain where the object is hosted
4991 mono_object_get_domain (MonoObject *obj)
4993 return mono_object_domain (obj);
4997 * mono_object_get_class:
4998 * @obj: object to query
5000 * Returns: the MonOClass of the object.
5003 mono_object_get_class (MonoObject *obj)
5005 return mono_object_class (obj);
5008 * mono_object_get_size:
5009 * @o: object to query
5011 * Returns: the size, in bytes, of @o
5014 mono_object_get_size (MonoObject* o)
5016 MonoClass* klass = mono_object_class (o);
5017 if (klass == mono_defaults.string_class) {
5018 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5019 } else if (o->vtable->rank) {
5020 MonoArray *array = (MonoArray*)o;
5021 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5022 if (array->bounds) {
5025 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5029 return mono_class_instance_size (klass);
5034 * mono_object_unbox:
5035 * @obj: object to unbox
5037 * Returns: a pointer to the start of the valuetype boxed in this
5040 * This method will assert if the object passed is not a valuetype.
5043 mono_object_unbox (MonoObject *obj)
5045 /* add assert for valuetypes? */
5046 g_assert (obj->vtable->klass->valuetype);
5047 return ((char*)obj) + sizeof (MonoObject);
5051 * mono_object_isinst:
5053 * @klass: a pointer to a class
5055 * Returns: @obj if @obj is derived from @klass
5058 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5061 mono_class_init (klass);
5063 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5064 return mono_object_isinst_mbyref (obj, klass);
5069 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5073 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5082 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5083 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5087 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5088 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5091 MonoClass *oklass = vt->klass;
5092 if ((oklass == mono_defaults.transparent_proxy_class))
5093 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5095 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5099 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5101 MonoDomain *domain = mono_domain_get ();
5103 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5104 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5105 MonoMethod *im = NULL;
5108 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5109 im = mono_object_get_virtual_method (rp, im);
5112 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5115 res = mono_runtime_invoke (im, rp, pa, NULL);
5117 if (*(MonoBoolean *) mono_object_unbox(res)) {
5118 /* Update the vtable of the remote type, so it can safely cast to this new type */
5119 mono_upgrade_remote_class (domain, obj, klass);
5128 * mono_object_castclass_mbyref:
5130 * @klass: a pointer to a class
5132 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5135 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5137 if (!obj) return NULL;
5138 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5140 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5142 "InvalidCastException"));
5147 MonoDomain *orig_domain;
5153 str_lookup (MonoDomain *domain, gpointer user_data)
5155 LDStrInfo *info = user_data;
5156 if (info->res || domain == info->orig_domain)
5158 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5164 mono_string_get_pinned (MonoString *str)
5168 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5169 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5171 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5172 news->length = mono_string_length (str);
5178 #define mono_string_get_pinned(str) (str)
5182 mono_string_is_interned_lookup (MonoString *str, int insert)
5184 MonoGHashTable *ldstr_table;
5188 domain = ((MonoObject *)str)->vtable->domain;
5189 ldstr_table = domain->ldstr_table;
5191 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5196 str = mono_string_get_pinned (str);
5198 mono_g_hash_table_insert (ldstr_table, str, str);
5202 LDStrInfo ldstr_info;
5203 ldstr_info.orig_domain = domain;
5204 ldstr_info.ins = str;
5205 ldstr_info.res = NULL;
5207 mono_domain_foreach (str_lookup, &ldstr_info);
5208 if (ldstr_info.res) {
5210 * the string was already interned in some other domain:
5211 * intern it in the current one as well.
5213 mono_g_hash_table_insert (ldstr_table, str, str);
5223 * mono_string_is_interned:
5224 * @o: String to probe
5226 * Returns whether the string has been interned.
5229 mono_string_is_interned (MonoString *o)
5231 return mono_string_is_interned_lookup (o, FALSE);
5235 * mono_string_intern:
5236 * @o: String to intern
5238 * Interns the string passed.
5239 * Returns: The interned string.
5242 mono_string_intern (MonoString *str)
5244 return mono_string_is_interned_lookup (str, TRUE);
5249 * @domain: the domain where the string will be used.
5250 * @image: a metadata context
5251 * @idx: index into the user string table.
5253 * Implementation for the ldstr opcode.
5254 * Returns: a loaded string from the @image/@idx combination.
5257 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5259 MONO_ARCH_SAVE_REGS;
5261 if (image->dynamic) {
5262 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5265 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5266 return NULL; /*FIXME we should probably be raising an exception here*/
5267 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5272 * mono_ldstr_metadata_sig
5273 * @domain: the domain for the string
5274 * @sig: the signature of a metadata string
5276 * Returns: a MonoString for a string stored in the metadata
5279 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5281 const char *str = sig;
5282 MonoString *o, *interned;
5285 len2 = mono_metadata_decode_blob_size (str, &str);
5288 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5289 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5292 guint16 *p2 = (guint16*)mono_string_chars (o);
5293 for (i = 0; i < len2; ++i) {
5294 *p2 = GUINT16_FROM_LE (*p2);
5300 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5302 /* o will get garbage collected */
5306 o = mono_string_get_pinned (o);
5308 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5315 * mono_string_to_utf8:
5316 * @s: a System.String
5318 * Returns the UTF8 representation for @s.
5319 * The resulting buffer needs to be freed with mono_free().
5321 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5324 mono_string_to_utf8 (MonoString *s)
5327 char *result = mono_string_to_utf8_checked (s, &error);
5329 if (!mono_error_ok (&error))
5330 mono_error_raise_exception (&error);
5335 * mono_string_to_utf8_checked:
5336 * @s: a System.String
5337 * @error: a MonoError.
5339 * Converts a MonoString to its UTF8 representation. May fail; check
5340 * @error to determine whether the conversion was successful.
5341 * The resulting buffer should be freed with mono_free().
5344 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5348 GError *gerror = NULL;
5350 mono_error_init (error);
5356 return g_strdup ("");
5358 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5360 mono_error_set_argument (error, "string", "%s", gerror->message);
5361 g_error_free (gerror);
5364 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5365 if (s->length > written) {
5366 /* allocate the total length and copy the part of the string that has been converted */
5367 char *as2 = g_malloc0 (s->length);
5368 memcpy (as2, as, written);
5377 * mono_string_to_utf16:
5380 * Return an null-terminated array of the utf-16 chars
5381 * contained in @s. The result must be freed with g_free().
5382 * This is a temporary helper until our string implementation
5383 * is reworked to always include the null terminating char.
5386 mono_string_to_utf16 (MonoString *s)
5393 as = g_malloc ((s->length * 2) + 2);
5394 as [(s->length * 2)] = '\0';
5395 as [(s->length * 2) + 1] = '\0';
5398 return (gunichar2 *)(as);
5401 memcpy (as, mono_string_chars(s), s->length * 2);
5402 return (gunichar2 *)(as);
5406 * mono_string_from_utf16:
5407 * @data: the UTF16 string (LPWSTR) to convert
5409 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5411 * Returns: a MonoString.
5414 mono_string_from_utf16 (gunichar2 *data)
5416 MonoDomain *domain = mono_domain_get ();
5422 while (data [len]) len++;
5424 return mono_string_new_utf16 (domain, data, len);
5429 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5435 r = mono_string_to_utf8_checked (s, error);
5436 if (!mono_error_ok (error))
5442 len = strlen (r) + 1;
5444 mp_s = mono_mempool_alloc (mp, len);
5446 mp_s = mono_image_alloc (image, len);
5448 memcpy (mp_s, r, len);
5456 * mono_string_to_utf8_image:
5457 * @s: a System.String
5459 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5462 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5464 return mono_string_to_utf8_internal (NULL, image, s, error);
5468 * mono_string_to_utf8_mp:
5469 * @s: a System.String
5471 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5474 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5476 return mono_string_to_utf8_internal (mp, NULL, s, error);
5480 default_ex_handler (MonoException *ex)
5482 MonoObject *o = (MonoObject*)ex;
5483 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5487 static MonoExceptionFunc ex_handler = default_ex_handler;
5490 * mono_install_handler:
5491 * @func: exception handler
5493 * This is an internal JIT routine used to install the handler for exceptions
5497 mono_install_handler (MonoExceptionFunc func)
5499 ex_handler = func? func: default_ex_handler;
5503 * mono_raise_exception:
5504 * @ex: exception object
5506 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5509 mono_raise_exception (MonoException *ex)
5512 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5513 * that will cause gcc to omit the function epilog, causing problems when
5514 * the JIT tries to walk the stack, since the return address on the stack
5515 * will point into the next function in the executable, not this one.
5518 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5519 MonoInternalThread *thread = mono_thread_internal_current ();
5520 g_assert (ex->object.vtable->domain == mono_domain_get ());
5521 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5528 * mono_wait_handle_new:
5529 * @domain: Domain where the object will be created
5530 * @handle: Handle for the wait handle
5532 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5535 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5537 MonoWaitHandle *res;
5538 gpointer params [1];
5539 static MonoMethod *handle_set;
5541 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5543 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5545 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5547 params [0] = &handle;
5548 mono_runtime_invoke (handle_set, res, params, NULL);
5554 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5556 static MonoClassField *f_os_handle;
5557 static MonoClassField *f_safe_handle;
5559 if (!f_os_handle && !f_safe_handle) {
5560 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5561 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5566 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5570 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5577 mono_runtime_capture_context (MonoDomain *domain)
5579 RuntimeInvokeFunction runtime_invoke;
5581 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5582 MonoMethod *method = mono_get_context_capture_method ();
5583 MonoMethod *wrapper;
5586 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5587 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5588 domain->capture_context_method = mono_compile_method (method);
5591 runtime_invoke = domain->capture_context_runtime_invoke;
5593 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5596 * mono_async_result_new:
5597 * @domain:domain where the object will be created.
5598 * @handle: wait handle.
5599 * @state: state to pass to AsyncResult
5600 * @data: C closure data.
5602 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5603 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5607 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5609 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5610 MonoObject *context = mono_runtime_capture_context (domain);
5611 /* we must capture the execution context from the original thread */
5613 MONO_OBJECT_SETREF (res, execution_context, context);
5614 /* note: result may be null if the flow is suppressed */
5618 MONO_OBJECT_SETREF (res, object_data, object_data);
5619 MONO_OBJECT_SETREF (res, async_state, state);
5621 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5623 res->sync_completed = FALSE;
5624 res->completed = FALSE;
5630 mono_message_init (MonoDomain *domain,
5631 MonoMethodMessage *this,
5632 MonoReflectionMethod *method,
5633 MonoArray *out_args)
5635 static MonoClass *object_array_klass;
5636 static MonoClass *byte_array_klass;
5637 static MonoClass *string_array_klass;
5638 MonoMethodSignature *sig = mono_method_signature (method->method);
5644 if (!object_array_klass) {
5647 klass = mono_array_class_get (mono_defaults.object_class, 1);
5650 mono_memory_barrier ();
5651 object_array_klass = klass;
5653 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5656 mono_memory_barrier ();
5657 byte_array_klass = klass;
5659 klass = mono_array_class_get (mono_defaults.string_class, 1);
5662 mono_memory_barrier ();
5663 string_array_klass = klass;
5666 MONO_OBJECT_SETREF (this, method, method);
5668 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5669 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5670 this->async_result = NULL;
5671 this->call_type = CallType_Sync;
5673 names = g_new (char *, sig->param_count);
5674 mono_method_get_param_names (method->method, (const char **) names);
5675 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5677 for (i = 0; i < sig->param_count; i++) {
5678 name = mono_string_new (domain, names [i]);
5679 mono_array_setref (this->names, i, name);
5683 for (i = 0, j = 0; i < sig->param_count; i++) {
5684 if (sig->params [i]->byref) {
5686 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5687 mono_array_setref (this->args, i, arg);
5691 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5695 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5698 mono_array_set (this->arg_types, guint8, i, arg_type);
5703 * mono_remoting_invoke:
5704 * @real_proxy: pointer to a RealProxy object
5705 * @msg: The MonoMethodMessage to execute
5706 * @exc: used to store exceptions
5707 * @out_args: used to store output arguments
5709 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5710 * IMessage interface and it is not trivial to extract results from there. So
5711 * we call an helper method PrivateInvoke instead of calling
5712 * RealProxy::Invoke() directly.
5714 * Returns: the result object.
5717 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5718 MonoObject **exc, MonoArray **out_args)
5720 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5723 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5726 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5728 real_proxy->vtable->domain->private_invoke_method = im;
5731 pa [0] = real_proxy;
5736 return mono_runtime_invoke (im, NULL, pa, exc);
5740 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5741 MonoObject **exc, MonoArray **out_args)
5743 static MonoClass *object_array_klass;
5746 MonoMethodSignature *sig;
5748 int i, j, outarg_count = 0;
5750 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5752 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5753 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5754 target = tp->rp->unwrapped_server;
5756 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5760 domain = mono_domain_get ();
5761 method = msg->method->method;
5762 sig = mono_method_signature (method);
5764 for (i = 0; i < sig->param_count; i++) {
5765 if (sig->params [i]->byref)
5769 if (!object_array_klass) {
5772 klass = mono_array_class_get (mono_defaults.object_class, 1);
5775 mono_memory_barrier ();
5776 object_array_klass = klass;
5779 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5780 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5783 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5785 for (i = 0, j = 0; i < sig->param_count; i++) {
5786 if (sig->params [i]->byref) {
5788 arg = mono_array_get (msg->args, gpointer, i);
5789 mono_array_setref (*out_args, j, arg);
5798 * mono_object_to_string:
5800 * @exc: Any exception thrown by ToString (). May be NULL.
5802 * Returns: the result of calling ToString () on an object.
5805 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5807 static MonoMethod *to_string = NULL;
5813 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5815 method = mono_object_get_virtual_method (obj, to_string);
5817 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5821 * mono_print_unhandled_exception:
5822 * @exc: The exception
5824 * Prints the unhandled exception.
5827 mono_print_unhandled_exception (MonoObject *exc)
5830 char *message = (char*)"";
5831 gboolean free_message = FALSE;
5834 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5835 message = g_strdup ("OutOfMemoryException");
5837 str = mono_object_to_string (exc, NULL);
5839 message = mono_string_to_utf8_checked (str, &error);
5840 if (!mono_error_ok (&error)) {
5841 mono_error_cleanup (&error);
5842 message = (char *) "";
5844 free_message = TRUE;
5850 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5851 * exc->vtable->klass->name, message);
5853 g_printerr ("\nUnhandled Exception: %s\n", message);
5860 * mono_delegate_ctor:
5861 * @this: pointer to an uninitialized delegate object
5862 * @target: target object
5863 * @addr: pointer to native code
5866 * Initialize a delegate and sets a specific method, not the one
5867 * associated with addr. This is useful when sharing generic code.
5868 * In that case addr will most probably not be associated with the
5869 * correct instantiation of the method.
5872 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5874 MonoDelegate *delegate = (MonoDelegate *)this;
5881 delegate->method = method;
5883 class = this->vtable->klass;
5884 mono_stats.delegate_creations++;
5886 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5888 method = mono_marshal_get_remoting_invoke (method);
5889 delegate->method_ptr = mono_compile_method (method);
5890 MONO_OBJECT_SETREF (delegate, target, target);
5891 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5892 method = mono_marshal_get_unbox_wrapper (method);
5893 delegate->method_ptr = mono_compile_method (method);
5894 MONO_OBJECT_SETREF (delegate, target, target);
5896 delegate->method_ptr = addr;
5897 MONO_OBJECT_SETREF (delegate, target, target);
5900 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5904 * mono_delegate_ctor:
5905 * @this: pointer to an uninitialized delegate object
5906 * @target: target object
5907 * @addr: pointer to native code
5909 * This is used to initialize a delegate.
5912 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5914 MonoDomain *domain = mono_domain_get ();
5916 MonoMethod *method = NULL;
5920 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5921 method = ji->method;
5922 g_assert (!method->klass->generic_container);
5925 mono_delegate_ctor_with_method (this, target, addr, method);
5929 * mono_method_call_message_new:
5930 * @method: method to encapsulate
5931 * @params: parameters to the method
5932 * @invoke: optional, delegate invoke.
5933 * @cb: async callback delegate.
5934 * @state: state passed to the async callback.
5936 * Translates arguments pointers into a MonoMethodMessage.
5939 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5940 MonoDelegate **cb, MonoObject **state)
5942 MonoDomain *domain = mono_domain_get ();
5943 MonoMethodSignature *sig = mono_method_signature (method);
5944 MonoMethodMessage *msg;
5947 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5950 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5951 count = sig->param_count - 2;
5953 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5954 count = sig->param_count;
5957 for (i = 0; i < count; i++) {
5962 if (sig->params [i]->byref)
5963 vpos = *((gpointer *)params [i]);
5967 type = sig->params [i]->type;
5968 class = mono_class_from_mono_type (sig->params [i]);
5970 if (class->valuetype)
5971 arg = mono_value_box (domain, class, vpos);
5973 arg = *((MonoObject **)vpos);
5975 mono_array_setref (msg->args, i, arg);
5978 if (cb != NULL && state != NULL) {
5979 *cb = *((MonoDelegate **)params [i]);
5981 *state = *((MonoObject **)params [i]);
5988 * mono_method_return_message_restore:
5990 * Restore results from message based processing back to arguments pointers
5993 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5995 MonoMethodSignature *sig = mono_method_signature (method);
5996 int i, j, type, size, out_len;
5998 if (out_args == NULL)
6000 out_len = mono_array_length (out_args);
6004 for (i = 0, j = 0; i < sig->param_count; i++) {
6005 MonoType *pt = sig->params [i];
6010 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6012 arg = mono_array_get (out_args, gpointer, j);
6015 g_assert (type != MONO_TYPE_VOID);
6017 if (MONO_TYPE_IS_REFERENCE (pt)) {
6018 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6021 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6022 size = mono_class_value_size (class, NULL);
6023 if (class->has_references)
6024 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6026 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6028 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6029 memset (*((gpointer *)params [i]), 0, size);
6039 * mono_load_remote_field:
6040 * @this: pointer to an object
6041 * @klass: klass of the object containing @field
6042 * @field: the field to load
6043 * @res: a storage to store the result
6045 * This method is called by the runtime on attempts to load fields of
6046 * transparent proxy objects. @this points to such TP, @klass is the class of
6047 * the object containing @field. @res is a storage location which can be
6048 * used to store the result.
6050 * Returns: an address pointing to the value of field.
6053 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6055 static MonoMethod *getter = NULL;
6056 MonoDomain *domain = mono_domain_get ();
6057 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6058 MonoClass *field_class;
6059 MonoMethodMessage *msg;
6060 MonoArray *out_args;
6064 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6065 g_assert (res != NULL);
6067 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6068 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6073 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6077 field_class = mono_class_from_mono_type (field->type);
6079 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6080 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6081 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6083 full_name = mono_type_get_full_name (klass);
6084 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6085 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6088 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6090 if (exc) mono_raise_exception ((MonoException *)exc);
6092 if (mono_array_length (out_args) == 0)
6095 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6097 if (field_class->valuetype) {
6098 return ((char *)*res) + sizeof (MonoObject);
6104 * mono_load_remote_field_new:
6109 * Missing documentation.
6112 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6114 static MonoMethod *getter = NULL;
6115 MonoDomain *domain = mono_domain_get ();
6116 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6117 MonoClass *field_class;
6118 MonoMethodMessage *msg;
6119 MonoArray *out_args;
6120 MonoObject *exc, *res;
6123 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6125 field_class = mono_class_from_mono_type (field->type);
6127 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6129 if (field_class->valuetype) {
6130 res = mono_object_new (domain, field_class);
6131 val = ((gchar *) res) + sizeof (MonoObject);
6135 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6140 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6144 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6145 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6147 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6149 full_name = mono_type_get_full_name (klass);
6150 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6151 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6154 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6156 if (exc) mono_raise_exception ((MonoException *)exc);
6158 if (mono_array_length (out_args) == 0)
6161 res = mono_array_get (out_args, MonoObject *, 0);
6167 * mono_store_remote_field:
6168 * @this: pointer to an object
6169 * @klass: klass of the object containing @field
6170 * @field: the field to load
6171 * @val: the value/object to store
6173 * This method is called by the runtime on attempts to store fields of
6174 * transparent proxy objects. @this points to such TP, @klass is the class of
6175 * the object containing @field. @val is the new value to store in @field.
6178 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6180 static MonoMethod *setter = NULL;
6181 MonoDomain *domain = mono_domain_get ();
6182 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6183 MonoClass *field_class;
6184 MonoMethodMessage *msg;
6185 MonoArray *out_args;
6190 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6192 field_class = mono_class_from_mono_type (field->type);
6194 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6195 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6196 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6201 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6205 if (field_class->valuetype)
6206 arg = mono_value_box (domain, field_class, val);
6208 arg = *((MonoObject **)val);
6211 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6212 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6214 full_name = mono_type_get_full_name (klass);
6215 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6216 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6217 mono_array_setref (msg->args, 2, arg);
6220 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6222 if (exc) mono_raise_exception ((MonoException *)exc);
6226 * mono_store_remote_field_new:
6232 * Missing documentation
6235 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6237 static MonoMethod *setter = NULL;
6238 MonoDomain *domain = mono_domain_get ();
6239 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6240 MonoClass *field_class;
6241 MonoMethodMessage *msg;
6242 MonoArray *out_args;
6246 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6248 field_class = mono_class_from_mono_type (field->type);
6250 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6251 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6252 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6257 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6261 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6262 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6264 full_name = mono_type_get_full_name (klass);
6265 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6266 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6267 mono_array_setref (msg->args, 2, arg);
6270 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6272 if (exc) mono_raise_exception ((MonoException *)exc);
6276 * mono_create_ftnptr:
6278 * Given a function address, create a function descriptor for it.
6279 * This is only needed on some platforms.
6282 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6284 return callbacks.create_ftnptr (domain, addr);
6288 * mono_get_addr_from_ftnptr:
6290 * Given a pointer to a function descriptor, return the function address.
6291 * This is only needed on some platforms.
6294 mono_get_addr_from_ftnptr (gpointer descr)
6296 return callbacks.get_addr_from_ftnptr (descr);
6300 * mono_string_chars:
6303 * Returns a pointer to the UCS16 characters stored in the MonoString
6306 mono_string_chars (MonoString *s)
6312 * mono_string_length:
6315 * Returns the lenght in characters of the string
6318 mono_string_length (MonoString *s)
6324 * mono_array_length:
6325 * @array: a MonoArray*
6327 * Returns the total number of elements in the array. This works for
6328 * both vectors and multidimensional arrays.
6331 mono_array_length (MonoArray *array)
6333 return array->max_length;
6337 * mono_array_addr_with_size:
6338 * @array: a MonoArray*
6339 * @size: size of the array elements
6340 * @idx: index into the array
6342 * Returns the address of the @idx element in the array.
6345 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6347 return ((char*)(array)->vector) + size * idx;