2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
83 free_main_args (void);
85 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
86 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
87 static CRITICAL_SECTION ldstr_section;
89 static gboolean profile_allocs = TRUE;
92 mono_runtime_object_init (MonoObject *this)
94 MonoMethod *method = NULL;
95 MonoClass *klass = this->vtable->klass;
97 method = mono_class_get_method_from_name (klass, ".ctor", 0);
100 if (method->klass->valuetype)
101 this = mono_object_unbox (this);
102 mono_runtime_invoke (method, this, NULL, NULL);
105 /* The pseudo algorithm for type initialization from the spec
106 Note it doesn't say anything about domains - only threads.
108 2. If the type is initialized you are done.
109 2.1. If the type is not yet initialized, try to take an
111 2.2. If successful, record this thread as responsible for
112 initializing the type and proceed to step 2.3.
113 2.2.1. If not, see whether this thread or any thread
114 waiting for this thread to complete already holds the lock.
115 2.2.2. If so, return since blocking would create a deadlock. This thread
116 will now see an incompletely initialized state for the type,
117 but no deadlock will arise.
118 2.2.3 If not, block until the type is initialized then return.
119 2.3 Initialize the parent type and then all interfaces implemented
121 2.4 Execute the type initialization code for this type.
122 2.5 Mark the type as initialized, release the initialization lock,
123 awaken any threads waiting for this type to be initialized,
130 guint32 initializing_tid;
131 guint32 waiting_count;
133 CRITICAL_SECTION initialization_section;
134 } TypeInitializationLock;
136 /* for locking access to type_initialization_hash and blocked_thread_hash */
137 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
138 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
139 static CRITICAL_SECTION type_initialization_section;
141 /* from vtable to lock */
142 static GHashTable *type_initialization_hash;
144 /* from thread id to thread id being waited on */
145 static GHashTable *blocked_thread_hash;
148 static MonoThread *main_thread;
150 /* Functions supplied by the runtime */
151 static MonoRuntimeCallbacks callbacks;
154 * mono_thread_set_main:
155 * @thread: thread to set as the main thread
157 * This function can be used to instruct the runtime to treat @thread
158 * as the main thread, ie, the thread that would normally execute the Main()
159 * method. This basically means that at the end of @thread, the runtime will
160 * wait for the existing foreground threads to quit and other such details.
163 mono_thread_set_main (MonoThread *thread)
165 main_thread = thread;
169 mono_thread_get_main (void)
175 mono_type_initialization_init (void)
177 InitializeCriticalSection (&type_initialization_section);
178 type_initialization_hash = g_hash_table_new (NULL, NULL);
179 blocked_thread_hash = g_hash_table_new (NULL, NULL);
180 InitializeCriticalSection (&ldstr_section);
184 mono_type_initialization_cleanup (void)
187 /* This is causing race conditions with
188 * mono_release_type_locks
190 DeleteCriticalSection (&type_initialization_section);
191 g_hash_table_destroy (type_initialization_hash);
192 type_initialization_hash = NULL;
194 DeleteCriticalSection (&ldstr_section);
195 g_hash_table_destroy (blocked_thread_hash);
196 blocked_thread_hash = NULL;
202 * get_type_init_exception_for_vtable:
204 * Return the stored type initialization exception for VTABLE.
206 static MonoException*
207 get_type_init_exception_for_vtable (MonoVTable *vtable)
209 MonoDomain *domain = vtable->domain;
210 MonoClass *klass = vtable->klass;
214 g_assert (vtable->init_failed);
217 * If the initializing thread was rudely aborted, the exception is not stored
221 mono_domain_lock (domain);
222 if (domain->type_init_exception_hash)
223 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
224 mono_domain_unlock (domain);
227 if (klass->name_space && *klass->name_space)
228 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
230 full_name = g_strdup (klass->name);
231 ex = mono_get_exception_type_initialization (full_name, NULL);
238 * mono_runtime_class_init:
239 * @vtable: vtable that needs to be initialized
241 * This routine calls the class constructor for @vtable.
244 mono_runtime_class_init (MonoVTable *vtable)
246 mono_runtime_class_init_full (vtable, TRUE);
250 * mono_runtime_class_init_full:
251 * @vtable that neeeds to be initialized
252 * @raise_exception is TRUE, exceptions are raised intead of returned
256 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
259 MonoException *exc_to_throw;
260 MonoMethod *method = NULL;
266 if (vtable->initialized)
270 klass = vtable->klass;
272 if (!klass->image->checked_module_cctor) {
273 mono_image_check_for_module_cctor (klass->image);
274 if (klass->image->has_module_cctor) {
275 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
276 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
279 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
284 method = mono_class_get_cctor (klass);
287 MonoDomain *domain = vtable->domain;
288 TypeInitializationLock *lock;
289 guint32 tid = GetCurrentThreadId();
290 int do_initialization = 0;
291 MonoDomain *last_domain = NULL;
293 mono_type_initialization_lock ();
294 /* double check... */
295 if (vtable->initialized) {
296 mono_type_initialization_unlock ();
299 if (vtable->init_failed) {
300 mono_type_initialization_unlock ();
302 /* The type initialization already failed once, rethrow the same exception */
304 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
305 return get_type_init_exception_for_vtable (vtable);
307 lock = g_hash_table_lookup (type_initialization_hash, vtable);
309 /* This thread will get to do the initialization */
310 if (mono_domain_get () != domain) {
311 /* Transfer into the target domain */
312 last_domain = mono_domain_get ();
313 if (!mono_domain_set (domain, FALSE)) {
314 vtable->initialized = 1;
315 mono_type_initialization_unlock ();
317 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
318 return mono_get_exception_appdomain_unloaded ();
321 lock = g_malloc (sizeof(TypeInitializationLock));
322 InitializeCriticalSection (&lock->initialization_section);
323 lock->initializing_tid = tid;
324 lock->waiting_count = 1;
326 /* grab the vtable lock while this thread still owns type_initialization_section */
327 EnterCriticalSection (&lock->initialization_section);
328 g_hash_table_insert (type_initialization_hash, vtable, lock);
329 do_initialization = 1;
332 TypeInitializationLock *pending_lock;
334 if (lock->initializing_tid == tid || lock->done) {
335 mono_type_initialization_unlock ();
338 /* see if the thread doing the initialization is already blocked on this thread */
339 blocked = GUINT_TO_POINTER (lock->initializing_tid);
340 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
341 if (pending_lock->initializing_tid == tid) {
342 if (!pending_lock->done) {
343 mono_type_initialization_unlock ();
346 /* the thread doing the initialization is blocked on this thread,
347 but on a lock that has already been freed. It just hasn't got
352 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
354 ++lock->waiting_count;
355 /* record the fact that we are waiting on the initializing thread */
356 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
358 mono_type_initialization_unlock ();
360 if (do_initialization) {
361 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
363 /* If the initialization failed, mark the class as unusable. */
364 /* Avoid infinite loops */
366 (klass->image == mono_defaults.corlib &&
367 !strcmp (klass->name_space, "System") &&
368 !strcmp (klass->name, "TypeInitializationException")))) {
369 vtable->init_failed = 1;
371 if (klass->name_space && *klass->name_space)
372 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
374 full_name = g_strdup (klass->name);
375 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
379 * Store the exception object so it could be thrown on subsequent
382 mono_domain_lock (domain);
383 if (!domain->type_init_exception_hash)
384 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
385 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
386 mono_domain_unlock (domain);
390 mono_domain_set (last_domain, TRUE);
392 LeaveCriticalSection (&lock->initialization_section);
394 /* this just blocks until the initializing thread is done */
395 EnterCriticalSection (&lock->initialization_section);
396 LeaveCriticalSection (&lock->initialization_section);
399 mono_type_initialization_lock ();
400 if (lock->initializing_tid != tid)
401 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
402 --lock->waiting_count;
403 if (lock->waiting_count == 0) {
404 DeleteCriticalSection (&lock->initialization_section);
405 g_hash_table_remove (type_initialization_hash, vtable);
408 if (!vtable->init_failed)
409 vtable->initialized = 1;
410 mono_type_initialization_unlock ();
412 if (vtable->init_failed) {
413 /* Either we were the initializing thread or we waited for the initialization */
415 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
416 return get_type_init_exception_for_vtable (vtable);
419 vtable->initialized = 1;
426 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
428 MonoVTable *vtable = (MonoVTable*)key;
430 TypeInitializationLock *lock = (TypeInitializationLock*) value;
431 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
434 * Have to set this since it cannot be set by the normal code in
435 * mono_runtime_class_init (). In this case, the exception object is not stored,
436 * and get_type_init_exception_for_class () needs to be aware of this.
438 vtable->init_failed = 1;
439 LeaveCriticalSection (&lock->initialization_section);
440 --lock->waiting_count;
441 if (lock->waiting_count == 0) {
442 DeleteCriticalSection (&lock->initialization_section);
451 mono_release_type_locks (MonoInternalThread *thread)
453 mono_type_initialization_lock ();
454 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
455 mono_type_initialization_unlock ();
459 default_trampoline (MonoMethod *method)
465 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
467 g_assert_not_reached ();
473 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
475 g_error ("remoting not installed");
480 default_delegate_trampoline (MonoClass *klass)
482 g_assert_not_reached ();
486 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
487 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
488 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
489 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
490 static MonoImtThunkBuilder imt_thunk_builder = NULL;
491 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
492 #if (MONO_IMT_SIZE > 32)
493 #error "MONO_IMT_SIZE cannot be larger than 32"
497 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
499 memcpy (&callbacks, cbs, sizeof (*cbs));
502 MonoRuntimeCallbacks*
503 mono_get_runtime_callbacks (void)
509 mono_install_trampoline (MonoTrampoline func)
511 arch_create_jit_trampoline = func? func: default_trampoline;
515 mono_install_jump_trampoline (MonoJumpTrampoline func)
517 arch_create_jump_trampoline = func? func: default_jump_trampoline;
521 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
523 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
527 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
529 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
533 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
534 imt_thunk_builder = func;
537 static MonoCompileFunc default_mono_compile_method = NULL;
540 * mono_install_compile_method:
541 * @func: function to install
543 * This is a VM internal routine
546 mono_install_compile_method (MonoCompileFunc func)
548 default_mono_compile_method = func;
552 * mono_compile_method:
553 * @method: The method to compile.
555 * This JIT-compiles the method, and returns the pointer to the native code
559 mono_compile_method (MonoMethod *method)
561 if (!default_mono_compile_method) {
562 g_error ("compile method called on uninitialized runtime");
565 return default_mono_compile_method (method);
569 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
571 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
575 mono_runtime_create_delegate_trampoline (MonoClass *klass)
577 return arch_create_delegate_trampoline (klass);
580 static MonoFreeMethodFunc default_mono_free_method = NULL;
583 * mono_install_free_method:
584 * @func: pointer to the MonoFreeMethodFunc used to release a method
586 * This is an internal VM routine, it is used for the engines to
587 * register a handler to release the resources associated with a method.
589 * Methods are freed when no more references to the delegate that holds
593 mono_install_free_method (MonoFreeMethodFunc func)
595 default_mono_free_method = func;
599 * mono_runtime_free_method:
600 * @domain; domain where the method is hosted
601 * @method: method to release
603 * This routine is invoked to free the resources associated with
604 * a method that has been JIT compiled. This is used to discard
605 * methods that were used only temporarily (for example, used in marshalling)
609 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
611 if (default_mono_free_method != NULL)
612 default_mono_free_method (domain, method);
614 mono_method_clear_object (domain, method);
616 mono_free_method (method);
620 * The vtables in the root appdomain are assumed to be reachable by other
621 * roots, and we don't use typed allocation in the other domains.
624 /* The sync block is no longer a GC pointer */
625 #define GC_HEADER_BITMAP (0)
627 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
630 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
632 MonoClassField *field;
638 max_size = mono_class_data_size (class) / sizeof (gpointer);
640 max_size = class->instance_size / sizeof (gpointer);
641 if (max_size > size) {
642 g_assert (offset <= 0);
643 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
648 /*An Ephemeron cannot be marked by sgen*/
649 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
651 memset (bitmap, 0, size / 8);
656 for (p = class; p != NULL; p = p->parent) {
657 gpointer iter = NULL;
658 while ((field = mono_class_get_fields (p, &iter))) {
662 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
664 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
667 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
670 /* FIXME: should not happen, flag as type load error */
671 if (field->type->byref)
674 if (static_fields && field->offset == -1)
678 pos = field->offset / sizeof (gpointer);
681 type = mono_type_get_underlying_type (field->type);
682 switch (type->type) {
685 case MONO_TYPE_FNPTR:
687 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
692 if (class->image != mono_defaults.corlib)
695 case MONO_TYPE_STRING:
696 case MONO_TYPE_SZARRAY:
697 case MONO_TYPE_CLASS:
698 case MONO_TYPE_OBJECT:
699 case MONO_TYPE_ARRAY:
700 g_assert ((field->offset % sizeof(gpointer)) == 0);
702 g_assert (pos < size || pos <= max_size);
703 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
704 *max_set = MAX (*max_set, pos);
706 case MONO_TYPE_GENERICINST:
707 if (!mono_type_generic_inst_is_valuetype (type)) {
708 g_assert ((field->offset % sizeof(gpointer)) == 0);
710 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
711 *max_set = MAX (*max_set, pos);
716 case MONO_TYPE_VALUETYPE: {
717 MonoClass *fclass = mono_class_from_mono_type (field->type);
718 if (fclass->has_references) {
719 /* remove the object header */
720 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
734 case MONO_TYPE_BOOLEAN:
738 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
750 * similar to the above, but sets the bits in the bitmap for any non-ref field
751 * and ignores static fields
754 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
756 MonoClassField *field;
761 max_size = class->instance_size / sizeof (gpointer);
762 if (max_size >= size) {
763 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
766 for (p = class; p != NULL; p = p->parent) {
767 gpointer iter = NULL;
768 while ((field = mono_class_get_fields (p, &iter))) {
771 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
773 /* FIXME: should not happen, flag as type load error */
774 if (field->type->byref)
777 pos = field->offset / sizeof (gpointer);
780 type = mono_type_get_underlying_type (field->type);
781 switch (type->type) {
782 #if SIZEOF_VOID_P == 8
786 case MONO_TYPE_FNPTR:
791 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
792 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
793 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
796 #if SIZEOF_VOID_P == 4
800 case MONO_TYPE_FNPTR:
805 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
806 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
807 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
813 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
814 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
815 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
818 case MONO_TYPE_BOOLEAN:
821 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
823 case MONO_TYPE_STRING:
824 case MONO_TYPE_SZARRAY:
825 case MONO_TYPE_CLASS:
826 case MONO_TYPE_OBJECT:
827 case MONO_TYPE_ARRAY:
829 case MONO_TYPE_GENERICINST:
830 if (!mono_type_generic_inst_is_valuetype (type)) {
835 case MONO_TYPE_VALUETYPE: {
836 MonoClass *fclass = mono_class_from_mono_type (field->type);
837 /* remove the object header */
838 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
842 g_assert_not_reached ();
851 * mono_class_insecure_overlapping:
852 * check if a class with explicit layout has references and non-references
853 * fields overlapping.
855 * Returns: TRUE if it is insecure to load the type.
858 mono_class_insecure_overlapping (MonoClass *klass)
862 gsize default_bitmap [4] = {0};
864 gsize default_nrbitmap [4] = {0};
865 int i, insecure = FALSE;
868 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
869 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
871 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
872 int idx = i % (sizeof (bitmap [0]) * 8);
873 if (bitmap [idx] & nrbitmap [idx]) {
878 if (bitmap != default_bitmap)
880 if (nrbitmap != default_nrbitmap)
883 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
891 mono_string_alloc (int length)
893 return mono_string_new_size (mono_domain_get (), length);
897 mono_class_compute_gc_descriptor (MonoClass *class)
901 gsize default_bitmap [4] = {0};
902 static gboolean gcj_inited = FALSE;
907 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
908 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
909 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
910 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
912 #ifdef HAVE_GC_GCJ_MALLOC
914 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
918 #ifdef GC_REDIRECT_TO_LOCAL
919 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
920 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
922 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
923 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
928 mono_loader_unlock ();
932 mono_class_init (class);
934 if (class->gc_descr_inited)
937 class->gc_descr_inited = TRUE;
938 class->gc_descr = GC_NO_DESCRIPTOR;
940 bitmap = default_bitmap;
941 if (class == mono_defaults.string_class) {
942 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
943 } else if (class->rank) {
944 mono_class_compute_gc_descriptor (class->element_class);
945 if (!class->element_class->valuetype) {
947 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
948 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
949 class->name_space, class->name);*/
951 /* remove the object header */
952 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
953 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
954 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
955 class->name_space, class->name);*/
956 if (bitmap != default_bitmap)
960 /*static int count = 0;
963 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
964 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
966 if (class->gc_descr == GC_NO_DESCRIPTOR)
967 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
969 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
970 if (bitmap != default_bitmap)
976 * field_is_special_static:
977 * @fklass: The MonoClass to look up.
978 * @field: The MonoClassField describing the field.
980 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
981 * SPECIAL_STATIC_NONE otherwise.
984 field_is_special_static (MonoClass *fklass, MonoClassField *field)
986 MonoCustomAttrInfo *ainfo;
988 ainfo = mono_custom_attrs_from_field (fklass, field);
991 for (i = 0; i < ainfo->num_attrs; ++i) {
992 MonoClass *klass = ainfo->attrs [i].ctor->klass;
993 if (klass->image == mono_defaults.corlib) {
994 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
995 mono_custom_attrs_free (ainfo);
996 return SPECIAL_STATIC_THREAD;
998 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
999 mono_custom_attrs_free (ainfo);
1000 return SPECIAL_STATIC_CONTEXT;
1004 mono_custom_attrs_free (ainfo);
1005 return SPECIAL_STATIC_NONE;
1008 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1009 #define mix(a,b,c) { \
1010 a -= c; a ^= rot(c, 4); c += b; \
1011 b -= a; b ^= rot(a, 6); a += c; \
1012 c -= b; c ^= rot(b, 8); b += a; \
1013 a -= c; a ^= rot(c,16); c += b; \
1014 b -= a; b ^= rot(a,19); a += c; \
1015 c -= b; c ^= rot(b, 4); b += a; \
1017 #define final(a,b,c) { \
1018 c ^= b; c -= rot(b,14); \
1019 a ^= c; a -= rot(c,11); \
1020 b ^= a; b -= rot(a,25); \
1021 c ^= b; c -= rot(b,16); \
1022 a ^= c; a -= rot(c,4); \
1023 b ^= a; b -= rot(a,14); \
1024 c ^= b; c -= rot(b,24); \
1028 * mono_method_get_imt_slot:
1030 * The IMT slot is embedded into AOTed code, so this must return the same value
1031 * for the same method across all executions. This means:
1032 * - pointers shouldn't be used as hash values.
1033 * - mono_metadata_str_hash () should be used for hashing strings.
1036 mono_method_get_imt_slot (MonoMethod *method)
1038 MonoMethodSignature *sig;
1040 guint32 *hashes_start, *hashes;
1044 /* This can be used to stress tests the collision code */
1048 * We do this to simplify generic sharing. It will hurt
1049 * performance in cases where a class implements two different
1050 * instantiations of the same generic interface.
1051 * The code in build_imt_slots () depends on this.
1053 if (method->is_inflated)
1054 method = ((MonoMethodInflated*)method)->declaring;
1056 sig = mono_method_signature (method);
1057 hashes_count = sig->param_count + 4;
1058 hashes_start = malloc (hashes_count * sizeof (guint32));
1059 hashes = hashes_start;
1061 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1062 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1063 method->klass->name_space, method->klass->name, method->name);
1064 g_assert_not_reached ();
1067 /* Initialize hashes */
1068 hashes [0] = mono_metadata_str_hash (method->klass->name);
1069 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1070 hashes [2] = mono_metadata_str_hash (method->name);
1071 hashes [3] = mono_metadata_type_hash (sig->ret);
1072 for (i = 0; i < sig->param_count; i++) {
1073 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1076 /* Setup internal state */
1077 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1079 /* Handle most of the hashes */
1080 while (hashes_count > 3) {
1089 /* Handle the last 3 hashes (all the case statements fall through) */
1090 switch (hashes_count) {
1091 case 3 : c += hashes [2];
1092 case 2 : b += hashes [1];
1093 case 1 : a += hashes [0];
1095 case 0: /* nothing left to add */
1099 free (hashes_start);
1100 /* Report the result */
1101 return c % MONO_IMT_SIZE;
1110 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1111 guint32 imt_slot = mono_method_get_imt_slot (method);
1112 MonoImtBuilderEntry *entry;
1114 if (slot_num >= 0 && imt_slot != slot_num) {
1115 /* we build just a single imt slot and this is not it */
1119 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1120 entry->key = method;
1121 entry->value.vtable_slot = vtable_slot;
1122 entry->next = imt_builder [imt_slot];
1123 if (imt_builder [imt_slot] != NULL) {
1124 entry->children = imt_builder [imt_slot]->children + 1;
1125 if (entry->children == 1) {
1126 mono_stats.imt_slots_with_collisions++;
1127 *imt_collisions_bitmap |= (1 << imt_slot);
1130 entry->children = 0;
1131 mono_stats.imt_used_slots++;
1133 imt_builder [imt_slot] = entry;
1136 char *method_name = mono_method_full_name (method, TRUE);
1137 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1138 method, method_name, imt_slot, vtable_slot, entry->children);
1139 g_free (method_name);
1146 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1148 MonoMethod *method = e->key;
1149 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1153 method->klass->name_space,
1154 method->klass->name,
1157 printf (" * %s: NULL\n", message);
1163 compare_imt_builder_entries (const void *p1, const void *p2) {
1164 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1165 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1167 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1171 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1173 int count = end - start;
1174 int chunk_start = out_array->len;
1177 for (i = start; i < end; ++i) {
1178 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1179 item->key = sorted_array [i]->key;
1180 item->value = sorted_array [i]->value;
1181 item->has_target_code = sorted_array [i]->has_target_code;
1182 item->is_equals = TRUE;
1184 item->check_target_idx = out_array->len + 1;
1186 item->check_target_idx = 0;
1187 g_ptr_array_add (out_array, item);
1190 int middle = start + count / 2;
1191 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1193 item->key = sorted_array [middle]->key;
1194 item->is_equals = FALSE;
1195 g_ptr_array_add (out_array, item);
1196 imt_emit_ir (sorted_array, start, middle, out_array);
1197 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1203 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1204 int number_of_entries = entries->children + 1;
1205 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1206 GPtrArray *result = g_ptr_array_new ();
1207 MonoImtBuilderEntry *current_entry;
1210 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1211 sorted_array [i] = current_entry;
1213 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1215 /*for (i = 0; i < number_of_entries; i++) {
1216 print_imt_entry (" sorted array:", sorted_array [i], i);
1219 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1221 free (sorted_array);
1226 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1228 if (imt_builder_entry != NULL) {
1229 if (imt_builder_entry->children == 0 && !fail_tramp) {
1230 /* No collision, return the vtable slot contents */
1231 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1233 /* Collision, build the thunk */
1234 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1237 result = imt_thunk_builder (vtable, domain,
1238 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1239 for (i = 0; i < imt_ir->len; ++i)
1240 g_free (g_ptr_array_index (imt_ir, i));
1241 g_ptr_array_free (imt_ir, TRUE);
1253 static MonoImtBuilderEntry*
1254 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1257 * LOCKING: requires the loader and domain locks.
1261 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1265 guint32 imt_collisions_bitmap = 0;
1266 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1267 int method_count = 0;
1268 gboolean record_method_count_for_max_collisions = FALSE;
1269 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1272 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1274 for (i = 0; i < klass->interface_offsets_count; ++i) {
1275 MonoClass *iface = klass->interfaces_packed [i];
1276 int interface_offset = klass->interface_offsets_packed [i];
1277 int method_slot_in_interface, vt_slot;
1279 if (mono_class_has_variant_generic_params (iface))
1280 has_variant_iface = TRUE;
1282 vt_slot = interface_offset;
1283 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1286 if (slot_num >= 0 && iface->is_inflated) {
1288 * The imt slot of the method is the same as for its declaring method,
1289 * see the comment in mono_method_get_imt_slot (), so we can
1290 * avoid inflating methods which will be discarded by
1291 * add_imt_builder_entry anyway.
1293 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1294 if (mono_method_get_imt_slot (method) != slot_num) {
1299 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1300 if (method->is_generic) {
1301 has_generic_virtual = TRUE;
1306 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1307 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1312 if (extra_interfaces) {
1313 int interface_offset = klass->vtable_size;
1315 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1316 MonoClass* iface = list_item->data;
1317 int method_slot_in_interface;
1318 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1319 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1320 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1322 interface_offset += iface->method.count;
1325 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1326 /* overwrite the imt slot only if we're building all the entries or if
1327 * we're building this specific one
1329 if (slot_num < 0 || i == slot_num) {
1330 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1333 if (imt_builder [i]) {
1334 MonoImtBuilderEntry *entry;
1336 /* Link entries with imt_builder [i] */
1337 for (entry = entries; entry->next; entry = entry->next) {
1339 MonoMethod *method = (MonoMethod*)entry->key;
1340 char *method_name = mono_method_full_name (method, TRUE);
1341 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1342 g_free (method_name);
1345 entry->next = imt_builder [i];
1346 entries->children += imt_builder [i]->children + 1;
1348 imt_builder [i] = entries;
1351 if (has_generic_virtual || has_variant_iface) {
1353 * There might be collisions later when the the thunk is expanded.
1355 imt_collisions_bitmap |= (1 << i);
1358 * The IMT thunk might be called with an instance of one of the
1359 * generic virtual methods, so has to fallback to the IMT trampoline.
1361 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1363 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1366 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1370 if (imt_builder [i] != NULL) {
1371 int methods_in_slot = imt_builder [i]->children + 1;
1372 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1373 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1374 record_method_count_for_max_collisions = TRUE;
1376 method_count += methods_in_slot;
1380 mono_stats.imt_number_of_methods += method_count;
1381 if (record_method_count_for_max_collisions) {
1382 mono_stats.imt_method_count_when_max_collisions = method_count;
1385 for (i = 0; i < MONO_IMT_SIZE; i++) {
1386 MonoImtBuilderEntry* entry = imt_builder [i];
1387 while (entry != NULL) {
1388 MonoImtBuilderEntry* next = entry->next;
1394 /* we OR the bitmap since we may build just a single imt slot at a time */
1395 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1399 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1400 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1404 * mono_vtable_build_imt_slot:
1405 * @vtable: virtual object table struct
1406 * @imt_slot: slot in the IMT table
1408 * Fill the given @imt_slot in the IMT table of @vtable with
1409 * a trampoline or a thunk for the case of collisions.
1410 * This is part of the internal mono API.
1412 * LOCKING: Take the domain lock.
1415 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1417 gpointer *imt = (gpointer*)vtable;
1418 imt -= MONO_IMT_SIZE;
1419 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1421 /* no support for extra interfaces: the proxy objects will need
1422 * to build the complete IMT
1423 * Update and heck needs to ahppen inside the proper domain lock, as all
1424 * the changes made to a MonoVTable.
1426 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1427 mono_domain_lock (vtable->domain);
1428 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1429 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1430 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1431 mono_domain_unlock (vtable->domain);
1432 mono_loader_unlock ();
1437 * The first two free list entries both belong to the wait list: The
1438 * first entry is the pointer to the head of the list and the second
1439 * entry points to the last element. That way appending and removing
1440 * the first element are both O(1) operations.
1442 #ifdef MONO_SMALL_CONFIG
1443 #define NUM_FREE_LISTS 6
1445 #define NUM_FREE_LISTS 12
1447 #define FIRST_FREE_LIST_SIZE 64
1448 #define MAX_WAIT_LENGTH 50
1449 #define THUNK_THRESHOLD 10
1452 * LOCKING: The domain lock must be held.
1455 init_thunk_free_lists (MonoDomain *domain)
1457 if (domain->thunk_free_lists)
1459 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1463 list_index_for_size (int item_size)
1466 int size = FIRST_FREE_LIST_SIZE;
1468 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1477 * mono_method_alloc_generic_virtual_thunk:
1479 * @size: size in bytes
1481 * Allocs size bytes to be used for the code of a generic virtual
1482 * thunk. It's either allocated from the domain's code manager or
1483 * reused from a previously invalidated piece.
1485 * LOCKING: The domain lock must be held.
1488 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1490 static gboolean inited = FALSE;
1491 static int generic_virtual_thunks_size = 0;
1495 MonoThunkFreeList **l;
1497 init_thunk_free_lists (domain);
1499 size += sizeof (guint32);
1500 if (size < sizeof (MonoThunkFreeList))
1501 size = sizeof (MonoThunkFreeList);
1503 i = list_index_for_size (size);
1504 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1505 if ((*l)->size >= size) {
1506 MonoThunkFreeList *item = *l;
1508 return ((guint32*)item) + 1;
1512 /* no suitable item found - search lists of larger sizes */
1513 while (++i < NUM_FREE_LISTS) {
1514 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1517 g_assert (item->size > size);
1518 domain->thunk_free_lists [i] = item->next;
1519 return ((guint32*)item) + 1;
1522 /* still nothing found - allocate it */
1524 mono_counters_register ("Generic virtual thunk bytes",
1525 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1528 generic_virtual_thunks_size += size;
1530 p = mono_domain_code_reserve (domain, size);
1537 * LOCKING: The domain lock must be held.
1540 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1543 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1545 init_thunk_free_lists (domain);
1547 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1548 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1549 int length = item->length;
1552 /* unlink the first item from the wait list */
1553 domain->thunk_free_lists [0] = item->next;
1554 domain->thunk_free_lists [0]->length = length - 1;
1556 i = list_index_for_size (item->size);
1558 /* put it in the free list */
1559 item->next = domain->thunk_free_lists [i];
1560 domain->thunk_free_lists [i] = item;
1564 if (domain->thunk_free_lists [1]) {
1565 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1566 domain->thunk_free_lists [0]->length++;
1568 g_assert (!domain->thunk_free_lists [0]);
1570 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1571 domain->thunk_free_lists [0]->length = 1;
1575 typedef struct _GenericVirtualCase {
1579 struct _GenericVirtualCase *next;
1580 } GenericVirtualCase;
1583 * get_generic_virtual_entries:
1585 * Return IMT entries for the generic virtual method instances and
1586 * variant interface methods for vtable slot
1589 static MonoImtBuilderEntry*
1590 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1592 GenericVirtualCase *list;
1593 MonoImtBuilderEntry *entries;
1595 mono_domain_lock (domain);
1596 if (!domain->generic_virtual_cases)
1597 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1599 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1602 for (; list; list = list->next) {
1603 MonoImtBuilderEntry *entry;
1605 if (list->count < THUNK_THRESHOLD)
1608 entry = g_new0 (MonoImtBuilderEntry, 1);
1609 entry->key = list->method;
1610 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1611 entry->has_target_code = 1;
1613 entry->children = entries->children + 1;
1614 entry->next = entries;
1618 mono_domain_unlock (domain);
1620 /* FIXME: Leaking memory ? */
1625 * mono_method_add_generic_virtual_invocation:
1627 * @vtable_slot: pointer to the vtable slot
1628 * @method: the inflated generic virtual method
1629 * @code: the method's code
1631 * Registers a call via unmanaged code to a generic virtual method
1632 * instantiation or variant interface method. If the number of calls reaches a threshold
1633 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1634 * virtual method thunk.
1637 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1638 gpointer *vtable_slot,
1639 MonoMethod *method, gpointer code)
1641 static gboolean inited = FALSE;
1642 static int num_added = 0;
1644 GenericVirtualCase *gvc, *list;
1645 MonoImtBuilderEntry *entries;
1649 mono_domain_lock (domain);
1650 if (!domain->generic_virtual_cases)
1651 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1653 /* Check whether the case was already added */
1654 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1657 if (gvc->method == method)
1662 /* If not found, make a new one */
1664 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1665 gvc->method = method;
1668 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1670 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1673 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1679 if (++gvc->count == THUNK_THRESHOLD) {
1680 gpointer *old_thunk = *vtable_slot;
1681 gpointer vtable_trampoline = NULL;
1682 gpointer imt_trampoline = NULL;
1684 if ((gpointer)vtable_slot < (gpointer)vtable) {
1685 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1686 int imt_slot = MONO_IMT_SIZE + displacement;
1688 /* Force the rebuild of the thunk at the next call */
1689 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1690 *vtable_slot = imt_trampoline;
1692 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1694 entries = get_generic_virtual_entries (domain, vtable_slot);
1696 sorted = imt_sort_slot_entries (entries);
1698 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1702 MonoImtBuilderEntry *next = entries->next;
1707 for (i = 0; i < sorted->len; ++i)
1708 g_free (g_ptr_array_index (sorted, i));
1709 g_ptr_array_free (sorted, TRUE);
1712 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1713 invalidate_generic_virtual_thunk (domain, old_thunk);
1716 mono_domain_unlock (domain);
1719 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1722 * mono_class_vtable:
1723 * @domain: the application domain
1724 * @class: the class to initialize
1726 * VTables are domain specific because we create domain specific code, and
1727 * they contain the domain specific static class data.
1728 * On failure, NULL is returned, and class->exception_type is set.
1731 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1733 return mono_class_vtable_full (domain, class, FALSE);
1737 * mono_class_vtable_full:
1738 * @domain: the application domain
1739 * @class: the class to initialize
1740 * @raise_on_error if an exception should be raised on failure or not
1742 * VTables are domain specific because we create domain specific code, and
1743 * they contain the domain specific static class data.
1746 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1748 MonoClassRuntimeInfo *runtime_info;
1752 if (class->exception_type) {
1754 mono_raise_exception (mono_class_get_exception_for_failure (class));
1758 /* this check can be inlined in jitted code, too */
1759 runtime_info = class->runtime_info;
1760 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1761 return runtime_info->domain_vtables [domain->domain_id];
1762 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1766 * mono_class_try_get_vtable:
1767 * @domain: the application domain
1768 * @class: the class to initialize
1770 * This function tries to get the associated vtable from @class if
1771 * it was already created.
1774 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1776 MonoClassRuntimeInfo *runtime_info;
1780 runtime_info = class->runtime_info;
1781 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1782 return runtime_info->domain_vtables [domain->domain_id];
1787 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1790 MonoClassRuntimeInfo *runtime_info, *old_info;
1791 MonoClassField *field;
1794 int imt_table_bytes = 0;
1795 guint32 vtable_size, class_size;
1798 gpointer *interface_offsets;
1800 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1801 mono_domain_lock (domain);
1802 runtime_info = class->runtime_info;
1803 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1804 mono_domain_unlock (domain);
1805 mono_loader_unlock ();
1806 return runtime_info->domain_vtables [domain->domain_id];
1808 if (!class->inited || class->exception_type) {
1809 if (!mono_class_init (class) || class->exception_type) {
1810 mono_domain_unlock (domain);
1811 mono_loader_unlock ();
1813 mono_raise_exception (mono_class_get_exception_for_failure (class));
1818 /* Array types require that their element type be valid*/
1819 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1820 MonoClass *element_class = class->element_class;
1821 if (!element_class->inited)
1822 mono_class_init (element_class);
1824 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1825 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1826 mono_class_setup_vtable (element_class);
1828 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1829 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1830 if (class->exception_type == MONO_EXCEPTION_NONE)
1831 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1832 mono_domain_unlock (domain);
1833 mono_loader_unlock ();
1835 mono_raise_exception (mono_class_get_exception_for_failure (class));
1841 * For some classes, mono_class_init () already computed class->vtable_size, and
1842 * that is all that is needed because of the vtable trampolines.
1844 if (!class->vtable_size)
1845 mono_class_setup_vtable (class);
1847 if (class->generic_class && !class->vtable)
1848 mono_class_check_vtable_constraints (class, NULL);
1850 if (class->exception_type) {
1851 mono_domain_unlock (domain);
1852 mono_loader_unlock ();
1854 mono_raise_exception (mono_class_get_exception_for_failure (class));
1859 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1860 if (class->interface_offsets_count) {
1861 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1862 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1863 mono_stats.imt_number_of_tables++;
1864 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1867 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1868 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1871 mono_stats.used_class_count++;
1872 mono_stats.class_vtable_size += vtable_size;
1873 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1876 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1878 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1880 vt->rank = class->rank;
1881 vt->domain = domain;
1883 mono_class_compute_gc_descriptor (class);
1885 * We can't use typed allocation in the non-root domains, since the
1886 * collector needs the GC descriptor stored in the vtable even after
1887 * the mempool containing the vtable is destroyed when the domain is
1888 * unloaded. An alternative might be to allocate vtables in the GC
1889 * heap, but this does not seem to work (it leads to crashes inside
1890 * libgc). If that approach is tried, two gc descriptors need to be
1891 * allocated for each class: one for the root domain, and one for all
1892 * other domains. The second descriptor should contain a bit for the
1893 * vtable field in MonoObject, since we can no longer assume the
1894 * vtable is reachable by other roots after the appdomain is unloaded.
1896 #ifdef HAVE_BOEHM_GC
1897 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1898 vt->gc_descr = GC_NO_DESCRIPTOR;
1901 vt->gc_descr = class->gc_descr;
1903 if ((class_size = mono_class_data_size (class))) {
1904 if (class->has_static_refs) {
1905 gpointer statics_gc_descr;
1907 gsize default_bitmap [4] = {0};
1910 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1911 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1912 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1913 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1914 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1915 if (bitmap != default_bitmap)
1918 vt->data = mono_domain_alloc0 (domain, class_size);
1920 mono_stats.class_static_data_size += class_size;
1925 while ((field = mono_class_get_fields (class, &iter))) {
1926 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1928 if (mono_field_is_deleted (field))
1930 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1931 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1932 if (special_static != SPECIAL_STATIC_NONE) {
1933 guint32 size, offset;
1935 gsize default_bitmap [4] = {0};
1939 if (mono_type_is_reference (field->type)) {
1940 default_bitmap [0] = 1;
1942 bitmap = default_bitmap;
1943 } else if (mono_type_is_struct (field->type)) {
1944 fclass = mono_class_from_mono_type (field->type);
1945 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1947 default_bitmap [0] = 0;
1949 bitmap = default_bitmap;
1951 size = mono_type_size (field->type, &align);
1952 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1953 if (!domain->special_static_fields)
1954 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1955 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1956 if (bitmap != default_bitmap)
1959 * This marks the field as special static to speed up the
1960 * checks in mono_field_static_get/set_value ().
1966 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1967 MonoClass *fklass = mono_class_from_mono_type (field->type);
1968 const char *data = mono_field_get_data (field);
1970 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1971 t = (char*)vt->data + field->offset;
1972 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1975 if (fklass->valuetype) {
1976 memcpy (t, data, mono_class_value_size (fklass, NULL));
1978 /* it's a pointer type: add check */
1979 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1986 vt->max_interface_id = class->max_interface_id;
1987 vt->interface_bitmap = class->interface_bitmap;
1989 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1990 // class->name, class->interface_offsets_count);
1992 if (! ARCH_USE_IMT) {
1993 /* initialize interface offsets */
1994 for (i = 0; i < class->interface_offsets_count; ++i) {
1995 int interface_id = class->interfaces_packed [i]->interface_id;
1996 int slot = class->interface_offsets_packed [i];
1997 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2001 /* class_vtable_array keeps an array of created vtables
2003 g_ptr_array_add (domain->class_vtable_array, vt);
2004 /* class->runtime_info is protected by the loader lock, both when
2005 * it it enlarged and when it is stored info.
2008 old_info = class->runtime_info;
2009 if (old_info && old_info->max_domain >= domain->domain_id) {
2010 /* someone already created a large enough runtime info */
2011 mono_memory_barrier ();
2012 old_info->domain_vtables [domain->domain_id] = vt;
2014 int new_size = domain->domain_id;
2016 new_size = MAX (new_size, old_info->max_domain);
2018 /* make the new size a power of two */
2020 while (new_size > i)
2023 /* this is a bounded memory retention issue: may want to
2024 * handle it differently when we'll have a rcu-like system.
2026 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2027 runtime_info->max_domain = new_size - 1;
2028 /* copy the stuff from the older info */
2030 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2032 runtime_info->domain_vtables [domain->domain_id] = vt;
2034 mono_memory_barrier ();
2035 class->runtime_info = runtime_info;
2038 /* Initialize vtable */
2039 if (callbacks.get_vtable_trampoline) {
2040 // This also covers the AOT case
2041 for (i = 0; i < class->vtable_size; ++i) {
2042 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2045 mono_class_setup_vtable (class);
2047 for (i = 0; i < class->vtable_size; ++i) {
2050 if ((cm = class->vtable [i]))
2051 vt->vtable [i] = arch_create_jit_trampoline (cm);
2055 if (ARCH_USE_IMT && imt_table_bytes) {
2056 /* Now that the vtable is full, we can actually fill up the IMT */
2057 if (callbacks.get_imt_trampoline) {
2058 /* lazy construction of the IMT entries enabled */
2059 for (i = 0; i < MONO_IMT_SIZE; ++i)
2060 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2062 build_imt (class, vt, domain, interface_offsets, NULL);
2066 mono_domain_unlock (domain);
2067 mono_loader_unlock ();
2069 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2070 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2071 mono_raise_exception (mono_class_get_exception_for_failure (class));
2073 /* make sure the parent is initialized */
2074 /*FIXME shouldn't this fail the current type?*/
2076 mono_class_vtable_full (domain, class->parent, raise_on_error);
2078 /*FIXME check for OOM*/
2079 vt->type = mono_type_get_object (domain, &class->byval_arg);
2080 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2081 /* This is unregistered in
2082 unregister_vtable_reflection_type() in
2084 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2085 if (class->contextbound)
2094 * mono_class_proxy_vtable:
2095 * @domain: the application domain
2096 * @remove_class: the remote class
2098 * Creates a vtable for transparent proxies. It is basically
2099 * a copy of the real vtable of the class wrapped in @remote_class,
2100 * but all function pointers invoke the remoting functions, and
2101 * vtable->klass points to the transparent proxy class, and not to @class.
2104 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2107 MonoVTable *vt, *pvt;
2108 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2110 GSList *extra_interfaces = NULL;
2111 MonoClass *class = remote_class->proxy_class;
2112 gpointer *interface_offsets;
2116 #ifdef COMPRESSED_INTERFACE_BITMAP
2120 vt = mono_class_vtable (domain, class);
2121 g_assert (vt); /*FIXME property handle failure*/
2122 max_interface_id = vt->max_interface_id;
2124 /* Calculate vtable space for extra interfaces */
2125 for (j = 0; j < remote_class->interface_count; j++) {
2126 MonoClass* iclass = remote_class->interfaces[j];
2130 /*FIXME test for interfaces with variant generic arguments*/
2131 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2132 continue; /* interface implemented by the class */
2133 if (g_slist_find (extra_interfaces, iclass))
2136 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2138 method_count = mono_class_num_methods (iclass);
2140 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2141 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2143 for (i = 0; i < ifaces->len; ++i) {
2144 MonoClass *ic = g_ptr_array_index (ifaces, i);
2145 /*FIXME test for interfaces with variant generic arguments*/
2146 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2147 continue; /* interface implemented by the class */
2148 if (g_slist_find (extra_interfaces, ic))
2150 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2151 method_count += mono_class_num_methods (ic);
2153 g_ptr_array_free (ifaces, TRUE);
2156 extra_interface_vtsize += method_count * sizeof (gpointer);
2157 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2161 mono_stats.imt_number_of_tables++;
2162 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2163 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2164 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2166 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2167 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2170 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2172 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2174 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2176 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2177 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2179 pvt->klass = mono_defaults.transparent_proxy_class;
2180 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2181 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2183 /* initialize vtable */
2184 mono_class_setup_vtable (class);
2185 for (i = 0; i < class->vtable_size; ++i) {
2188 if ((cm = class->vtable [i]))
2189 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2191 pvt->vtable [i] = NULL;
2194 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2195 /* create trampolines for abstract methods */
2196 for (k = class; k; k = k->parent) {
2198 gpointer iter = NULL;
2199 while ((m = mono_class_get_methods (k, &iter)))
2200 if (!pvt->vtable [m->slot])
2201 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2205 pvt->max_interface_id = max_interface_id;
2206 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2207 #ifdef COMPRESSED_INTERFACE_BITMAP
2208 bitmap = g_malloc0 (bsize);
2210 bitmap = mono_domain_alloc0 (domain, bsize);
2213 if (! ARCH_USE_IMT) {
2214 /* initialize interface offsets */
2215 for (i = 0; i < class->interface_offsets_count; ++i) {
2216 int interface_id = class->interfaces_packed [i]->interface_id;
2217 int slot = class->interface_offsets_packed [i];
2218 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2221 for (i = 0; i < class->interface_offsets_count; ++i) {
2222 int interface_id = class->interfaces_packed [i]->interface_id;
2223 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2226 if (extra_interfaces) {
2227 int slot = class->vtable_size;
2233 /* Create trampolines for the methods of the interfaces */
2234 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2235 interf = list_item->data;
2237 if (! ARCH_USE_IMT) {
2238 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2240 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2244 while ((cm = mono_class_get_methods (interf, &iter)))
2245 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2247 slot += mono_class_num_methods (interf);
2249 if (! ARCH_USE_IMT) {
2250 g_slist_free (extra_interfaces);
2255 /* Now that the vtable is full, we can actually fill up the IMT */
2256 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2257 if (extra_interfaces) {
2258 g_slist_free (extra_interfaces);
2262 #ifdef COMPRESSED_INTERFACE_BITMAP
2263 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2264 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2265 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2268 pvt->interface_bitmap = bitmap;
2274 * mono_class_field_is_special_static:
2276 * Returns whether @field is a thread/context static field.
2279 mono_class_field_is_special_static (MonoClassField *field)
2281 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2283 if (mono_field_is_deleted (field))
2285 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2286 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2293 * mono_class_has_special_static_fields:
2295 * Returns whenever @klass has any thread/context static fields.
2298 mono_class_has_special_static_fields (MonoClass *klass)
2300 MonoClassField *field;
2304 while ((field = mono_class_get_fields (klass, &iter))) {
2305 g_assert (field->parent == klass);
2306 if (mono_class_field_is_special_static (field))
2314 * create_remote_class_key:
2315 * Creates an array of pointers that can be used as a hash key for a remote class.
2316 * The first element of the array is the number of pointers.
2319 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2324 if (remote_class == NULL) {
2325 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2326 key = g_malloc (sizeof(gpointer) * 3);
2327 key [0] = GINT_TO_POINTER (2);
2328 key [1] = mono_defaults.marshalbyrefobject_class;
2329 key [2] = extra_class;
2331 key = g_malloc (sizeof(gpointer) * 2);
2332 key [0] = GINT_TO_POINTER (1);
2333 key [1] = extra_class;
2336 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2337 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2338 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2339 key [1] = remote_class->proxy_class;
2341 // Keep the list of interfaces sorted
2342 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2343 if (extra_class && remote_class->interfaces [i] > extra_class) {
2344 key [j++] = extra_class;
2347 key [j] = remote_class->interfaces [i];
2350 key [j] = extra_class;
2352 // Replace the old class. The interface list is the same
2353 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2354 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2355 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2356 for (i = 0; i < remote_class->interface_count; i++)
2357 key [2 + i] = remote_class->interfaces [i];
2365 * copy_remote_class_key:
2367 * Make a copy of KEY in the domain and return the copy.
2370 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2372 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2373 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2375 memcpy (mp_key, key, key_size);
2381 * mono_remote_class:
2382 * @domain: the application domain
2383 * @class_name: name of the remote class
2385 * Creates and initializes a MonoRemoteClass object for a remote type.
2387 * Can raise an exception on failure.
2390 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2393 MonoRemoteClass *rc;
2394 gpointer* key, *mp_key;
2397 key = create_remote_class_key (NULL, proxy_class);
2399 mono_domain_lock (domain);
2400 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2404 mono_domain_unlock (domain);
2408 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2409 if (!mono_error_ok (&error)) {
2411 mono_domain_unlock (domain);
2412 mono_error_raise_exception (&error);
2415 mp_key = copy_remote_class_key (domain, key);
2419 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2420 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2421 rc->interface_count = 1;
2422 rc->interfaces [0] = proxy_class;
2423 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2425 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2426 rc->interface_count = 0;
2427 rc->proxy_class = proxy_class;
2430 rc->default_vtable = NULL;
2431 rc->xdomain_vtable = NULL;
2432 rc->proxy_class_name = name;
2433 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2435 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2437 mono_domain_unlock (domain);
2442 * clone_remote_class:
2443 * Creates a copy of the remote_class, adding the provided class or interface
2445 static MonoRemoteClass*
2446 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2448 MonoRemoteClass *rc;
2449 gpointer* key, *mp_key;
2451 key = create_remote_class_key (remote_class, extra_class);
2452 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2458 mp_key = copy_remote_class_key (domain, key);
2462 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2464 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2465 rc->proxy_class = remote_class->proxy_class;
2466 rc->interface_count = remote_class->interface_count + 1;
2468 // Keep the list of interfaces sorted, since the hash key of
2469 // the remote class depends on this
2470 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2471 if (remote_class->interfaces [i] > extra_class && i == j)
2472 rc->interfaces [j++] = extra_class;
2473 rc->interfaces [j] = remote_class->interfaces [i];
2476 rc->interfaces [j] = extra_class;
2478 // Replace the old class. The interface array is the same
2479 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2480 rc->proxy_class = extra_class;
2481 rc->interface_count = remote_class->interface_count;
2482 if (rc->interface_count > 0)
2483 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2486 rc->default_vtable = NULL;
2487 rc->xdomain_vtable = NULL;
2488 rc->proxy_class_name = remote_class->proxy_class_name;
2490 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2496 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2498 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2499 mono_domain_lock (domain);
2500 if (rp->target_domain_id != -1) {
2501 if (remote_class->xdomain_vtable == NULL)
2502 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2503 mono_domain_unlock (domain);
2504 mono_loader_unlock ();
2505 return remote_class->xdomain_vtable;
2507 if (remote_class->default_vtable == NULL) {
2510 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2511 klass = mono_class_from_mono_type (type);
2512 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2513 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2515 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2518 mono_domain_unlock (domain);
2519 mono_loader_unlock ();
2520 return remote_class->default_vtable;
2524 * mono_upgrade_remote_class:
2525 * @domain: the application domain
2526 * @tproxy: the proxy whose remote class has to be upgraded.
2527 * @klass: class to which the remote class can be casted.
2529 * Updates the vtable of the remote class by adding the necessary method slots
2530 * and interface offsets so it can be safely casted to klass. klass can be a
2531 * class or an interface.
2534 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2536 MonoTransparentProxy *tproxy;
2537 MonoRemoteClass *remote_class;
2538 gboolean redo_vtable;
2540 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2541 mono_domain_lock (domain);
2543 tproxy = (MonoTransparentProxy*) proxy_object;
2544 remote_class = tproxy->remote_class;
2546 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2549 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2550 if (remote_class->interfaces [i] == klass)
2551 redo_vtable = FALSE;
2554 redo_vtable = (remote_class->proxy_class != klass);
2558 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2559 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2562 mono_domain_unlock (domain);
2563 mono_loader_unlock ();
2568 * mono_object_get_virtual_method:
2569 * @obj: object to operate on.
2572 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2573 * the instance of a callvirt of method.
2576 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2579 MonoMethod **vtable;
2581 MonoMethod *res = NULL;
2583 klass = mono_object_class (obj);
2584 if (klass == mono_defaults.transparent_proxy_class) {
2585 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2591 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2594 mono_class_setup_vtable (klass);
2595 vtable = klass->vtable;
2597 if (method->slot == -1) {
2598 /* method->slot might not be set for instances of generic methods */
2599 if (method->is_inflated) {
2600 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2601 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2604 g_assert_not_reached ();
2608 /* check method->slot is a valid index: perform isinstance? */
2609 if (method->slot != -1) {
2610 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2612 gboolean variance_used = FALSE;
2613 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2614 g_assert (iface_offset > 0);
2615 res = vtable [iface_offset + method->slot];
2618 res = vtable [method->slot];
2623 /* It may be an interface, abstract class method or generic method */
2624 if (!res || mono_method_signature (res)->generic_param_count)
2627 /* generic methods demand invoke_with_check */
2628 if (mono_method_signature (res)->generic_param_count)
2629 res = mono_marshal_get_remoting_invoke_with_check (res);
2632 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2633 res = mono_cominterop_get_invoke (res);
2636 res = mono_marshal_get_remoting_invoke (res);
2639 if (method->is_inflated) {
2640 /* Have to inflate the result */
2641 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2651 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2653 g_error ("runtime invoke called on uninitialized runtime");
2657 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2660 * mono_runtime_invoke:
2661 * @method: method to invoke
2662 * @obJ: object instance
2663 * @params: arguments to the method
2664 * @exc: exception information.
2666 * Invokes the method represented by @method on the object @obj.
2668 * obj is the 'this' pointer, it should be NULL for static
2669 * methods, a MonoObject* for object instances and a pointer to
2670 * the value type for value types.
2672 * The params array contains the arguments to the method with the
2673 * same convention: MonoObject* pointers for object instances and
2674 * pointers to the value type otherwise.
2676 * From unmanaged code you'll usually use the
2677 * mono_runtime_invoke() variant.
2679 * Note that this function doesn't handle virtual methods for
2680 * you, it will exec the exact method you pass: we still need to
2681 * expose a function to lookup the derived class implementation
2682 * of a virtual method (there are examples of this in the code,
2685 * You can pass NULL as the exc argument if you don't want to
2686 * catch exceptions, otherwise, *exc will be set to the exception
2687 * thrown, if any. if an exception is thrown, you can't use the
2688 * MonoObject* result from the function.
2690 * If the method returns a value type, it is boxed in an object
2694 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2698 if (mono_runtime_get_no_exec ())
2699 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2701 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2702 mono_profiler_method_start_invoke (method);
2704 result = default_mono_runtime_invoke (method, obj, params, exc);
2706 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2707 mono_profiler_method_end_invoke (method);
2713 * mono_method_get_unmanaged_thunk:
2714 * @method: method to generate a thunk for.
2716 * Returns an unmanaged->managed thunk that can be used to call
2717 * a managed method directly from C.
2719 * The thunk's C signature closely matches the managed signature:
2721 * C#: public bool Equals (object obj);
2722 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2723 * MonoObject*, MonoException**);
2725 * The 1st ("this") parameter must not be used with static methods:
2727 * C#: public static bool ReferenceEquals (object a, object b);
2728 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2731 * The last argument must be a non-null pointer of a MonoException* pointer.
2732 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2733 * exception has been thrown in managed code. Otherwise it will point
2734 * to the MonoException* caught by the thunk. In this case, the result of
2735 * the thunk is undefined:
2737 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2738 * MonoException *ex = NULL;
2739 * Equals func = mono_method_get_unmanaged_thunk (method);
2740 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2742 * // handle exception
2745 * The calling convention of the thunk matches the platform's default
2746 * convention. This means that under Windows, C declarations must
2747 * contain the __stdcall attribute:
2749 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2750 * MonoObject*, MonoException**);
2754 * Value type arguments and return values are treated as they were objects:
2756 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2757 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2759 * Arguments must be properly boxed upon trunk's invocation, while return
2760 * values must be unboxed.
2763 mono_method_get_unmanaged_thunk (MonoMethod *method)
2765 method = mono_marshal_get_thunk_invoke_wrapper (method);
2766 return mono_compile_method (method);
2770 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2774 /* object fields cannot be byref, so we don't need a
2776 gpointer *p = (gpointer*)dest;
2783 case MONO_TYPE_BOOLEAN:
2785 case MONO_TYPE_U1: {
2786 guint8 *p = (guint8*)dest;
2787 *p = value ? *(guint8*)value : 0;
2792 case MONO_TYPE_CHAR: {
2793 guint16 *p = (guint16*)dest;
2794 *p = value ? *(guint16*)value : 0;
2797 #if SIZEOF_VOID_P == 4
2802 case MONO_TYPE_U4: {
2803 gint32 *p = (gint32*)dest;
2804 *p = value ? *(gint32*)value : 0;
2807 #if SIZEOF_VOID_P == 8
2812 case MONO_TYPE_U8: {
2813 gint64 *p = (gint64*)dest;
2814 *p = value ? *(gint64*)value : 0;
2817 case MONO_TYPE_R4: {
2818 float *p = (float*)dest;
2819 *p = value ? *(float*)value : 0;
2822 case MONO_TYPE_R8: {
2823 double *p = (double*)dest;
2824 *p = value ? *(double*)value : 0;
2827 case MONO_TYPE_STRING:
2828 case MONO_TYPE_SZARRAY:
2829 case MONO_TYPE_CLASS:
2830 case MONO_TYPE_OBJECT:
2831 case MONO_TYPE_ARRAY:
2832 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2834 case MONO_TYPE_FNPTR:
2835 case MONO_TYPE_PTR: {
2836 gpointer *p = (gpointer*)dest;
2837 *p = deref_pointer? *(gpointer*)value: value;
2840 case MONO_TYPE_VALUETYPE:
2841 /* note that 't' and 'type->type' can be different */
2842 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2843 t = mono_class_enum_basetype (type->data.klass)->type;
2846 MonoClass *class = mono_class_from_mono_type (type);
2847 int size = mono_class_value_size (class, NULL);
2849 memset (dest, 0, size);
2851 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2854 case MONO_TYPE_GENERICINST:
2855 t = type->data.generic_class->container_class->byval_arg.type;
2858 g_warning ("got type %x", type->type);
2859 g_assert_not_reached ();
2864 * mono_field_set_value:
2865 * @obj: Instance object
2866 * @field: MonoClassField describing the field to set
2867 * @value: The value to be set
2869 * Sets the value of the field described by @field in the object instance @obj
2870 * to the value passed in @value. This method should only be used for instance
2871 * fields. For static fields, use mono_field_static_set_value.
2873 * The value must be on the native format of the field type.
2876 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2880 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2882 dest = (char*)obj + field->offset;
2883 set_value (field->type, dest, value, FALSE);
2887 * mono_field_static_set_value:
2888 * @field: MonoClassField describing the field to set
2889 * @value: The value to be set
2891 * Sets the value of the static field described by @field
2892 * to the value passed in @value.
2894 * The value must be on the native format of the field type.
2897 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2901 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2902 /* you cant set a constant! */
2903 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2905 if (field->offset == -1) {
2906 /* Special static */
2907 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2908 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2910 dest = (char*)vt->data + field->offset;
2912 set_value (field->type, dest, value, FALSE);
2915 /* Used by the debugger */
2917 mono_vtable_get_static_field_data (MonoVTable *vt)
2923 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2927 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2928 if (field->offset == -1) {
2929 /* Special static */
2930 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2931 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2933 src = (guint8*)vt->data + field->offset;
2936 src = (guint8*)obj + field->offset;
2943 * mono_field_get_value:
2944 * @obj: Object instance
2945 * @field: MonoClassField describing the field to fetch information from
2946 * @value: pointer to the location where the value will be stored
2948 * Use this routine to get the value of the field @field in the object
2951 * The pointer provided by value must be of the field type, for reference
2952 * types this is a MonoObject*, for value types its the actual pointer to
2957 * mono_field_get_value (obj, int_field, &i);
2960 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2966 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2968 src = (char*)obj + field->offset;
2969 set_value (field->type, value, src, TRUE);
2973 * mono_field_get_value_object:
2974 * @domain: domain where the object will be created (if boxing)
2975 * @field: MonoClassField describing the field to fetch information from
2976 * @obj: The object instance for the field.
2978 * Returns: a new MonoObject with the value from the given field. If the
2979 * field represents a value type, the value is boxed.
2983 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2987 MonoVTable *vtable = NULL;
2989 gboolean is_static = FALSE;
2990 gboolean is_ref = FALSE;
2991 gboolean is_literal = FALSE;
2992 gboolean is_ptr = FALSE;
2994 MonoType *type = mono_field_get_type_checked (field, &error);
2996 if (!mono_error_ok (&error))
2997 mono_error_raise_exception (&error);
2999 switch (type->type) {
3000 case MONO_TYPE_STRING:
3001 case MONO_TYPE_OBJECT:
3002 case MONO_TYPE_CLASS:
3003 case MONO_TYPE_ARRAY:
3004 case MONO_TYPE_SZARRAY:
3009 case MONO_TYPE_BOOLEAN:
3012 case MONO_TYPE_CHAR:
3021 case MONO_TYPE_VALUETYPE:
3022 is_ref = type->byref;
3024 case MONO_TYPE_GENERICINST:
3025 is_ref = !mono_type_generic_inst_is_valuetype (type);
3031 g_error ("type 0x%x not handled in "
3032 "mono_field_get_value_object", type->type);
3036 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3039 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3043 vtable = mono_class_vtable (domain, field->parent);
3045 char *name = mono_type_get_full_name (field->parent);
3046 /*FIXME extend this to use the MonoError api*/
3047 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3051 if (!vtable->initialized)
3052 mono_runtime_class_init (vtable);
3060 get_default_field_value (domain, field, &o);
3061 } else if (is_static) {
3062 mono_field_static_get_value (vtable, field, &o);
3064 mono_field_get_value (obj, field, &o);
3070 static MonoMethod *m;
3076 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3077 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3083 get_default_field_value (domain, field, v);
3084 } else if (is_static) {
3085 mono_field_static_get_value (vtable, field, v);
3087 mono_field_get_value (obj, field, v);
3090 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3092 args [1] = mono_type_get_object (mono_domain_get (), type);
3094 return mono_runtime_invoke (m, NULL, args, NULL);
3097 /* boxed value type */
3098 klass = mono_class_from_mono_type (type);
3100 if (mono_class_is_nullable (klass))
3101 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3103 o = mono_object_new (domain, klass);
3104 v = ((gchar *) o) + sizeof (MonoObject);
3107 get_default_field_value (domain, field, v);
3108 } else if (is_static) {
3109 mono_field_static_get_value (vtable, field, v);
3111 mono_field_get_value (obj, field, v);
3118 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3121 const char *p = blob;
3122 mono_metadata_decode_blob_size (p, &p);
3125 case MONO_TYPE_BOOLEAN:
3128 *(guint8 *) value = *p;
3130 case MONO_TYPE_CHAR:
3133 *(guint16*) value = read16 (p);
3137 *(guint32*) value = read32 (p);
3141 *(guint64*) value = read64 (p);
3144 readr4 (p, (float*) value);
3147 readr8 (p, (double*) value);
3149 case MONO_TYPE_STRING:
3150 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3152 case MONO_TYPE_CLASS:
3153 *(gpointer*) value = NULL;
3157 g_warning ("type 0x%02x should not be in constant table", type);
3163 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3165 MonoTypeEnum def_type;
3168 data = mono_class_get_field_default_value (field, &def_type);
3169 mono_get_constant_value_from_blob (domain, def_type, data, value);
3173 * mono_field_static_get_value:
3174 * @vt: vtable to the object
3175 * @field: MonoClassField describing the field to fetch information from
3176 * @value: where the value is returned
3178 * Use this routine to get the value of the static field @field value.
3180 * The pointer provided by value must be of the field type, for reference
3181 * types this is a MonoObject*, for value types its the actual pointer to
3186 * mono_field_static_get_value (vt, int_field, &i);
3189 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3193 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3195 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3196 get_default_field_value (vt->domain, field, value);
3200 if (field->offset == -1) {
3201 /* Special static */
3202 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3203 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3205 src = (char*)vt->data + field->offset;
3207 set_value (field->type, value, src, TRUE);
3211 * mono_property_set_value:
3212 * @prop: MonoProperty to set
3213 * @obj: instance object on which to act
3214 * @params: parameters to pass to the propery
3215 * @exc: optional exception
3217 * Invokes the property's set method with the given arguments on the
3218 * object instance obj (or NULL for static properties).
3220 * You can pass NULL as the exc argument if you don't want to
3221 * catch exceptions, otherwise, *exc will be set to the exception
3222 * thrown, if any. if an exception is thrown, you can't use the
3223 * MonoObject* result from the function.
3226 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3228 default_mono_runtime_invoke (prop->set, obj, params, exc);
3232 * mono_property_get_value:
3233 * @prop: MonoProperty to fetch
3234 * @obj: instance object on which to act
3235 * @params: parameters to pass to the propery
3236 * @exc: optional exception
3238 * Invokes the property's get method with the given arguments on the
3239 * object instance obj (or NULL for static properties).
3241 * You can pass NULL as the exc argument if you don't want to
3242 * catch exceptions, otherwise, *exc will be set to the exception
3243 * thrown, if any. if an exception is thrown, you can't use the
3244 * MonoObject* result from the function.
3246 * Returns: the value from invoking the get method on the property.
3249 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3251 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3255 * mono_nullable_init:
3256 * @buf: The nullable structure to initialize.
3257 * @value: the value to initialize from
3258 * @klass: the type for the object
3260 * Initialize the nullable structure pointed to by @buf from @value which
3261 * should be a boxed value type. The size of @buf should be able to hold
3262 * as much data as the @klass->instance_size (which is the number of bytes
3263 * that will be copies).
3265 * Since Nullables have variable structure, we can not define a C
3266 * structure for them.
3269 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3271 MonoClass *param_class = klass->cast_class;
3273 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3274 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3276 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3278 if (param_class->has_references)
3279 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3281 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3283 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3288 * mono_nullable_box:
3289 * @buf: The buffer representing the data to be boxed
3290 * @klass: the type to box it as.
3292 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3296 mono_nullable_box (guint8 *buf, MonoClass *klass)
3298 MonoClass *param_class = klass->cast_class;
3300 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3301 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3303 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3304 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3305 if (param_class->has_references)
3306 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3308 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3316 * mono_get_delegate_invoke:
3317 * @klass: The delegate class
3319 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3322 mono_get_delegate_invoke (MonoClass *klass)
3326 /* This is called at runtime, so avoid the slower search in metadata */
3327 mono_class_setup_methods (klass);
3328 if (klass->exception_type)
3330 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3335 * mono_runtime_delegate_invoke:
3336 * @delegate: pointer to a delegate object.
3337 * @params: parameters for the delegate.
3338 * @exc: Pointer to the exception result.
3340 * Invokes the delegate method @delegate with the parameters provided.
3342 * You can pass NULL as the exc argument if you don't want to
3343 * catch exceptions, otherwise, *exc will be set to the exception
3344 * thrown, if any. if an exception is thrown, you can't use the
3345 * MonoObject* result from the function.
3348 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3352 im = mono_get_delegate_invoke (delegate->vtable->klass);
3355 return mono_runtime_invoke (im, delegate, params, exc);
3358 static char **main_args = NULL;
3359 static int num_main_args;
3362 * mono_runtime_get_main_args:
3364 * Returns: a MonoArray with the arguments passed to the main program
3367 mono_runtime_get_main_args (void)
3371 MonoDomain *domain = mono_domain_get ();
3376 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3378 for (i = 0; i < num_main_args; ++i)
3379 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3385 free_main_args (void)
3389 for (i = 0; i < num_main_args; ++i)
3390 g_free (main_args [i]);
3395 * mono_runtime_run_main:
3396 * @method: the method to start the application with (usually Main)
3397 * @argc: number of arguments from the command line
3398 * @argv: array of strings from the command line
3399 * @exc: excetption results
3401 * Execute a standard Main() method (argc/argv contains the
3402 * executable name). This method also sets the command line argument value
3403 * needed by System.Environment.
3408 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3412 MonoArray *args = NULL;
3413 MonoDomain *domain = mono_domain_get ();
3414 gchar *utf8_fullpath;
3415 MonoMethodSignature *sig;
3417 g_assert (method != NULL);
3419 mono_thread_set_main (mono_thread_current ());
3421 main_args = g_new0 (char*, argc);
3422 num_main_args = argc;
3424 if (!g_path_is_absolute (argv [0])) {
3425 gchar *basename = g_path_get_basename (argv [0]);
3426 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3430 utf8_fullpath = mono_utf8_from_external (fullpath);
3431 if(utf8_fullpath == NULL) {
3432 /* Printing the arg text will cause glib to
3433 * whinge about "Invalid UTF-8", but at least
3434 * its relevant, and shows the problem text
3437 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3438 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3445 utf8_fullpath = mono_utf8_from_external (argv[0]);
3446 if(utf8_fullpath == NULL) {
3447 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3448 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3453 main_args [0] = utf8_fullpath;
3455 for (i = 1; i < argc; ++i) {
3458 utf8_arg=mono_utf8_from_external (argv[i]);
3459 if(utf8_arg==NULL) {
3460 /* Ditto the comment about Invalid UTF-8 here */
3461 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3462 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3466 main_args [i] = utf8_arg;
3471 sig = mono_method_signature (method);
3473 g_print ("Unable to load Main method.\n");
3477 if (sig->param_count) {
3478 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3479 for (i = 0; i < argc; ++i) {
3480 /* The encodings should all work, given that
3481 * we've checked all these args for the
3484 gchar *str = mono_utf8_from_external (argv [i]);
3485 MonoString *arg = mono_string_new (domain, str);
3486 mono_array_setref (args, i, arg);
3490 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3493 mono_assembly_set_main (method->klass->image->assembly);
3495 return mono_runtime_exec_main (method, args, exc);
3499 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3501 static MonoMethod *serialize_method;
3506 if (!serialize_method) {
3507 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3508 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3511 if (!serialize_method) {
3516 g_assert (!mono_object_class (obj)->marshalbyref);
3520 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3528 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3530 static MonoMethod *deserialize_method;
3535 if (!deserialize_method) {
3536 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3537 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3539 if (!deserialize_method) {
3546 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3554 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3556 static MonoMethod *get_proxy_method;
3558 MonoDomain *domain = mono_domain_get ();
3559 MonoRealProxy *real_proxy;
3560 MonoReflectionType *reflection_type;
3561 MonoTransparentProxy *transparent_proxy;
3563 if (!get_proxy_method)
3564 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3566 g_assert (obj->vtable->klass->marshalbyref);
3568 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3569 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3571 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3572 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3575 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3579 return (MonoObject*) transparent_proxy;
3583 * mono_object_xdomain_representation
3585 * @target_domain: a domain
3586 * @exc: pointer to a MonoObject*
3588 * Creates a representation of obj in the domain target_domain. This
3589 * is either a copy of obj arrived through via serialization and
3590 * deserialization or a proxy, depending on whether the object is
3591 * serializable or marshal by ref. obj must not be in target_domain.
3593 * If the object cannot be represented in target_domain, NULL is
3594 * returned and *exc is set to an appropriate exception.
3597 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3599 MonoObject *deserialized = NULL;
3600 gboolean failure = FALSE;
3604 if (mono_object_class (obj)->marshalbyref) {
3605 deserialized = make_transparent_proxy (obj, &failure, exc);
3607 MonoDomain *domain = mono_domain_get ();
3608 MonoObject *serialized;
3610 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3611 serialized = serialize_object (obj, &failure, exc);
3612 mono_domain_set_internal_with_options (target_domain, FALSE);
3614 deserialized = deserialize_object (serialized, &failure, exc);
3615 if (domain != target_domain)
3616 mono_domain_set_internal_with_options (domain, FALSE);
3619 return deserialized;
3622 /* Used in call_unhandled_exception_delegate */
3624 create_unhandled_exception_eventargs (MonoObject *exc)
3628 MonoMethod *method = NULL;
3629 MonoBoolean is_terminating = TRUE;
3632 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3635 mono_class_init (klass);
3637 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3638 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3642 args [1] = &is_terminating;
3644 obj = mono_object_new (mono_domain_get (), klass);
3645 mono_runtime_invoke (method, obj, args, NULL);
3650 /* Used in mono_unhandled_exception */
3652 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3653 MonoObject *e = NULL;
3655 MonoDomain *current_domain = mono_domain_get ();
3657 if (domain != current_domain)
3658 mono_domain_set_internal_with_options (domain, FALSE);
3660 g_assert (domain == mono_object_domain (domain->domain));
3662 if (mono_object_domain (exc) != domain) {
3663 MonoObject *serialization_exc;
3665 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3667 if (serialization_exc) {
3669 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3672 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3673 "System.Runtime.Serialization", "SerializationException",
3674 "Could not serialize unhandled exception.");
3678 g_assert (mono_object_domain (exc) == domain);
3680 pa [0] = domain->domain;
3681 pa [1] = create_unhandled_exception_eventargs (exc);
3682 mono_runtime_delegate_invoke (delegate, pa, &e);
3684 if (domain != current_domain)
3685 mono_domain_set_internal_with_options (current_domain, FALSE);
3689 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3690 if (!mono_error_ok (&error)) {
3691 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3692 mono_error_cleanup (&error);
3694 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3700 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3703 * mono_runtime_unhandled_exception_policy_set:
3704 * @policy: the new policy
3706 * This is a VM internal routine.
3708 * Sets the runtime policy for handling unhandled exceptions.
3711 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3712 runtime_unhandled_exception_policy = policy;
3716 * mono_runtime_unhandled_exception_policy_get:
3718 * This is a VM internal routine.
3720 * Gets the runtime policy for handling unhandled exceptions.
3722 MonoRuntimeUnhandledExceptionPolicy
3723 mono_runtime_unhandled_exception_policy_get (void) {
3724 return runtime_unhandled_exception_policy;
3728 * mono_unhandled_exception:
3729 * @exc: exception thrown
3731 * This is a VM internal routine.
3733 * We call this function when we detect an unhandled exception
3734 * in the default domain.
3736 * It invokes the * UnhandledException event in AppDomain or prints
3737 * a warning to the console
3740 mono_unhandled_exception (MonoObject *exc)
3742 MonoDomain *current_domain = mono_domain_get ();
3743 MonoDomain *root_domain = mono_get_root_domain ();
3744 MonoClassField *field;
3745 MonoObject *current_appdomain_delegate;
3746 MonoObject *root_appdomain_delegate;
3748 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3749 "UnhandledException");
3752 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3753 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3754 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3755 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3756 if (current_domain != root_domain) {
3757 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3759 current_appdomain_delegate = NULL;
3762 /* set exitcode only if we will abort the process */
3764 mono_environment_exitcode_set (1);
3765 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3766 mono_print_unhandled_exception (exc);
3768 if (root_appdomain_delegate) {
3769 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3771 if (current_appdomain_delegate) {
3772 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3779 * mono_runtime_exec_managed_code:
3780 * @domain: Application domain
3781 * @main_func: function to invoke from the execution thread
3782 * @main_args: parameter to the main_func
3784 * Launch a new thread to execute a function
3786 * main_func is called back from the thread with main_args as the
3787 * parameter. The callback function is expected to start Main()
3788 * eventually. This function then waits for all managed threads to
3790 * It is not necesseray anymore to execute managed code in a subthread,
3791 * so this function should not be used anymore by default: just
3792 * execute the code and then call mono_thread_manage ().
3795 mono_runtime_exec_managed_code (MonoDomain *domain,
3796 MonoMainThreadFunc main_func,
3799 mono_thread_create (domain, main_func, main_args);
3801 mono_thread_manage ();
3805 * Execute a standard Main() method (args doesn't contain the
3809 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3814 MonoCustomAttrInfo* cinfo;
3815 gboolean has_stathread_attribute;
3816 MonoInternalThread* thread = mono_thread_internal_current ();
3822 domain = mono_object_domain (args);
3823 if (!domain->entry_assembly) {
3825 MonoAssembly *assembly;
3827 assembly = method->klass->image->assembly;
3828 domain->entry_assembly = assembly;
3829 /* Domains created from another domain already have application_base and configuration_file set */
3830 if (domain->setup->application_base == NULL) {
3831 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3834 if (domain->setup->configuration_file == NULL) {
3835 str = g_strconcat (assembly->image->name, ".config", NULL);
3836 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3838 mono_set_private_bin_path_from_config (domain);
3842 cinfo = mono_custom_attrs_from_method (method);
3844 static MonoClass *stathread_attribute = NULL;
3845 if (!stathread_attribute)
3846 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3847 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3849 mono_custom_attrs_free (cinfo);
3851 has_stathread_attribute = FALSE;
3853 if (has_stathread_attribute) {
3854 thread->apartment_state = ThreadApartmentState_STA;
3856 thread->apartment_state = ThreadApartmentState_MTA;
3858 mono_thread_init_apartment_state ();
3860 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3862 /* FIXME: check signature of method */
3863 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3865 res = mono_runtime_invoke (method, NULL, pa, exc);
3867 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3871 mono_environment_exitcode_set (rval);
3873 mono_runtime_invoke (method, NULL, pa, exc);
3877 /* If the return type of Main is void, only
3878 * set the exitcode if an exception was thrown
3879 * (we don't want to blow away an
3880 * explicitly-set exit code)
3883 mono_environment_exitcode_set (rval);
3887 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3893 * mono_install_runtime_invoke:
3894 * @func: Function to install
3896 * This is a VM internal routine
3899 mono_install_runtime_invoke (MonoInvokeFunc func)
3901 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3906 * mono_runtime_invoke_array:
3907 * @method: method to invoke
3908 * @obJ: object instance
3909 * @params: arguments to the method
3910 * @exc: exception information.
3912 * Invokes the method represented by @method on the object @obj.
3914 * obj is the 'this' pointer, it should be NULL for static
3915 * methods, a MonoObject* for object instances and a pointer to
3916 * the value type for value types.
3918 * The params array contains the arguments to the method with the
3919 * same convention: MonoObject* pointers for object instances and
3920 * pointers to the value type otherwise. The _invoke_array
3921 * variant takes a C# object[] as the params argument (MonoArray
3922 * *params): in this case the value types are boxed inside the
3923 * respective reference representation.
3925 * From unmanaged code you'll usually use the
3926 * mono_runtime_invoke() variant.
3928 * Note that this function doesn't handle virtual methods for
3929 * you, it will exec the exact method you pass: we still need to
3930 * expose a function to lookup the derived class implementation
3931 * of a virtual method (there are examples of this in the code,
3934 * You can pass NULL as the exc argument if you don't want to
3935 * catch exceptions, otherwise, *exc will be set to the exception
3936 * thrown, if any. if an exception is thrown, you can't use the
3937 * MonoObject* result from the function.
3939 * If the method returns a value type, it is boxed in an object
3943 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3946 MonoMethodSignature *sig = mono_method_signature (method);
3947 gpointer *pa = NULL;
3950 gboolean has_byref_nullables = FALSE;
3952 if (NULL != params) {
3953 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3954 for (i = 0; i < mono_array_length (params); i++) {
3955 MonoType *t = sig->params [i];
3961 case MONO_TYPE_BOOLEAN:
3964 case MONO_TYPE_CHAR:
3973 case MONO_TYPE_VALUETYPE:
3974 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3975 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3976 pa [i] = mono_array_get (params, MonoObject*, i);
3978 has_byref_nullables = TRUE;
3980 /* MS seems to create the objects if a null is passed in */
3981 if (!mono_array_get (params, MonoObject*, i))
3982 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3986 * We can't pass the unboxed vtype byref to the callee, since
3987 * that would mean the callee would be able to modify boxed
3988 * primitive types. So we (and MS) make a copy of the boxed
3989 * object, pass that to the callee, and replace the original
3990 * boxed object in the arg array with the copy.
3992 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3993 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3994 mono_array_setref (params, i, copy);
3997 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4000 case MONO_TYPE_STRING:
4001 case MONO_TYPE_OBJECT:
4002 case MONO_TYPE_CLASS:
4003 case MONO_TYPE_ARRAY:
4004 case MONO_TYPE_SZARRAY:
4006 pa [i] = mono_array_addr (params, MonoObject*, i);
4007 // FIXME: I need to check this code path
4009 pa [i] = mono_array_get (params, MonoObject*, i);
4011 case MONO_TYPE_GENERICINST:
4013 t = &t->data.generic_class->container_class->this_arg;
4015 t = &t->data.generic_class->container_class->byval_arg;
4017 case MONO_TYPE_PTR: {
4020 /* The argument should be an IntPtr */
4021 arg = mono_array_get (params, MonoObject*, i);
4025 g_assert (arg->vtable->klass == mono_defaults.int_class);
4026 pa [i] = ((MonoIntPtr*)arg)->m_value;
4031 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4036 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4039 if (mono_class_is_nullable (method->klass)) {
4040 /* Need to create a boxed vtype instead */
4046 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4050 obj = mono_object_new (mono_domain_get (), method->klass);
4051 g_assert (obj); /*maybe we should raise a TLE instead?*/
4052 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4053 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4055 if (method->klass->valuetype)
4056 o = mono_object_unbox (obj);
4059 } else if (method->klass->valuetype) {
4060 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4063 mono_runtime_invoke (method, o, pa, exc);
4066 if (mono_class_is_nullable (method->klass)) {
4067 MonoObject *nullable;
4069 /* Convert the unboxed vtype into a Nullable structure */
4070 nullable = mono_object_new (mono_domain_get (), method->klass);
4072 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4073 obj = mono_object_unbox (nullable);
4076 /* obj must be already unboxed if needed */
4077 res = mono_runtime_invoke (method, obj, pa, exc);
4079 if (sig->ret->type == MONO_TYPE_PTR) {
4080 MonoClass *pointer_class;
4081 static MonoMethod *box_method;
4083 MonoObject *box_exc;
4086 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4087 * convert it to a Pointer object.
4089 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4091 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4093 g_assert (res->vtable->klass == mono_defaults.int_class);
4094 box_args [0] = ((MonoIntPtr*)res)->m_value;
4095 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4096 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4097 g_assert (!box_exc);
4100 if (has_byref_nullables) {
4102 * The runtime invoke wrapper already converted byref nullables back,
4103 * and stored them in pa, we just need to copy them back to the
4106 for (i = 0; i < mono_array_length (params); i++) {
4107 MonoType *t = sig->params [i];
4109 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4110 mono_array_setref (params, i, pa [i]);
4119 arith_overflow (void)
4121 mono_raise_exception (mono_get_exception_overflow ());
4125 * mono_object_allocate:
4126 * @size: number of bytes to allocate
4128 * This is a very simplistic routine until we have our GC-aware
4131 * Returns: an allocated object of size @size, or NULL on failure.
4133 static inline void *
4134 mono_object_allocate (size_t size, MonoVTable *vtable)
4137 mono_stats.new_object_count++;
4138 ALLOC_OBJECT (o, vtable, size);
4144 * mono_object_allocate_ptrfree:
4145 * @size: number of bytes to allocate
4147 * Note that the memory allocated is not zeroed.
4148 * Returns: an allocated object of size @size, or NULL on failure.
4150 static inline void *
4151 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4154 mono_stats.new_object_count++;
4155 ALLOC_PTRFREE (o, vtable, size);
4159 static inline void *
4160 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4163 ALLOC_TYPED (o, size, vtable);
4164 mono_stats.new_object_count++;
4171 * @klass: the class of the object that we want to create
4173 * Returns: a newly created object whose definition is
4174 * looked up using @klass. This will not invoke any constructors,
4175 * so the consumer of this routine has to invoke any constructors on
4176 * its own to initialize the object.
4178 * It returns NULL on failure.
4181 mono_object_new (MonoDomain *domain, MonoClass *klass)
4185 MONO_ARCH_SAVE_REGS;
4186 vtable = mono_class_vtable (domain, klass);
4189 return mono_object_new_specific (vtable);
4193 * mono_object_new_pinned:
4195 * Same as mono_object_new, but the returned object will be pinned.
4196 * For SGEN, these objects will only be freed at appdomain unload.
4199 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4203 MONO_ARCH_SAVE_REGS;
4204 vtable = mono_class_vtable (domain, klass);
4209 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4211 return mono_object_new_specific (vtable);
4216 * mono_object_new_specific:
4217 * @vtable: the vtable of the object that we want to create
4219 * Returns: A newly created object with class and domain specified
4223 mono_object_new_specific (MonoVTable *vtable)
4227 MONO_ARCH_SAVE_REGS;
4229 /* check for is_com_object for COM Interop */
4230 if (vtable->remote || vtable->klass->is_com_object)
4233 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4236 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4239 mono_class_init (klass);
4241 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4243 vtable->domain->create_proxy_for_type_method = im;
4246 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4248 o = mono_runtime_invoke (im, NULL, pa, NULL);
4249 if (o != NULL) return o;
4252 return mono_object_new_alloc_specific (vtable);
4256 mono_object_new_alloc_specific (MonoVTable *vtable)
4260 if (!vtable->klass->has_references) {
4261 o = mono_object_new_ptrfree (vtable);
4262 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4263 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4265 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4266 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4268 if (G_UNLIKELY (vtable->klass->has_finalize))
4269 mono_object_register_finalizer (o);
4271 if (G_UNLIKELY (profile_allocs))
4272 mono_profiler_allocation (o, vtable->klass);
4277 mono_object_new_fast (MonoVTable *vtable)
4280 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4285 mono_object_new_ptrfree (MonoVTable *vtable)
4288 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4289 #if NEED_TO_ZERO_PTRFREE
4290 /* an inline memset is much faster for the common vcase of small objects
4291 * note we assume the allocated size is a multiple of sizeof (void*).
4293 if (vtable->klass->instance_size < 128) {
4295 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4296 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4302 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4309 mono_object_new_ptrfree_box (MonoVTable *vtable)
4312 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4313 /* the object will be boxed right away, no need to memzero it */
4318 * mono_class_get_allocation_ftn:
4320 * @for_box: the object will be used for boxing
4321 * @pass_size_in_words:
4323 * Return the allocation function appropriate for the given class.
4327 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4329 *pass_size_in_words = FALSE;
4331 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4332 profile_allocs = FALSE;
4334 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4335 return mono_object_new_specific;
4337 if (!vtable->klass->has_references) {
4338 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4340 return mono_object_new_ptrfree_box;
4341 return mono_object_new_ptrfree;
4344 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4346 return mono_object_new_fast;
4349 * FIXME: This is actually slower than mono_object_new_fast, because
4350 * of the overhead of parameter passing.
4353 *pass_size_in_words = TRUE;
4354 #ifdef GC_REDIRECT_TO_LOCAL
4355 return GC_local_gcj_fast_malloc;
4357 return GC_gcj_fast_malloc;
4362 return mono_object_new_specific;
4366 * mono_object_new_from_token:
4367 * @image: Context where the type_token is hosted
4368 * @token: a token of the type that we want to create
4370 * Returns: A newly created object whose definition is
4371 * looked up using @token in the @image image
4374 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4378 class = mono_class_get (image, token);
4380 return mono_object_new (domain, class);
4385 * mono_object_clone:
4386 * @obj: the object to clone
4388 * Returns: A newly created object who is a shallow copy of @obj
4391 mono_object_clone (MonoObject *obj)
4394 int size = obj->vtable->klass->instance_size;
4396 o = mono_object_allocate (size, obj->vtable);
4398 if (obj->vtable->klass->has_references) {
4399 mono_gc_wbarrier_object_copy (o, obj);
4401 int size = obj->vtable->klass->instance_size;
4402 /* do not copy the sync state */
4403 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4405 if (G_UNLIKELY (profile_allocs))
4406 mono_profiler_allocation (o, obj->vtable->klass);
4408 if (obj->vtable->klass->has_finalize)
4409 mono_object_register_finalizer (o);
4414 * mono_array_full_copy:
4415 * @src: source array to copy
4416 * @dest: destination array
4418 * Copies the content of one array to another with exactly the same type and size.
4421 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4424 MonoClass *klass = src->obj.vtable->klass;
4426 MONO_ARCH_SAVE_REGS;
4428 g_assert (klass == dest->obj.vtable->klass);
4430 size = mono_array_length (src);
4431 g_assert (size == mono_array_length (dest));
4432 size *= mono_array_element_size (klass);
4434 if (klass->element_class->valuetype) {
4435 if (klass->element_class->has_references)
4436 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4438 memcpy (&dest->vector, &src->vector, size);
4440 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4443 memcpy (&dest->vector, &src->vector, size);
4448 * mono_array_clone_in_domain:
4449 * @domain: the domain in which the array will be cloned into
4450 * @array: the array to clone
4452 * This routine returns a copy of the array that is hosted on the
4453 * specified MonoDomain.
4456 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4461 MonoClass *klass = array->obj.vtable->klass;
4463 MONO_ARCH_SAVE_REGS;
4465 if (array->bounds == NULL) {
4466 size = mono_array_length (array);
4467 o = mono_array_new_full (domain, klass, &size, NULL);
4469 size *= mono_array_element_size (klass);
4471 if (klass->element_class->valuetype) {
4472 if (klass->element_class->has_references)
4473 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4475 memcpy (&o->vector, &array->vector, size);
4477 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4480 memcpy (&o->vector, &array->vector, size);
4485 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4486 size = mono_array_element_size (klass);
4487 for (i = 0; i < klass->rank; ++i) {
4488 sizes [i] = array->bounds [i].length;
4489 size *= array->bounds [i].length;
4490 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4492 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4494 if (klass->element_class->valuetype) {
4495 if (klass->element_class->has_references)
4496 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4498 memcpy (&o->vector, &array->vector, size);
4500 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4503 memcpy (&o->vector, &array->vector, size);
4511 * @array: the array to clone
4513 * Returns: A newly created array who is a shallow copy of @array
4516 mono_array_clone (MonoArray *array)
4518 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4521 /* helper macros to check for overflow when calculating the size of arrays */
4522 #ifdef MONO_BIG_ARRAYS
4523 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4524 #define MYGUINT_MAX MYGUINT64_MAX
4525 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4526 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4527 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4528 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4529 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4531 #define MYGUINT32_MAX 4294967295U
4532 #define MYGUINT_MAX MYGUINT32_MAX
4533 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4534 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4535 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4536 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4537 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4541 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4545 byte_len = mono_array_element_size (class);
4546 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4549 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4551 byte_len += sizeof (MonoArray);
4559 * mono_array_new_full:
4560 * @domain: domain where the object is created
4561 * @array_class: array class
4562 * @lengths: lengths for each dimension in the array
4563 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4565 * This routine creates a new array objects with the given dimensions,
4566 * lower bounds and type.
4569 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4571 uintptr_t byte_len, len, bounds_size;
4574 MonoArrayBounds *bounds;
4578 if (!array_class->inited)
4579 mono_class_init (array_class);
4583 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4584 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4586 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4590 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4592 for (i = 0; i < array_class->rank; ++i) {
4593 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4595 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4596 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4601 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4602 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4606 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4607 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4608 byte_len = (byte_len + 3) & ~3;
4609 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4610 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4611 byte_len += bounds_size;
4614 * Following three lines almost taken from mono_object_new ():
4615 * they need to be kept in sync.
4617 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4618 #ifndef HAVE_SGEN_GC
4619 if (!array_class->has_references) {
4620 o = mono_object_allocate_ptrfree (byte_len, vtable);
4621 #if NEED_TO_ZERO_PTRFREE
4622 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4624 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4625 o = mono_object_allocate_spec (byte_len, vtable);
4627 o = mono_object_allocate (byte_len, vtable);
4630 array = (MonoArray*)o;
4631 array->max_length = len;
4634 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4635 array->bounds = bounds;
4639 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4641 o = mono_gc_alloc_vector (vtable, byte_len, len);
4642 array = (MonoArray*)o;
4643 mono_stats.new_object_count++;
4645 bounds = array->bounds;
4649 for (i = 0; i < array_class->rank; ++i) {
4650 bounds [i].length = lengths [i];
4652 bounds [i].lower_bound = lower_bounds [i];
4656 if (G_UNLIKELY (profile_allocs))
4657 mono_profiler_allocation (o, array_class);
4664 * @domain: domain where the object is created
4665 * @eclass: element class
4666 * @n: number of array elements
4668 * This routine creates a new szarray with @n elements of type @eclass.
4671 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4675 MONO_ARCH_SAVE_REGS;
4677 ac = mono_array_class_get (eclass, 1);
4680 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4684 * mono_array_new_specific:
4685 * @vtable: a vtable in the appropriate domain for an initialized class
4686 * @n: number of array elements
4688 * This routine is a fast alternative to mono_array_new() for code which
4689 * can be sure about the domain it operates in.
4692 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4698 MONO_ARCH_SAVE_REGS;
4700 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4705 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4706 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4709 #ifndef HAVE_SGEN_GC
4710 if (!vtable->klass->has_references) {
4711 o = mono_object_allocate_ptrfree (byte_len, vtable);
4712 #if NEED_TO_ZERO_PTRFREE
4713 ((MonoArray*)o)->bounds = NULL;
4714 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4716 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4717 o = mono_object_allocate_spec (byte_len, vtable);
4719 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4720 o = mono_object_allocate (byte_len, vtable);
4723 ao = (MonoArray *)o;
4726 o = mono_gc_alloc_vector (vtable, byte_len, n);
4728 mono_stats.new_object_count++;
4731 if (G_UNLIKELY (profile_allocs))
4732 mono_profiler_allocation (o, vtable->klass);
4738 * mono_string_new_utf16:
4739 * @text: a pointer to an utf16 string
4740 * @len: the length of the string
4742 * Returns: A newly created string object which contains @text.
4745 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4749 s = mono_string_new_size (domain, len);
4750 g_assert (s != NULL);
4752 memcpy (mono_string_chars (s), text, len * 2);
4758 * mono_string_new_size:
4759 * @text: a pointer to an utf16 string
4760 * @len: the length of the string
4762 * Returns: A newly created string object of @len
4765 mono_string_new_size (MonoDomain *domain, gint32 len)
4769 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4771 /* overflow ? can't fit it, can't allocate it! */
4773 mono_gc_out_of_memory (-1);
4775 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4778 #ifndef HAVE_SGEN_GC
4779 s = mono_object_allocate_ptrfree (size, vtable);
4783 s = mono_gc_alloc_string (vtable, size, len);
4785 #if NEED_TO_ZERO_PTRFREE
4788 if (G_UNLIKELY (profile_allocs))
4789 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4795 * mono_string_new_len:
4796 * @text: a pointer to an utf8 string
4797 * @length: number of bytes in @text to consider
4799 * Returns: A newly created string object which contains @text.
4802 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4804 GError *error = NULL;
4805 MonoString *o = NULL;
4807 glong items_written;
4809 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4812 o = mono_string_new_utf16 (domain, ut, items_written);
4814 g_error_free (error);
4823 * @text: a pointer to an utf8 string
4825 * Returns: A newly created string object which contains @text.
4828 mono_string_new (MonoDomain *domain, const char *text)
4830 GError *error = NULL;
4831 MonoString *o = NULL;
4833 glong items_written;
4838 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4841 o = mono_string_new_utf16 (domain, ut, items_written);
4843 g_error_free (error);
4846 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4851 MonoString *o = NULL;
4853 if (!g_utf8_validate (text, -1, &end))
4856 len = g_utf8_strlen (text, -1);
4857 o = mono_string_new_size (domain, len);
4858 str = mono_string_chars (o);
4860 while (text < end) {
4861 *str++ = g_utf8_get_char (text);
4862 text = g_utf8_next_char (text);
4869 * mono_string_new_wrapper:
4870 * @text: pointer to utf8 characters.
4872 * Helper function to create a string object from @text in the current domain.
4875 mono_string_new_wrapper (const char *text)
4877 MonoDomain *domain = mono_domain_get ();
4879 MONO_ARCH_SAVE_REGS;
4882 return mono_string_new (domain, text);
4889 * @class: the class of the value
4890 * @value: a pointer to the unboxed data
4892 * Returns: A newly created object which contains @value.
4895 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4901 g_assert (class->valuetype);
4902 if (mono_class_is_nullable (class))
4903 return mono_nullable_box (value, class);
4905 vtable = mono_class_vtable (domain, class);
4908 size = mono_class_instance_size (class);
4909 res = mono_object_new_alloc_specific (vtable);
4910 if (G_UNLIKELY (profile_allocs))
4911 mono_profiler_allocation (res, class);
4913 size = size - sizeof (MonoObject);
4916 g_assert (size == mono_class_value_size (class, NULL));
4917 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4919 #if NO_UNALIGNED_ACCESS
4920 memcpy ((char *)res + sizeof (MonoObject), value, size);
4924 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4927 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4930 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4933 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4936 memcpy ((char *)res + sizeof (MonoObject), value, size);
4940 if (class->has_finalize)
4941 mono_object_register_finalizer (res);
4947 * @dest: destination pointer
4948 * @src: source pointer
4949 * @klass: a valuetype class
4951 * Copy a valuetype from @src to @dest. This function must be used
4952 * when @klass contains references fields.
4955 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4957 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4961 * mono_value_copy_array:
4962 * @dest: destination array
4963 * @dest_idx: index in the @dest array
4964 * @src: source pointer
4965 * @count: number of items
4967 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4968 * This function must be used when @klass contains references fields.
4969 * Overlap is handled.
4972 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4974 int size = mono_array_element_size (dest->obj.vtable->klass);
4975 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4976 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4977 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4981 * mono_object_get_domain:
4982 * @obj: object to query
4984 * Returns: the MonoDomain where the object is hosted
4987 mono_object_get_domain (MonoObject *obj)
4989 return mono_object_domain (obj);
4993 * mono_object_get_class:
4994 * @obj: object to query
4996 * Returns: the MonOClass of the object.
4999 mono_object_get_class (MonoObject *obj)
5001 return mono_object_class (obj);
5004 * mono_object_get_size:
5005 * @o: object to query
5007 * Returns: the size, in bytes, of @o
5010 mono_object_get_size (MonoObject* o)
5012 MonoClass* klass = mono_object_class (o);
5013 if (klass == mono_defaults.string_class) {
5014 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5015 } else if (o->vtable->rank) {
5016 MonoArray *array = (MonoArray*)o;
5017 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5018 if (array->bounds) {
5021 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5025 return mono_class_instance_size (klass);
5030 * mono_object_unbox:
5031 * @obj: object to unbox
5033 * Returns: a pointer to the start of the valuetype boxed in this
5036 * This method will assert if the object passed is not a valuetype.
5039 mono_object_unbox (MonoObject *obj)
5041 /* add assert for valuetypes? */
5042 g_assert (obj->vtable->klass->valuetype);
5043 return ((char*)obj) + sizeof (MonoObject);
5047 * mono_object_isinst:
5049 * @klass: a pointer to a class
5051 * Returns: @obj if @obj is derived from @klass
5054 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5057 mono_class_init (klass);
5059 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5060 return mono_object_isinst_mbyref (obj, klass);
5065 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5069 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5078 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5079 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5083 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5084 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5087 MonoClass *oklass = vt->klass;
5088 if ((oklass == mono_defaults.transparent_proxy_class))
5089 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5091 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5095 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5097 MonoDomain *domain = mono_domain_get ();
5099 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5100 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5101 MonoMethod *im = NULL;
5104 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5105 im = mono_object_get_virtual_method (rp, im);
5108 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5111 res = mono_runtime_invoke (im, rp, pa, NULL);
5113 if (*(MonoBoolean *) mono_object_unbox(res)) {
5114 /* Update the vtable of the remote type, so it can safely cast to this new type */
5115 mono_upgrade_remote_class (domain, obj, klass);
5124 * mono_object_castclass_mbyref:
5126 * @klass: a pointer to a class
5128 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5131 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5133 if (!obj) return NULL;
5134 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5136 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5138 "InvalidCastException"));
5143 MonoDomain *orig_domain;
5149 str_lookup (MonoDomain *domain, gpointer user_data)
5151 LDStrInfo *info = user_data;
5152 if (info->res || domain == info->orig_domain)
5154 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5160 mono_string_get_pinned (MonoString *str)
5164 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5165 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5167 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5168 news->length = mono_string_length (str);
5174 #define mono_string_get_pinned(str) (str)
5178 mono_string_is_interned_lookup (MonoString *str, int insert)
5180 MonoGHashTable *ldstr_table;
5184 domain = ((MonoObject *)str)->vtable->domain;
5185 ldstr_table = domain->ldstr_table;
5187 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5192 str = mono_string_get_pinned (str);
5194 mono_g_hash_table_insert (ldstr_table, str, str);
5198 LDStrInfo ldstr_info;
5199 ldstr_info.orig_domain = domain;
5200 ldstr_info.ins = str;
5201 ldstr_info.res = NULL;
5203 mono_domain_foreach (str_lookup, &ldstr_info);
5204 if (ldstr_info.res) {
5206 * the string was already interned in some other domain:
5207 * intern it in the current one as well.
5209 mono_g_hash_table_insert (ldstr_table, str, str);
5219 * mono_string_is_interned:
5220 * @o: String to probe
5222 * Returns whether the string has been interned.
5225 mono_string_is_interned (MonoString *o)
5227 return mono_string_is_interned_lookup (o, FALSE);
5231 * mono_string_intern:
5232 * @o: String to intern
5234 * Interns the string passed.
5235 * Returns: The interned string.
5238 mono_string_intern (MonoString *str)
5240 return mono_string_is_interned_lookup (str, TRUE);
5245 * @domain: the domain where the string will be used.
5246 * @image: a metadata context
5247 * @idx: index into the user string table.
5249 * Implementation for the ldstr opcode.
5250 * Returns: a loaded string from the @image/@idx combination.
5253 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5255 MONO_ARCH_SAVE_REGS;
5257 if (image->dynamic) {
5258 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5261 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5262 return NULL; /*FIXME we should probably be raising an exception here*/
5263 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5268 * mono_ldstr_metadata_sig
5269 * @domain: the domain for the string
5270 * @sig: the signature of a metadata string
5272 * Returns: a MonoString for a string stored in the metadata
5275 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5277 const char *str = sig;
5278 MonoString *o, *interned;
5281 len2 = mono_metadata_decode_blob_size (str, &str);
5284 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5285 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5288 guint16 *p2 = (guint16*)mono_string_chars (o);
5289 for (i = 0; i < len2; ++i) {
5290 *p2 = GUINT16_FROM_LE (*p2);
5296 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5298 /* o will get garbage collected */
5302 o = mono_string_get_pinned (o);
5304 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5311 * mono_string_to_utf8:
5312 * @s: a System.String
5314 * Returns the UTF8 representation for @s.
5315 * The resulting buffer needs to be freed with mono_free().
5317 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5320 mono_string_to_utf8 (MonoString *s)
5323 char *result = mono_string_to_utf8_checked (s, &error);
5325 if (!mono_error_ok (&error))
5326 mono_error_raise_exception (&error);
5331 * mono_string_to_utf8_checked:
5332 * @s: a System.String
5333 * @error: a MonoError.
5335 * Converts a MonoString to its UTF8 representation. May fail; check
5336 * @error to determine whether the conversion was successful.
5337 * The resulting buffer should be freed with mono_free().
5340 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5344 GError *gerror = NULL;
5346 mono_error_init (error);
5352 return g_strdup ("");
5354 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5356 mono_error_set_argument (error, "string", "%s", gerror->message);
5357 g_error_free (gerror);
5360 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5361 if (s->length > written) {
5362 /* allocate the total length and copy the part of the string that has been converted */
5363 char *as2 = g_malloc0 (s->length);
5364 memcpy (as2, as, written);
5373 * mono_string_to_utf16:
5376 * Return an null-terminated array of the utf-16 chars
5377 * contained in @s. The result must be freed with g_free().
5378 * This is a temporary helper until our string implementation
5379 * is reworked to always include the null terminating char.
5382 mono_string_to_utf16 (MonoString *s)
5389 as = g_malloc ((s->length * 2) + 2);
5390 as [(s->length * 2)] = '\0';
5391 as [(s->length * 2) + 1] = '\0';
5394 return (gunichar2 *)(as);
5397 memcpy (as, mono_string_chars(s), s->length * 2);
5398 return (gunichar2 *)(as);
5402 * mono_string_from_utf16:
5403 * @data: the UTF16 string (LPWSTR) to convert
5405 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5407 * Returns: a MonoString.
5410 mono_string_from_utf16 (gunichar2 *data)
5412 MonoDomain *domain = mono_domain_get ();
5418 while (data [len]) len++;
5420 return mono_string_new_utf16 (domain, data, len);
5425 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5431 r = mono_string_to_utf8_checked (s, error);
5432 if (!mono_error_ok (error))
5438 len = strlen (r) + 1;
5440 mp_s = mono_mempool_alloc (mp, len);
5442 mp_s = mono_image_alloc (image, len);
5444 memcpy (mp_s, r, len);
5452 * mono_string_to_utf8_image:
5453 * @s: a System.String
5455 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5458 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5460 return mono_string_to_utf8_internal (NULL, image, s, error);
5464 * mono_string_to_utf8_mp:
5465 * @s: a System.String
5467 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5470 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5472 return mono_string_to_utf8_internal (mp, NULL, s, error);
5476 default_ex_handler (MonoException *ex)
5478 MonoObject *o = (MonoObject*)ex;
5479 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5483 static MonoExceptionFunc ex_handler = default_ex_handler;
5486 * mono_install_handler:
5487 * @func: exception handler
5489 * This is an internal JIT routine used to install the handler for exceptions
5493 mono_install_handler (MonoExceptionFunc func)
5495 ex_handler = func? func: default_ex_handler;
5499 * mono_raise_exception:
5500 * @ex: exception object
5502 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5505 mono_raise_exception (MonoException *ex)
5508 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5509 * that will cause gcc to omit the function epilog, causing problems when
5510 * the JIT tries to walk the stack, since the return address on the stack
5511 * will point into the next function in the executable, not this one.
5514 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5515 MonoInternalThread *thread = mono_thread_internal_current ();
5516 g_assert (ex->object.vtable->domain == mono_domain_get ());
5517 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5524 * mono_wait_handle_new:
5525 * @domain: Domain where the object will be created
5526 * @handle: Handle for the wait handle
5528 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5531 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5533 MonoWaitHandle *res;
5534 gpointer params [1];
5535 static MonoMethod *handle_set;
5537 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5539 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5541 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5543 params [0] = &handle;
5544 mono_runtime_invoke (handle_set, res, params, NULL);
5550 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5552 static MonoClassField *f_os_handle;
5553 static MonoClassField *f_safe_handle;
5555 if (!f_os_handle && !f_safe_handle) {
5556 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5557 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5562 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5566 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5573 mono_runtime_capture_context (MonoDomain *domain)
5575 RuntimeInvokeFunction runtime_invoke;
5577 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5578 MonoMethod *method = mono_get_context_capture_method ();
5579 MonoMethod *wrapper;
5582 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5583 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5584 domain->capture_context_method = mono_compile_method (method);
5587 runtime_invoke = domain->capture_context_runtime_invoke;
5589 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5592 * mono_async_result_new:
5593 * @domain:domain where the object will be created.
5594 * @handle: wait handle.
5595 * @state: state to pass to AsyncResult
5596 * @data: C closure data.
5598 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5599 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5603 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5605 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5606 MonoObject *context = mono_runtime_capture_context (domain);
5607 /* we must capture the execution context from the original thread */
5609 MONO_OBJECT_SETREF (res, execution_context, context);
5610 /* note: result may be null if the flow is suppressed */
5614 MONO_OBJECT_SETREF (res, object_data, object_data);
5615 MONO_OBJECT_SETREF (res, async_state, state);
5617 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5619 res->sync_completed = FALSE;
5620 res->completed = FALSE;
5626 mono_message_init (MonoDomain *domain,
5627 MonoMethodMessage *this,
5628 MonoReflectionMethod *method,
5629 MonoArray *out_args)
5631 static MonoClass *object_array_klass;
5632 static MonoClass *byte_array_klass;
5633 static MonoClass *string_array_klass;
5634 MonoMethodSignature *sig = mono_method_signature (method->method);
5640 if (!object_array_klass) {
5643 klass = mono_array_class_get (mono_defaults.object_class, 1);
5646 mono_memory_barrier ();
5647 object_array_klass = klass;
5649 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5652 mono_memory_barrier ();
5653 byte_array_klass = klass;
5655 klass = mono_array_class_get (mono_defaults.string_class, 1);
5658 mono_memory_barrier ();
5659 string_array_klass = klass;
5662 MONO_OBJECT_SETREF (this, method, method);
5664 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5665 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5666 this->async_result = NULL;
5667 this->call_type = CallType_Sync;
5669 names = g_new (char *, sig->param_count);
5670 mono_method_get_param_names (method->method, (const char **) names);
5671 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5673 for (i = 0; i < sig->param_count; i++) {
5674 name = mono_string_new (domain, names [i]);
5675 mono_array_setref (this->names, i, name);
5679 for (i = 0, j = 0; i < sig->param_count; i++) {
5680 if (sig->params [i]->byref) {
5682 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5683 mono_array_setref (this->args, i, arg);
5687 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5691 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5694 mono_array_set (this->arg_types, guint8, i, arg_type);
5699 * mono_remoting_invoke:
5700 * @real_proxy: pointer to a RealProxy object
5701 * @msg: The MonoMethodMessage to execute
5702 * @exc: used to store exceptions
5703 * @out_args: used to store output arguments
5705 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5706 * IMessage interface and it is not trivial to extract results from there. So
5707 * we call an helper method PrivateInvoke instead of calling
5708 * RealProxy::Invoke() directly.
5710 * Returns: the result object.
5713 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5714 MonoObject **exc, MonoArray **out_args)
5716 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5719 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5722 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5724 real_proxy->vtable->domain->private_invoke_method = im;
5727 pa [0] = real_proxy;
5732 return mono_runtime_invoke (im, NULL, pa, exc);
5736 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5737 MonoObject **exc, MonoArray **out_args)
5739 static MonoClass *object_array_klass;
5742 MonoMethodSignature *sig;
5744 int i, j, outarg_count = 0;
5746 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5748 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5749 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5750 target = tp->rp->unwrapped_server;
5752 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5756 domain = mono_domain_get ();
5757 method = msg->method->method;
5758 sig = mono_method_signature (method);
5760 for (i = 0; i < sig->param_count; i++) {
5761 if (sig->params [i]->byref)
5765 if (!object_array_klass) {
5768 klass = mono_array_class_get (mono_defaults.object_class, 1);
5771 mono_memory_barrier ();
5772 object_array_klass = klass;
5775 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5776 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5779 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5781 for (i = 0, j = 0; i < sig->param_count; i++) {
5782 if (sig->params [i]->byref) {
5784 arg = mono_array_get (msg->args, gpointer, i);
5785 mono_array_setref (*out_args, j, arg);
5794 * mono_object_to_string:
5796 * @exc: Any exception thrown by ToString (). May be NULL.
5798 * Returns: the result of calling ToString () on an object.
5801 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5803 static MonoMethod *to_string = NULL;
5809 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5811 method = mono_object_get_virtual_method (obj, to_string);
5813 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5817 * mono_print_unhandled_exception:
5818 * @exc: The exception
5820 * Prints the unhandled exception.
5823 mono_print_unhandled_exception (MonoObject *exc)
5826 char *message = (char*)"";
5827 gboolean free_message = FALSE;
5830 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5831 message = g_strdup ("OutOfMemoryException");
5833 str = mono_object_to_string (exc, NULL);
5835 message = mono_string_to_utf8_checked (str, &error);
5836 if (!mono_error_ok (&error)) {
5837 mono_error_cleanup (&error);
5838 message = (char *) "";
5840 free_message = TRUE;
5846 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5847 * exc->vtable->klass->name, message);
5849 g_printerr ("\nUnhandled Exception: %s\n", message);
5856 * mono_delegate_ctor:
5857 * @this: pointer to an uninitialized delegate object
5858 * @target: target object
5859 * @addr: pointer to native code
5862 * Initialize a delegate and sets a specific method, not the one
5863 * associated with addr. This is useful when sharing generic code.
5864 * In that case addr will most probably not be associated with the
5865 * correct instantiation of the method.
5868 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5870 MonoDelegate *delegate = (MonoDelegate *)this;
5877 delegate->method = method;
5879 class = this->vtable->klass;
5880 mono_stats.delegate_creations++;
5882 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5884 method = mono_marshal_get_remoting_invoke (method);
5885 delegate->method_ptr = mono_compile_method (method);
5886 MONO_OBJECT_SETREF (delegate, target, target);
5887 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5888 method = mono_marshal_get_unbox_wrapper (method);
5889 delegate->method_ptr = mono_compile_method (method);
5890 MONO_OBJECT_SETREF (delegate, target, target);
5892 delegate->method_ptr = addr;
5893 MONO_OBJECT_SETREF (delegate, target, target);
5896 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5900 * mono_delegate_ctor:
5901 * @this: pointer to an uninitialized delegate object
5902 * @target: target object
5903 * @addr: pointer to native code
5905 * This is used to initialize a delegate.
5908 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5910 MonoDomain *domain = mono_domain_get ();
5912 MonoMethod *method = NULL;
5916 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5917 method = ji->method;
5918 g_assert (!method->klass->generic_container);
5921 mono_delegate_ctor_with_method (this, target, addr, method);
5925 * mono_method_call_message_new:
5926 * @method: method to encapsulate
5927 * @params: parameters to the method
5928 * @invoke: optional, delegate invoke.
5929 * @cb: async callback delegate.
5930 * @state: state passed to the async callback.
5932 * Translates arguments pointers into a MonoMethodMessage.
5935 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5936 MonoDelegate **cb, MonoObject **state)
5938 MonoDomain *domain = mono_domain_get ();
5939 MonoMethodSignature *sig = mono_method_signature (method);
5940 MonoMethodMessage *msg;
5943 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5946 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5947 count = sig->param_count - 2;
5949 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5950 count = sig->param_count;
5953 for (i = 0; i < count; i++) {
5958 if (sig->params [i]->byref)
5959 vpos = *((gpointer *)params [i]);
5963 type = sig->params [i]->type;
5964 class = mono_class_from_mono_type (sig->params [i]);
5966 if (class->valuetype)
5967 arg = mono_value_box (domain, class, vpos);
5969 arg = *((MonoObject **)vpos);
5971 mono_array_setref (msg->args, i, arg);
5974 if (cb != NULL && state != NULL) {
5975 *cb = *((MonoDelegate **)params [i]);
5977 *state = *((MonoObject **)params [i]);
5984 * mono_method_return_message_restore:
5986 * Restore results from message based processing back to arguments pointers
5989 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5991 MonoMethodSignature *sig = mono_method_signature (method);
5992 int i, j, type, size, out_len;
5994 if (out_args == NULL)
5996 out_len = mono_array_length (out_args);
6000 for (i = 0, j = 0; i < sig->param_count; i++) {
6001 MonoType *pt = sig->params [i];
6006 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6008 arg = mono_array_get (out_args, gpointer, j);
6011 g_assert (type != MONO_TYPE_VOID);
6013 if (MONO_TYPE_IS_REFERENCE (pt)) {
6014 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6017 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6018 size = mono_class_value_size (class, NULL);
6019 if (class->has_references)
6020 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6022 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6024 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6025 memset (*((gpointer *)params [i]), 0, size);
6035 * mono_load_remote_field:
6036 * @this: pointer to an object
6037 * @klass: klass of the object containing @field
6038 * @field: the field to load
6039 * @res: a storage to store the result
6041 * This method is called by the runtime on attempts to load fields of
6042 * transparent proxy objects. @this points to such TP, @klass is the class of
6043 * the object containing @field. @res is a storage location which can be
6044 * used to store the result.
6046 * Returns: an address pointing to the value of field.
6049 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6051 static MonoMethod *getter = NULL;
6052 MonoDomain *domain = mono_domain_get ();
6053 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6054 MonoClass *field_class;
6055 MonoMethodMessage *msg;
6056 MonoArray *out_args;
6060 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6061 g_assert (res != NULL);
6063 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6064 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6069 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6073 field_class = mono_class_from_mono_type (field->type);
6075 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6076 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6077 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6079 full_name = mono_type_get_full_name (klass);
6080 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6081 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6084 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6086 if (exc) mono_raise_exception ((MonoException *)exc);
6088 if (mono_array_length (out_args) == 0)
6091 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6093 if (field_class->valuetype) {
6094 return ((char *)*res) + sizeof (MonoObject);
6100 * mono_load_remote_field_new:
6105 * Missing documentation.
6108 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6110 static MonoMethod *getter = NULL;
6111 MonoDomain *domain = mono_domain_get ();
6112 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6113 MonoClass *field_class;
6114 MonoMethodMessage *msg;
6115 MonoArray *out_args;
6116 MonoObject *exc, *res;
6119 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6121 field_class = mono_class_from_mono_type (field->type);
6123 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6125 if (field_class->valuetype) {
6126 res = mono_object_new (domain, field_class);
6127 val = ((gchar *) res) + sizeof (MonoObject);
6131 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6136 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6140 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6141 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6143 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6145 full_name = mono_type_get_full_name (klass);
6146 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6147 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6150 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6152 if (exc) mono_raise_exception ((MonoException *)exc);
6154 if (mono_array_length (out_args) == 0)
6157 res = mono_array_get (out_args, MonoObject *, 0);
6163 * mono_store_remote_field:
6164 * @this: pointer to an object
6165 * @klass: klass of the object containing @field
6166 * @field: the field to load
6167 * @val: the value/object to store
6169 * This method is called by the runtime on attempts to store fields of
6170 * transparent proxy objects. @this points to such TP, @klass is the class of
6171 * the object containing @field. @val is the new value to store in @field.
6174 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6176 static MonoMethod *setter = NULL;
6177 MonoDomain *domain = mono_domain_get ();
6178 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6179 MonoClass *field_class;
6180 MonoMethodMessage *msg;
6181 MonoArray *out_args;
6186 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6188 field_class = mono_class_from_mono_type (field->type);
6190 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6191 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6192 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6197 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6201 if (field_class->valuetype)
6202 arg = mono_value_box (domain, field_class, val);
6204 arg = *((MonoObject **)val);
6207 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6208 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6210 full_name = mono_type_get_full_name (klass);
6211 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6212 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6213 mono_array_setref (msg->args, 2, arg);
6216 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6218 if (exc) mono_raise_exception ((MonoException *)exc);
6222 * mono_store_remote_field_new:
6228 * Missing documentation
6231 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6233 static MonoMethod *setter = NULL;
6234 MonoDomain *domain = mono_domain_get ();
6235 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6236 MonoClass *field_class;
6237 MonoMethodMessage *msg;
6238 MonoArray *out_args;
6242 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6244 field_class = mono_class_from_mono_type (field->type);
6246 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6247 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6248 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6253 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6257 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6258 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6260 full_name = mono_type_get_full_name (klass);
6261 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6262 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6263 mono_array_setref (msg->args, 2, arg);
6266 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6268 if (exc) mono_raise_exception ((MonoException *)exc);
6272 * mono_create_ftnptr:
6274 * Given a function address, create a function descriptor for it.
6275 * This is only needed on some platforms.
6278 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6280 return callbacks.create_ftnptr (domain, addr);
6284 * mono_get_addr_from_ftnptr:
6286 * Given a pointer to a function descriptor, return the function address.
6287 * This is only needed on some platforms.
6290 mono_get_addr_from_ftnptr (gpointer descr)
6292 return callbacks.get_addr_from_ftnptr (descr);
6296 * mono_string_chars:
6299 * Returns a pointer to the UCS16 characters stored in the MonoString
6302 mono_string_chars (MonoString *s)
6308 * mono_string_length:
6311 * Returns the lenght in characters of the string
6314 mono_string_length (MonoString *s)
6320 * mono_array_length:
6321 * @array: a MonoArray*
6323 * Returns the total number of elements in the array. This works for
6324 * both vectors and multidimensional arrays.
6327 mono_array_length (MonoArray *array)
6329 return array->max_length;
6333 * mono_array_addr_with_size:
6334 * @array: a MonoArray*
6335 * @size: size of the array elements
6336 * @idx: index into the array
6338 * Returns the address of the @idx element in the array.
6341 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6343 return ((char*)(array)->vector) + size * idx;