2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
83 free_main_args (void);
85 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
86 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
87 static CRITICAL_SECTION ldstr_section;
89 static gboolean profile_allocs = TRUE;
92 mono_runtime_object_init (MonoObject *this)
94 MonoMethod *method = NULL;
95 MonoClass *klass = this->vtable->klass;
97 method = mono_class_get_method_from_name (klass, ".ctor", 0);
100 if (method->klass->valuetype)
101 this = mono_object_unbox (this);
102 mono_runtime_invoke (method, this, NULL, NULL);
105 /* The pseudo algorithm for type initialization from the spec
106 Note it doesn't say anything about domains - only threads.
108 2. If the type is initialized you are done.
109 2.1. If the type is not yet initialized, try to take an
111 2.2. If successful, record this thread as responsible for
112 initializing the type and proceed to step 2.3.
113 2.2.1. If not, see whether this thread or any thread
114 waiting for this thread to complete already holds the lock.
115 2.2.2. If so, return since blocking would create a deadlock. This thread
116 will now see an incompletely initialized state for the type,
117 but no deadlock will arise.
118 2.2.3 If not, block until the type is initialized then return.
119 2.3 Initialize the parent type and then all interfaces implemented
121 2.4 Execute the type initialization code for this type.
122 2.5 Mark the type as initialized, release the initialization lock,
123 awaken any threads waiting for this type to be initialized,
130 guint32 initializing_tid;
131 guint32 waiting_count;
133 CRITICAL_SECTION initialization_section;
134 } TypeInitializationLock;
136 /* for locking access to type_initialization_hash and blocked_thread_hash */
137 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
138 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
139 static CRITICAL_SECTION type_initialization_section;
141 /* from vtable to lock */
142 static GHashTable *type_initialization_hash;
144 /* from thread id to thread id being waited on */
145 static GHashTable *blocked_thread_hash;
148 static MonoThread *main_thread;
150 /* Functions supplied by the runtime */
151 static MonoRuntimeCallbacks callbacks;
154 * mono_thread_set_main:
155 * @thread: thread to set as the main thread
157 * This function can be used to instruct the runtime to treat @thread
158 * as the main thread, ie, the thread that would normally execute the Main()
159 * method. This basically means that at the end of @thread, the runtime will
160 * wait for the existing foreground threads to quit and other such details.
163 mono_thread_set_main (MonoThread *thread)
165 main_thread = thread;
169 mono_thread_get_main (void)
175 mono_type_initialization_init (void)
177 InitializeCriticalSection (&type_initialization_section);
178 type_initialization_hash = g_hash_table_new (NULL, NULL);
179 blocked_thread_hash = g_hash_table_new (NULL, NULL);
180 InitializeCriticalSection (&ldstr_section);
184 mono_type_initialization_cleanup (void)
187 /* This is causing race conditions with
188 * mono_release_type_locks
190 DeleteCriticalSection (&type_initialization_section);
191 g_hash_table_destroy (type_initialization_hash);
192 type_initialization_hash = NULL;
194 DeleteCriticalSection (&ldstr_section);
195 g_hash_table_destroy (blocked_thread_hash);
196 blocked_thread_hash = NULL;
202 * get_type_init_exception_for_vtable:
204 * Return the stored type initialization exception for VTABLE.
206 static MonoException*
207 get_type_init_exception_for_vtable (MonoVTable *vtable)
209 MonoDomain *domain = vtable->domain;
210 MonoClass *klass = vtable->klass;
214 g_assert (vtable->init_failed);
217 * If the initializing thread was rudely aborted, the exception is not stored
221 mono_domain_lock (domain);
222 if (domain->type_init_exception_hash)
223 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
224 mono_domain_unlock (domain);
227 if (klass->name_space && *klass->name_space)
228 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
230 full_name = g_strdup (klass->name);
231 ex = mono_get_exception_type_initialization (full_name, NULL);
238 * mono_runtime_class_init:
239 * @vtable: vtable that needs to be initialized
241 * This routine calls the class constructor for @vtable.
244 mono_runtime_class_init (MonoVTable *vtable)
246 mono_runtime_class_init_full (vtable, TRUE);
250 * mono_runtime_class_init_full:
251 * @vtable that neeeds to be initialized
252 * @raise_exception is TRUE, exceptions are raised intead of returned
256 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
259 MonoException *exc_to_throw;
260 MonoMethod *method = NULL;
266 if (vtable->initialized)
270 klass = vtable->klass;
272 if (!klass->image->checked_module_cctor) {
273 mono_image_check_for_module_cctor (klass->image);
274 if (klass->image->has_module_cctor) {
275 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
276 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
279 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
284 method = mono_class_get_cctor (klass);
287 MonoDomain *domain = vtable->domain;
288 TypeInitializationLock *lock;
289 guint32 tid = GetCurrentThreadId();
290 int do_initialization = 0;
291 MonoDomain *last_domain = NULL;
293 mono_type_initialization_lock ();
294 /* double check... */
295 if (vtable->initialized) {
296 mono_type_initialization_unlock ();
299 if (vtable->init_failed) {
300 mono_type_initialization_unlock ();
302 /* The type initialization already failed once, rethrow the same exception */
304 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
305 return get_type_init_exception_for_vtable (vtable);
307 lock = g_hash_table_lookup (type_initialization_hash, vtable);
309 /* This thread will get to do the initialization */
310 if (mono_domain_get () != domain) {
311 /* Transfer into the target domain */
312 last_domain = mono_domain_get ();
313 if (!mono_domain_set (domain, FALSE)) {
314 vtable->initialized = 1;
315 mono_type_initialization_unlock ();
317 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
318 return mono_get_exception_appdomain_unloaded ();
321 lock = g_malloc (sizeof(TypeInitializationLock));
322 InitializeCriticalSection (&lock->initialization_section);
323 lock->initializing_tid = tid;
324 lock->waiting_count = 1;
326 /* grab the vtable lock while this thread still owns type_initialization_section */
327 EnterCriticalSection (&lock->initialization_section);
328 g_hash_table_insert (type_initialization_hash, vtable, lock);
329 do_initialization = 1;
332 TypeInitializationLock *pending_lock;
334 if (lock->initializing_tid == tid || lock->done) {
335 mono_type_initialization_unlock ();
338 /* see if the thread doing the initialization is already blocked on this thread */
339 blocked = GUINT_TO_POINTER (lock->initializing_tid);
340 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
341 if (pending_lock->initializing_tid == tid) {
342 if (!pending_lock->done) {
343 mono_type_initialization_unlock ();
346 /* the thread doing the initialization is blocked on this thread,
347 but on a lock that has already been freed. It just hasn't got
352 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
354 ++lock->waiting_count;
355 /* record the fact that we are waiting on the initializing thread */
356 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
358 mono_type_initialization_unlock ();
360 if (do_initialization) {
361 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
363 /* If the initialization failed, mark the class as unusable. */
364 /* Avoid infinite loops */
366 (klass->image == mono_defaults.corlib &&
367 !strcmp (klass->name_space, "System") &&
368 !strcmp (klass->name, "TypeInitializationException")))) {
369 vtable->init_failed = 1;
371 if (klass->name_space && *klass->name_space)
372 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
374 full_name = g_strdup (klass->name);
375 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
379 * Store the exception object so it could be thrown on subsequent
382 mono_domain_lock (domain);
383 if (!domain->type_init_exception_hash)
384 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
385 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
386 mono_domain_unlock (domain);
390 mono_domain_set (last_domain, TRUE);
392 LeaveCriticalSection (&lock->initialization_section);
394 /* this just blocks until the initializing thread is done */
395 EnterCriticalSection (&lock->initialization_section);
396 LeaveCriticalSection (&lock->initialization_section);
399 mono_type_initialization_lock ();
400 if (lock->initializing_tid != tid)
401 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
402 --lock->waiting_count;
403 if (lock->waiting_count == 0) {
404 DeleteCriticalSection (&lock->initialization_section);
405 g_hash_table_remove (type_initialization_hash, vtable);
408 if (!vtable->init_failed)
409 vtable->initialized = 1;
410 mono_type_initialization_unlock ();
412 if (vtable->init_failed) {
413 /* Either we were the initializing thread or we waited for the initialization */
415 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
416 return get_type_init_exception_for_vtable (vtable);
419 vtable->initialized = 1;
426 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
428 MonoVTable *vtable = (MonoVTable*)key;
430 TypeInitializationLock *lock = (TypeInitializationLock*) value;
431 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
434 * Have to set this since it cannot be set by the normal code in
435 * mono_runtime_class_init (). In this case, the exception object is not stored,
436 * and get_type_init_exception_for_class () needs to be aware of this.
438 vtable->init_failed = 1;
439 LeaveCriticalSection (&lock->initialization_section);
440 --lock->waiting_count;
441 if (lock->waiting_count == 0) {
442 DeleteCriticalSection (&lock->initialization_section);
451 mono_release_type_locks (MonoInternalThread *thread)
453 mono_type_initialization_lock ();
454 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
455 mono_type_initialization_unlock ();
459 default_trampoline (MonoMethod *method)
465 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
467 g_assert_not_reached ();
473 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
475 g_error ("remoting not installed");
480 default_delegate_trampoline (MonoClass *klass)
482 g_assert_not_reached ();
486 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
487 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
488 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
489 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
490 static MonoImtThunkBuilder imt_thunk_builder = NULL;
491 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
492 #if (MONO_IMT_SIZE > 32)
493 #error "MONO_IMT_SIZE cannot be larger than 32"
497 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
499 memcpy (&callbacks, cbs, sizeof (*cbs));
502 MonoRuntimeCallbacks*
503 mono_get_runtime_callbacks (void)
509 mono_install_trampoline (MonoTrampoline func)
511 arch_create_jit_trampoline = func? func: default_trampoline;
515 mono_install_jump_trampoline (MonoJumpTrampoline func)
517 arch_create_jump_trampoline = func? func: default_jump_trampoline;
521 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
523 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
527 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
529 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
533 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
534 imt_thunk_builder = func;
537 static MonoCompileFunc default_mono_compile_method = NULL;
540 * mono_install_compile_method:
541 * @func: function to install
543 * This is a VM internal routine
546 mono_install_compile_method (MonoCompileFunc func)
548 default_mono_compile_method = func;
552 * mono_compile_method:
553 * @method: The method to compile.
555 * This JIT-compiles the method, and returns the pointer to the native code
559 mono_compile_method (MonoMethod *method)
561 if (!default_mono_compile_method) {
562 g_error ("compile method called on uninitialized runtime");
565 return default_mono_compile_method (method);
569 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
571 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
575 mono_runtime_create_delegate_trampoline (MonoClass *klass)
577 return arch_create_delegate_trampoline (klass);
580 static MonoFreeMethodFunc default_mono_free_method = NULL;
583 * mono_install_free_method:
584 * @func: pointer to the MonoFreeMethodFunc used to release a method
586 * This is an internal VM routine, it is used for the engines to
587 * register a handler to release the resources associated with a method.
589 * Methods are freed when no more references to the delegate that holds
593 mono_install_free_method (MonoFreeMethodFunc func)
595 default_mono_free_method = func;
599 * mono_runtime_free_method:
600 * @domain; domain where the method is hosted
601 * @method: method to release
603 * This routine is invoked to free the resources associated with
604 * a method that has been JIT compiled. This is used to discard
605 * methods that were used only temporarily (for example, used in marshalling)
609 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
611 if (default_mono_free_method != NULL)
612 default_mono_free_method (domain, method);
614 mono_method_clear_object (domain, method);
616 mono_free_method (method);
620 * The vtables in the root appdomain are assumed to be reachable by other
621 * roots, and we don't use typed allocation in the other domains.
624 /* The sync block is no longer a GC pointer */
625 #define GC_HEADER_BITMAP (0)
627 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
630 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
632 MonoClassField *field;
638 max_size = mono_class_data_size (class) / sizeof (gpointer);
640 max_size = class->instance_size / sizeof (gpointer);
641 if (max_size > size) {
642 g_assert (offset <= 0);
643 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
648 /*An Ephemeron cannot be marked by sgen*/
649 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
651 memset (bitmap, 0, size / 8);
656 for (p = class; p != NULL; p = p->parent) {
657 gpointer iter = NULL;
658 while ((field = mono_class_get_fields (p, &iter))) {
662 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
664 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
667 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
670 /* FIXME: should not happen, flag as type load error */
671 if (field->type->byref)
674 if (static_fields && field->offset == -1)
678 pos = field->offset / sizeof (gpointer);
681 type = mono_type_get_underlying_type (field->type);
682 switch (type->type) {
685 case MONO_TYPE_FNPTR:
687 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
692 if (class->image != mono_defaults.corlib)
695 case MONO_TYPE_STRING:
696 case MONO_TYPE_SZARRAY:
697 case MONO_TYPE_CLASS:
698 case MONO_TYPE_OBJECT:
699 case MONO_TYPE_ARRAY:
700 g_assert ((field->offset % sizeof(gpointer)) == 0);
702 g_assert (pos < size || pos <= max_size);
703 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
704 *max_set = MAX (*max_set, pos);
706 case MONO_TYPE_GENERICINST:
707 if (!mono_type_generic_inst_is_valuetype (type)) {
708 g_assert ((field->offset % sizeof(gpointer)) == 0);
710 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
711 *max_set = MAX (*max_set, pos);
716 case MONO_TYPE_VALUETYPE: {
717 MonoClass *fclass = mono_class_from_mono_type (field->type);
718 if (fclass->has_references) {
719 /* remove the object header */
720 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
734 case MONO_TYPE_BOOLEAN:
738 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
750 * similar to the above, but sets the bits in the bitmap for any non-ref field
751 * and ignores static fields
754 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
756 MonoClassField *field;
761 max_size = class->instance_size / sizeof (gpointer);
762 if (max_size >= size) {
763 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
766 for (p = class; p != NULL; p = p->parent) {
767 gpointer iter = NULL;
768 while ((field = mono_class_get_fields (p, &iter))) {
771 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
773 /* FIXME: should not happen, flag as type load error */
774 if (field->type->byref)
777 pos = field->offset / sizeof (gpointer);
780 type = mono_type_get_underlying_type (field->type);
781 switch (type->type) {
782 #if SIZEOF_VOID_P == 8
786 case MONO_TYPE_FNPTR:
791 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
792 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
793 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
796 #if SIZEOF_VOID_P == 4
800 case MONO_TYPE_FNPTR:
805 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
806 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
807 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
813 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
814 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
815 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
818 case MONO_TYPE_BOOLEAN:
821 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
823 case MONO_TYPE_STRING:
824 case MONO_TYPE_SZARRAY:
825 case MONO_TYPE_CLASS:
826 case MONO_TYPE_OBJECT:
827 case MONO_TYPE_ARRAY:
829 case MONO_TYPE_GENERICINST:
830 if (!mono_type_generic_inst_is_valuetype (type)) {
835 case MONO_TYPE_VALUETYPE: {
836 MonoClass *fclass = mono_class_from_mono_type (field->type);
837 /* remove the object header */
838 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
842 g_assert_not_reached ();
851 * mono_class_insecure_overlapping:
852 * check if a class with explicit layout has references and non-references
853 * fields overlapping.
855 * Returns: TRUE if it is insecure to load the type.
858 mono_class_insecure_overlapping (MonoClass *klass)
862 gsize default_bitmap [4] = {0};
864 gsize default_nrbitmap [4] = {0};
865 int i, insecure = FALSE;
868 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
869 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
871 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
872 int idx = i % (sizeof (bitmap [0]) * 8);
873 if (bitmap [idx] & nrbitmap [idx]) {
878 if (bitmap != default_bitmap)
880 if (nrbitmap != default_nrbitmap)
883 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
891 mono_string_alloc (int length)
893 return mono_string_new_size (mono_domain_get (), length);
897 mono_class_compute_gc_descriptor (MonoClass *class)
901 gsize default_bitmap [4] = {0};
902 static gboolean gcj_inited = FALSE;
907 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
908 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
909 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
910 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
912 #ifdef HAVE_GC_GCJ_MALLOC
914 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
918 #ifdef GC_REDIRECT_TO_LOCAL
919 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
920 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
922 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
923 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
928 mono_loader_unlock ();
932 mono_class_init (class);
934 if (class->gc_descr_inited)
937 class->gc_descr_inited = TRUE;
938 class->gc_descr = GC_NO_DESCRIPTOR;
940 bitmap = default_bitmap;
941 if (class == mono_defaults.string_class) {
942 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
943 } else if (class->rank) {
944 mono_class_compute_gc_descriptor (class->element_class);
945 if (!class->element_class->valuetype) {
947 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
948 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
949 class->name_space, class->name);*/
951 /* remove the object header */
952 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
953 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
954 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
955 class->name_space, class->name);*/
956 if (bitmap != default_bitmap)
960 /*static int count = 0;
963 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
964 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
966 if (class->gc_descr == GC_NO_DESCRIPTOR)
967 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
969 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
970 if (bitmap != default_bitmap)
976 * field_is_special_static:
977 * @fklass: The MonoClass to look up.
978 * @field: The MonoClassField describing the field.
980 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
981 * SPECIAL_STATIC_NONE otherwise.
984 field_is_special_static (MonoClass *fklass, MonoClassField *field)
986 MonoCustomAttrInfo *ainfo;
988 ainfo = mono_custom_attrs_from_field (fklass, field);
991 for (i = 0; i < ainfo->num_attrs; ++i) {
992 MonoClass *klass = ainfo->attrs [i].ctor->klass;
993 if (klass->image == mono_defaults.corlib) {
994 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
995 mono_custom_attrs_free (ainfo);
996 return SPECIAL_STATIC_THREAD;
998 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
999 mono_custom_attrs_free (ainfo);
1000 return SPECIAL_STATIC_CONTEXT;
1004 mono_custom_attrs_free (ainfo);
1005 return SPECIAL_STATIC_NONE;
1008 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1009 #define mix(a,b,c) { \
1010 a -= c; a ^= rot(c, 4); c += b; \
1011 b -= a; b ^= rot(a, 6); a += c; \
1012 c -= b; c ^= rot(b, 8); b += a; \
1013 a -= c; a ^= rot(c,16); c += b; \
1014 b -= a; b ^= rot(a,19); a += c; \
1015 c -= b; c ^= rot(b, 4); b += a; \
1017 #define final(a,b,c) { \
1018 c ^= b; c -= rot(b,14); \
1019 a ^= c; a -= rot(c,11); \
1020 b ^= a; b -= rot(a,25); \
1021 c ^= b; c -= rot(b,16); \
1022 a ^= c; a -= rot(c,4); \
1023 b ^= a; b -= rot(a,14); \
1024 c ^= b; c -= rot(b,24); \
1028 * mono_method_get_imt_slot:
1030 * The IMT slot is embedded into AOTed code, so this must return the same value
1031 * for the same method across all executions. This means:
1032 * - pointers shouldn't be used as hash values.
1033 * - mono_metadata_str_hash () should be used for hashing strings.
1036 mono_method_get_imt_slot (MonoMethod *method)
1038 MonoMethodSignature *sig;
1040 guint32 *hashes_start, *hashes;
1044 /* This can be used to stress tests the collision code */
1048 * We do this to simplify generic sharing. It will hurt
1049 * performance in cases where a class implements two different
1050 * instantiations of the same generic interface.
1051 * The code in build_imt_slots () depends on this.
1053 if (method->is_inflated)
1054 method = ((MonoMethodInflated*)method)->declaring;
1056 sig = mono_method_signature (method);
1057 hashes_count = sig->param_count + 4;
1058 hashes_start = malloc (hashes_count * sizeof (guint32));
1059 hashes = hashes_start;
1061 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1062 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1063 method->klass->name_space, method->klass->name, method->name);
1064 g_assert_not_reached ();
1067 /* Initialize hashes */
1068 hashes [0] = mono_metadata_str_hash (method->klass->name);
1069 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1070 hashes [2] = mono_metadata_str_hash (method->name);
1071 hashes [3] = mono_metadata_type_hash (sig->ret);
1072 for (i = 0; i < sig->param_count; i++) {
1073 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1076 /* Setup internal state */
1077 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1079 /* Handle most of the hashes */
1080 while (hashes_count > 3) {
1089 /* Handle the last 3 hashes (all the case statements fall through) */
1090 switch (hashes_count) {
1091 case 3 : c += hashes [2];
1092 case 2 : b += hashes [1];
1093 case 1 : a += hashes [0];
1095 case 0: /* nothing left to add */
1099 free (hashes_start);
1100 /* Report the result */
1101 return c % MONO_IMT_SIZE;
1110 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1111 guint32 imt_slot = mono_method_get_imt_slot (method);
1112 MonoImtBuilderEntry *entry;
1114 if (slot_num >= 0 && imt_slot != slot_num) {
1115 /* we build just a single imt slot and this is not it */
1119 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1120 entry->key = method;
1121 entry->value.vtable_slot = vtable_slot;
1122 entry->next = imt_builder [imt_slot];
1123 if (imt_builder [imt_slot] != NULL) {
1124 entry->children = imt_builder [imt_slot]->children + 1;
1125 if (entry->children == 1) {
1126 mono_stats.imt_slots_with_collisions++;
1127 *imt_collisions_bitmap |= (1 << imt_slot);
1130 entry->children = 0;
1131 mono_stats.imt_used_slots++;
1133 imt_builder [imt_slot] = entry;
1136 char *method_name = mono_method_full_name (method, TRUE);
1137 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1138 method, method_name, imt_slot, vtable_slot, entry->children);
1139 g_free (method_name);
1146 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1148 MonoMethod *method = e->key;
1149 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1153 method->klass->name_space,
1154 method->klass->name,
1157 printf (" * %s: NULL\n", message);
1163 compare_imt_builder_entries (const void *p1, const void *p2) {
1164 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1165 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1167 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1171 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1173 int count = end - start;
1174 int chunk_start = out_array->len;
1177 for (i = start; i < end; ++i) {
1178 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1179 item->key = sorted_array [i]->key;
1180 item->value = sorted_array [i]->value;
1181 item->has_target_code = sorted_array [i]->has_target_code;
1182 item->is_equals = TRUE;
1184 item->check_target_idx = out_array->len + 1;
1186 item->check_target_idx = 0;
1187 g_ptr_array_add (out_array, item);
1190 int middle = start + count / 2;
1191 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1193 item->key = sorted_array [middle]->key;
1194 item->is_equals = FALSE;
1195 g_ptr_array_add (out_array, item);
1196 imt_emit_ir (sorted_array, start, middle, out_array);
1197 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1203 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1204 int number_of_entries = entries->children + 1;
1205 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1206 GPtrArray *result = g_ptr_array_new ();
1207 MonoImtBuilderEntry *current_entry;
1210 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1211 sorted_array [i] = current_entry;
1213 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1215 /*for (i = 0; i < number_of_entries; i++) {
1216 print_imt_entry (" sorted array:", sorted_array [i], i);
1219 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1221 free (sorted_array);
1226 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1228 if (imt_builder_entry != NULL) {
1229 if (imt_builder_entry->children == 0 && !fail_tramp) {
1230 /* No collision, return the vtable slot contents */
1231 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1233 /* Collision, build the thunk */
1234 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1237 result = imt_thunk_builder (vtable, domain,
1238 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1239 for (i = 0; i < imt_ir->len; ++i)
1240 g_free (g_ptr_array_index (imt_ir, i));
1241 g_ptr_array_free (imt_ir, TRUE);
1253 static MonoImtBuilderEntry*
1254 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1257 * LOCKING: requires the loader and domain locks.
1261 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1265 guint32 imt_collisions_bitmap = 0;
1266 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1267 int method_count = 0;
1268 gboolean record_method_count_for_max_collisions = FALSE;
1269 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1272 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1274 for (i = 0; i < klass->interface_offsets_count; ++i) {
1275 MonoClass *iface = klass->interfaces_packed [i];
1276 int interface_offset = klass->interface_offsets_packed [i];
1277 int method_slot_in_interface, vt_slot;
1279 if (mono_class_has_variant_generic_params (iface))
1280 has_variant_iface = TRUE;
1282 vt_slot = interface_offset;
1283 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1286 if (slot_num >= 0 && iface->is_inflated) {
1288 * The imt slot of the method is the same as for its declaring method,
1289 * see the comment in mono_method_get_imt_slot (), so we can
1290 * avoid inflating methods which will be discarded by
1291 * add_imt_builder_entry anyway.
1293 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1294 if (mono_method_get_imt_slot (method) != slot_num) {
1299 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1300 if (method->is_generic) {
1301 has_generic_virtual = TRUE;
1306 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1307 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1312 if (extra_interfaces) {
1313 int interface_offset = klass->vtable_size;
1315 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1316 MonoClass* iface = list_item->data;
1317 int method_slot_in_interface;
1318 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1319 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1320 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1322 interface_offset += iface->method.count;
1325 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1326 /* overwrite the imt slot only if we're building all the entries or if
1327 * we're building this specific one
1329 if (slot_num < 0 || i == slot_num) {
1330 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1333 if (imt_builder [i]) {
1334 MonoImtBuilderEntry *entry;
1336 /* Link entries with imt_builder [i] */
1337 for (entry = entries; entry->next; entry = entry->next) {
1339 MonoMethod *method = (MonoMethod*)entry->key;
1340 char *method_name = mono_method_full_name (method, TRUE);
1341 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1342 g_free (method_name);
1345 entry->next = imt_builder [i];
1346 entries->children += imt_builder [i]->children + 1;
1348 imt_builder [i] = entries;
1351 if (has_generic_virtual || has_variant_iface) {
1353 * There might be collisions later when the the thunk is expanded.
1355 imt_collisions_bitmap |= (1 << i);
1358 * The IMT thunk might be called with an instance of one of the
1359 * generic virtual methods, so has to fallback to the IMT trampoline.
1361 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline ? callbacks.get_imt_trampoline (i) : NULL);
1363 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1366 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1370 if (imt_builder [i] != NULL) {
1371 int methods_in_slot = imt_builder [i]->children + 1;
1372 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1373 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1374 record_method_count_for_max_collisions = TRUE;
1376 method_count += methods_in_slot;
1380 mono_stats.imt_number_of_methods += method_count;
1381 if (record_method_count_for_max_collisions) {
1382 mono_stats.imt_method_count_when_max_collisions = method_count;
1385 for (i = 0; i < MONO_IMT_SIZE; i++) {
1386 MonoImtBuilderEntry* entry = imt_builder [i];
1387 while (entry != NULL) {
1388 MonoImtBuilderEntry* next = entry->next;
1394 /* we OR the bitmap since we may build just a single imt slot at a time */
1395 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1399 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1400 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1404 * mono_vtable_build_imt_slot:
1405 * @vtable: virtual object table struct
1406 * @imt_slot: slot in the IMT table
1408 * Fill the given @imt_slot in the IMT table of @vtable with
1409 * a trampoline or a thunk for the case of collisions.
1410 * This is part of the internal mono API.
1412 * LOCKING: Take the domain lock.
1415 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1417 gpointer *imt = (gpointer*)vtable;
1418 imt -= MONO_IMT_SIZE;
1419 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1421 /* no support for extra interfaces: the proxy objects will need
1422 * to build the complete IMT
1423 * Update and heck needs to ahppen inside the proper domain lock, as all
1424 * the changes made to a MonoVTable.
1426 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1427 mono_domain_lock (vtable->domain);
1428 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1429 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1430 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1431 mono_domain_unlock (vtable->domain);
1432 mono_loader_unlock ();
1437 * The first two free list entries both belong to the wait list: The
1438 * first entry is the pointer to the head of the list and the second
1439 * entry points to the last element. That way appending and removing
1440 * the first element are both O(1) operations.
1442 #ifdef MONO_SMALL_CONFIG
1443 #define NUM_FREE_LISTS 6
1445 #define NUM_FREE_LISTS 12
1447 #define FIRST_FREE_LIST_SIZE 64
1448 #define MAX_WAIT_LENGTH 50
1449 #define THUNK_THRESHOLD 10
1452 * LOCKING: The domain lock must be held.
1455 init_thunk_free_lists (MonoDomain *domain)
1457 if (domain->thunk_free_lists)
1459 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1463 list_index_for_size (int item_size)
1466 int size = FIRST_FREE_LIST_SIZE;
1468 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1477 * mono_method_alloc_generic_virtual_thunk:
1479 * @size: size in bytes
1481 * Allocs size bytes to be used for the code of a generic virtual
1482 * thunk. It's either allocated from the domain's code manager or
1483 * reused from a previously invalidated piece.
1485 * LOCKING: The domain lock must be held.
1488 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1490 static gboolean inited = FALSE;
1491 static int generic_virtual_thunks_size = 0;
1495 MonoThunkFreeList **l;
1497 init_thunk_free_lists (domain);
1499 size += sizeof (guint32);
1500 if (size < sizeof (MonoThunkFreeList))
1501 size = sizeof (MonoThunkFreeList);
1503 i = list_index_for_size (size);
1504 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1505 if ((*l)->size >= size) {
1506 MonoThunkFreeList *item = *l;
1508 return ((guint32*)item) + 1;
1512 /* no suitable item found - search lists of larger sizes */
1513 while (++i < NUM_FREE_LISTS) {
1514 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1517 g_assert (item->size > size);
1518 domain->thunk_free_lists [i] = item->next;
1519 return ((guint32*)item) + 1;
1522 /* still nothing found - allocate it */
1524 mono_counters_register ("Generic virtual thunk bytes",
1525 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1528 generic_virtual_thunks_size += size;
1530 p = mono_domain_code_reserve (domain, size);
1537 * LOCKING: The domain lock must be held.
1540 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1543 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1545 init_thunk_free_lists (domain);
1547 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1548 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1549 int length = item->length;
1552 /* unlink the first item from the wait list */
1553 domain->thunk_free_lists [0] = item->next;
1554 domain->thunk_free_lists [0]->length = length - 1;
1556 i = list_index_for_size (item->size);
1558 /* put it in the free list */
1559 item->next = domain->thunk_free_lists [i];
1560 domain->thunk_free_lists [i] = item;
1564 if (domain->thunk_free_lists [1]) {
1565 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1566 domain->thunk_free_lists [0]->length++;
1568 g_assert (!domain->thunk_free_lists [0]);
1570 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1571 domain->thunk_free_lists [0]->length = 1;
1575 typedef struct _GenericVirtualCase {
1579 struct _GenericVirtualCase *next;
1580 } GenericVirtualCase;
1583 * get_generic_virtual_entries:
1585 * Return IMT entries for the generic virtual method instances and
1586 * variant interface methods for vtable slot
1589 static MonoImtBuilderEntry*
1590 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1592 GenericVirtualCase *list;
1593 MonoImtBuilderEntry *entries;
1595 mono_domain_lock (domain);
1596 if (!domain->generic_virtual_cases)
1597 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1599 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1602 for (; list; list = list->next) {
1603 MonoImtBuilderEntry *entry;
1605 if (list->count < THUNK_THRESHOLD)
1608 entry = g_new0 (MonoImtBuilderEntry, 1);
1609 entry->key = list->method;
1610 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1611 entry->has_target_code = 1;
1613 entry->children = entries->children + 1;
1614 entry->next = entries;
1618 mono_domain_unlock (domain);
1620 /* FIXME: Leaking memory ? */
1625 * mono_method_add_generic_virtual_invocation:
1627 * @vtable_slot: pointer to the vtable slot
1628 * @method: the inflated generic virtual method
1629 * @code: the method's code
1631 * Registers a call via unmanaged code to a generic virtual method
1632 * instantiation or variant interface method. If the number of calls reaches a threshold
1633 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1634 * virtual method thunk.
1637 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1638 gpointer *vtable_slot,
1639 MonoMethod *method, gpointer code)
1641 static gboolean inited = FALSE;
1642 static int num_added = 0;
1644 GenericVirtualCase *gvc, *list;
1645 MonoImtBuilderEntry *entries;
1649 mono_domain_lock (domain);
1650 if (!domain->generic_virtual_cases)
1651 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1653 /* Check whether the case was already added */
1654 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1657 if (gvc->method == method)
1662 /* If not found, make a new one */
1664 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1665 gvc->method = method;
1668 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1670 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1673 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1679 if (++gvc->count == THUNK_THRESHOLD) {
1680 gpointer *old_thunk = *vtable_slot;
1681 gpointer vtable_trampoline = NULL;
1682 gpointer imt_trampoline = NULL;
1684 if ((gpointer)vtable_slot < (gpointer)vtable) {
1685 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1686 int imt_slot = MONO_IMT_SIZE + displacement;
1688 /* Force the rebuild of the thunk at the next call */
1689 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1690 *vtable_slot = imt_trampoline;
1692 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1694 entries = get_generic_virtual_entries (domain, vtable_slot);
1696 sorted = imt_sort_slot_entries (entries);
1698 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1702 MonoImtBuilderEntry *next = entries->next;
1707 for (i = 0; i < sorted->len; ++i)
1708 g_free (g_ptr_array_index (sorted, i));
1709 g_ptr_array_free (sorted, TRUE);
1712 #ifndef __native_client__
1713 /* We don't re-use any thunks as there is a lot of overhead */
1714 /* to deleting and re-using code in Native Client. */
1715 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1716 invalidate_generic_virtual_thunk (domain, old_thunk);
1720 mono_domain_unlock (domain);
1723 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1726 * mono_class_vtable:
1727 * @domain: the application domain
1728 * @class: the class to initialize
1730 * VTables are domain specific because we create domain specific code, and
1731 * they contain the domain specific static class data.
1732 * On failure, NULL is returned, and class->exception_type is set.
1735 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1737 return mono_class_vtable_full (domain, class, FALSE);
1741 * mono_class_vtable_full:
1742 * @domain: the application domain
1743 * @class: the class to initialize
1744 * @raise_on_error if an exception should be raised on failure or not
1746 * VTables are domain specific because we create domain specific code, and
1747 * they contain the domain specific static class data.
1750 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1752 MonoClassRuntimeInfo *runtime_info;
1756 if (class->exception_type) {
1758 mono_raise_exception (mono_class_get_exception_for_failure (class));
1762 /* this check can be inlined in jitted code, too */
1763 runtime_info = class->runtime_info;
1764 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1765 return runtime_info->domain_vtables [domain->domain_id];
1766 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1770 * mono_class_try_get_vtable:
1771 * @domain: the application domain
1772 * @class: the class to initialize
1774 * This function tries to get the associated vtable from @class if
1775 * it was already created.
1778 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1780 MonoClassRuntimeInfo *runtime_info;
1784 runtime_info = class->runtime_info;
1785 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1786 return runtime_info->domain_vtables [domain->domain_id];
1791 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1794 MonoClassRuntimeInfo *runtime_info, *old_info;
1795 MonoClassField *field;
1798 int imt_table_bytes = 0;
1799 guint32 vtable_size, class_size;
1802 gpointer *interface_offsets;
1804 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1805 mono_domain_lock (domain);
1806 runtime_info = class->runtime_info;
1807 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1808 mono_domain_unlock (domain);
1809 mono_loader_unlock ();
1810 return runtime_info->domain_vtables [domain->domain_id];
1812 if (!class->inited || class->exception_type) {
1813 if (!mono_class_init (class) || class->exception_type) {
1814 mono_domain_unlock (domain);
1815 mono_loader_unlock ();
1817 mono_raise_exception (mono_class_get_exception_for_failure (class));
1822 /* Array types require that their element type be valid*/
1823 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1824 MonoClass *element_class = class->element_class;
1825 if (!element_class->inited)
1826 mono_class_init (element_class);
1828 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1829 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1830 mono_class_setup_vtable (element_class);
1832 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1833 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1834 if (class->exception_type == MONO_EXCEPTION_NONE)
1835 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1836 mono_domain_unlock (domain);
1837 mono_loader_unlock ();
1839 mono_raise_exception (mono_class_get_exception_for_failure (class));
1845 * For some classes, mono_class_init () already computed class->vtable_size, and
1846 * that is all that is needed because of the vtable trampolines.
1848 if (!class->vtable_size)
1849 mono_class_setup_vtable (class);
1851 if (class->generic_class && !class->vtable)
1852 mono_class_check_vtable_constraints (class, NULL);
1854 if (class->exception_type) {
1855 mono_domain_unlock (domain);
1856 mono_loader_unlock ();
1858 mono_raise_exception (mono_class_get_exception_for_failure (class));
1863 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1864 if (class->interface_offsets_count) {
1865 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1866 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1867 mono_stats.imt_number_of_tables++;
1868 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1871 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1872 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1875 mono_stats.used_class_count++;
1876 mono_stats.class_vtable_size += vtable_size;
1877 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1880 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1882 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1884 vt->rank = class->rank;
1885 vt->domain = domain;
1887 mono_class_compute_gc_descriptor (class);
1889 * We can't use typed allocation in the non-root domains, since the
1890 * collector needs the GC descriptor stored in the vtable even after
1891 * the mempool containing the vtable is destroyed when the domain is
1892 * unloaded. An alternative might be to allocate vtables in the GC
1893 * heap, but this does not seem to work (it leads to crashes inside
1894 * libgc). If that approach is tried, two gc descriptors need to be
1895 * allocated for each class: one for the root domain, and one for all
1896 * other domains. The second descriptor should contain a bit for the
1897 * vtable field in MonoObject, since we can no longer assume the
1898 * vtable is reachable by other roots after the appdomain is unloaded.
1900 #ifdef HAVE_BOEHM_GC
1901 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1902 vt->gc_descr = GC_NO_DESCRIPTOR;
1905 vt->gc_descr = class->gc_descr;
1907 if ((class_size = mono_class_data_size (class))) {
1908 if (class->has_static_refs) {
1909 gpointer statics_gc_descr;
1911 gsize default_bitmap [4] = {0};
1914 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1915 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1916 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1917 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1918 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1919 if (bitmap != default_bitmap)
1922 vt->data = mono_domain_alloc0 (domain, class_size);
1924 mono_stats.class_static_data_size += class_size;
1929 while ((field = mono_class_get_fields (class, &iter))) {
1930 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1932 if (mono_field_is_deleted (field))
1934 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1935 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1936 if (special_static != SPECIAL_STATIC_NONE) {
1937 guint32 size, offset;
1939 gsize default_bitmap [4] = {0};
1943 if (mono_type_is_reference (field->type)) {
1944 default_bitmap [0] = 1;
1946 bitmap = default_bitmap;
1947 } else if (mono_type_is_struct (field->type)) {
1948 fclass = mono_class_from_mono_type (field->type);
1949 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1951 default_bitmap [0] = 0;
1953 bitmap = default_bitmap;
1955 size = mono_type_size (field->type, &align);
1956 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1957 if (!domain->special_static_fields)
1958 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1959 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1960 if (bitmap != default_bitmap)
1963 * This marks the field as special static to speed up the
1964 * checks in mono_field_static_get/set_value ().
1970 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1971 MonoClass *fklass = mono_class_from_mono_type (field->type);
1972 const char *data = mono_field_get_data (field);
1974 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1975 t = (char*)vt->data + field->offset;
1976 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1979 if (fklass->valuetype) {
1980 memcpy (t, data, mono_class_value_size (fklass, NULL));
1982 /* it's a pointer type: add check */
1983 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1990 vt->max_interface_id = class->max_interface_id;
1991 vt->interface_bitmap = class->interface_bitmap;
1993 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1994 // class->name, class->interface_offsets_count);
1996 if (! ARCH_USE_IMT) {
1997 /* initialize interface offsets */
1998 for (i = 0; i < class->interface_offsets_count; ++i) {
1999 int interface_id = class->interfaces_packed [i]->interface_id;
2000 int slot = class->interface_offsets_packed [i];
2001 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
2005 /* class_vtable_array keeps an array of created vtables
2007 g_ptr_array_add (domain->class_vtable_array, vt);
2008 /* class->runtime_info is protected by the loader lock, both when
2009 * it it enlarged and when it is stored info.
2012 old_info = class->runtime_info;
2013 if (old_info && old_info->max_domain >= domain->domain_id) {
2014 /* someone already created a large enough runtime info */
2015 mono_memory_barrier ();
2016 old_info->domain_vtables [domain->domain_id] = vt;
2018 int new_size = domain->domain_id;
2020 new_size = MAX (new_size, old_info->max_domain);
2022 /* make the new size a power of two */
2024 while (new_size > i)
2027 /* this is a bounded memory retention issue: may want to
2028 * handle it differently when we'll have a rcu-like system.
2030 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2031 runtime_info->max_domain = new_size - 1;
2032 /* copy the stuff from the older info */
2034 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2036 runtime_info->domain_vtables [domain->domain_id] = vt;
2038 mono_memory_barrier ();
2039 class->runtime_info = runtime_info;
2042 /* Initialize vtable */
2043 if (callbacks.get_vtable_trampoline) {
2044 // This also covers the AOT case
2045 for (i = 0; i < class->vtable_size; ++i) {
2046 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2049 mono_class_setup_vtable (class);
2051 for (i = 0; i < class->vtable_size; ++i) {
2054 if ((cm = class->vtable [i]))
2055 vt->vtable [i] = arch_create_jit_trampoline (cm);
2059 if (ARCH_USE_IMT && imt_table_bytes) {
2060 /* Now that the vtable is full, we can actually fill up the IMT */
2061 if (callbacks.get_imt_trampoline) {
2062 /* lazy construction of the IMT entries enabled */
2063 for (i = 0; i < MONO_IMT_SIZE; ++i)
2064 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2066 build_imt (class, vt, domain, interface_offsets, NULL);
2070 mono_domain_unlock (domain);
2071 mono_loader_unlock ();
2073 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2074 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2075 mono_raise_exception (mono_class_get_exception_for_failure (class));
2077 /* make sure the parent is initialized */
2078 /*FIXME shouldn't this fail the current type?*/
2080 mono_class_vtable_full (domain, class->parent, raise_on_error);
2082 /*FIXME check for OOM*/
2083 vt->type = mono_type_get_object (domain, &class->byval_arg);
2084 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2085 /* This is unregistered in
2086 unregister_vtable_reflection_type() in
2088 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2089 if (class->contextbound)
2098 * mono_class_proxy_vtable:
2099 * @domain: the application domain
2100 * @remove_class: the remote class
2102 * Creates a vtable for transparent proxies. It is basically
2103 * a copy of the real vtable of the class wrapped in @remote_class,
2104 * but all function pointers invoke the remoting functions, and
2105 * vtable->klass points to the transparent proxy class, and not to @class.
2108 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2111 MonoVTable *vt, *pvt;
2112 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2114 GSList *extra_interfaces = NULL;
2115 MonoClass *class = remote_class->proxy_class;
2116 gpointer *interface_offsets;
2120 #ifdef COMPRESSED_INTERFACE_BITMAP
2124 vt = mono_class_vtable (domain, class);
2125 g_assert (vt); /*FIXME property handle failure*/
2126 max_interface_id = vt->max_interface_id;
2128 /* Calculate vtable space for extra interfaces */
2129 for (j = 0; j < remote_class->interface_count; j++) {
2130 MonoClass* iclass = remote_class->interfaces[j];
2134 /*FIXME test for interfaces with variant generic arguments*/
2135 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2136 continue; /* interface implemented by the class */
2137 if (g_slist_find (extra_interfaces, iclass))
2140 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2142 method_count = mono_class_num_methods (iclass);
2144 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2145 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2147 for (i = 0; i < ifaces->len; ++i) {
2148 MonoClass *ic = g_ptr_array_index (ifaces, i);
2149 /*FIXME test for interfaces with variant generic arguments*/
2150 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2151 continue; /* interface implemented by the class */
2152 if (g_slist_find (extra_interfaces, ic))
2154 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2155 method_count += mono_class_num_methods (ic);
2157 g_ptr_array_free (ifaces, TRUE);
2160 extra_interface_vtsize += method_count * sizeof (gpointer);
2161 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2165 mono_stats.imt_number_of_tables++;
2166 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2167 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2168 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2170 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2171 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2174 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2176 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2178 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2180 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2181 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2183 pvt->klass = mono_defaults.transparent_proxy_class;
2184 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2185 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2187 /* initialize vtable */
2188 mono_class_setup_vtable (class);
2189 for (i = 0; i < class->vtable_size; ++i) {
2192 if ((cm = class->vtable [i]))
2193 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2195 pvt->vtable [i] = NULL;
2198 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2199 /* create trampolines for abstract methods */
2200 for (k = class; k; k = k->parent) {
2202 gpointer iter = NULL;
2203 while ((m = mono_class_get_methods (k, &iter)))
2204 if (!pvt->vtable [m->slot])
2205 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2209 pvt->max_interface_id = max_interface_id;
2210 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2211 #ifdef COMPRESSED_INTERFACE_BITMAP
2212 bitmap = g_malloc0 (bsize);
2214 bitmap = mono_domain_alloc0 (domain, bsize);
2217 if (! ARCH_USE_IMT) {
2218 /* initialize interface offsets */
2219 for (i = 0; i < class->interface_offsets_count; ++i) {
2220 int interface_id = class->interfaces_packed [i]->interface_id;
2221 int slot = class->interface_offsets_packed [i];
2222 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2225 for (i = 0; i < class->interface_offsets_count; ++i) {
2226 int interface_id = class->interfaces_packed [i]->interface_id;
2227 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2230 if (extra_interfaces) {
2231 int slot = class->vtable_size;
2237 /* Create trampolines for the methods of the interfaces */
2238 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2239 interf = list_item->data;
2241 if (! ARCH_USE_IMT) {
2242 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2244 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2248 while ((cm = mono_class_get_methods (interf, &iter)))
2249 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2251 slot += mono_class_num_methods (interf);
2253 if (! ARCH_USE_IMT) {
2254 g_slist_free (extra_interfaces);
2259 /* Now that the vtable is full, we can actually fill up the IMT */
2260 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2261 if (extra_interfaces) {
2262 g_slist_free (extra_interfaces);
2266 #ifdef COMPRESSED_INTERFACE_BITMAP
2267 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2268 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2269 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2272 pvt->interface_bitmap = bitmap;
2278 * mono_class_field_is_special_static:
2280 * Returns whether @field is a thread/context static field.
2283 mono_class_field_is_special_static (MonoClassField *field)
2285 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2287 if (mono_field_is_deleted (field))
2289 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2290 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2297 * mono_class_field_get_special_static_type:
2298 * @field: The MonoClassField describing the field.
2300 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2301 * SPECIAL_STATIC_NONE otherwise.
2304 mono_class_field_get_special_static_type (MonoClassField *field)
2306 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2307 return SPECIAL_STATIC_NONE;
2308 if (mono_field_is_deleted (field))
2309 return SPECIAL_STATIC_NONE;
2310 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2311 return field_is_special_static (field->parent, field);
2312 return SPECIAL_STATIC_NONE;
2316 * mono_class_has_special_static_fields:
2318 * Returns whenever @klass has any thread/context static fields.
2321 mono_class_has_special_static_fields (MonoClass *klass)
2323 MonoClassField *field;
2327 while ((field = mono_class_get_fields (klass, &iter))) {
2328 g_assert (field->parent == klass);
2329 if (mono_class_field_is_special_static (field))
2337 * create_remote_class_key:
2338 * Creates an array of pointers that can be used as a hash key for a remote class.
2339 * The first element of the array is the number of pointers.
2342 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2347 if (remote_class == NULL) {
2348 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2349 key = g_malloc (sizeof(gpointer) * 3);
2350 key [0] = GINT_TO_POINTER (2);
2351 key [1] = mono_defaults.marshalbyrefobject_class;
2352 key [2] = extra_class;
2354 key = g_malloc (sizeof(gpointer) * 2);
2355 key [0] = GINT_TO_POINTER (1);
2356 key [1] = extra_class;
2359 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2360 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2361 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2362 key [1] = remote_class->proxy_class;
2364 // Keep the list of interfaces sorted
2365 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2366 if (extra_class && remote_class->interfaces [i] > extra_class) {
2367 key [j++] = extra_class;
2370 key [j] = remote_class->interfaces [i];
2373 key [j] = extra_class;
2375 // Replace the old class. The interface list is the same
2376 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2377 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2378 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2379 for (i = 0; i < remote_class->interface_count; i++)
2380 key [2 + i] = remote_class->interfaces [i];
2388 * copy_remote_class_key:
2390 * Make a copy of KEY in the domain and return the copy.
2393 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2395 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2396 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2398 memcpy (mp_key, key, key_size);
2404 * mono_remote_class:
2405 * @domain: the application domain
2406 * @class_name: name of the remote class
2408 * Creates and initializes a MonoRemoteClass object for a remote type.
2410 * Can raise an exception on failure.
2413 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2416 MonoRemoteClass *rc;
2417 gpointer* key, *mp_key;
2420 key = create_remote_class_key (NULL, proxy_class);
2422 mono_domain_lock (domain);
2423 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2427 mono_domain_unlock (domain);
2431 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2432 if (!mono_error_ok (&error)) {
2434 mono_domain_unlock (domain);
2435 mono_error_raise_exception (&error);
2438 mp_key = copy_remote_class_key (domain, key);
2442 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2443 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2444 rc->interface_count = 1;
2445 rc->interfaces [0] = proxy_class;
2446 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2448 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2449 rc->interface_count = 0;
2450 rc->proxy_class = proxy_class;
2453 rc->default_vtable = NULL;
2454 rc->xdomain_vtable = NULL;
2455 rc->proxy_class_name = name;
2456 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2458 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2460 mono_domain_unlock (domain);
2465 * clone_remote_class:
2466 * Creates a copy of the remote_class, adding the provided class or interface
2468 static MonoRemoteClass*
2469 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2471 MonoRemoteClass *rc;
2472 gpointer* key, *mp_key;
2474 key = create_remote_class_key (remote_class, extra_class);
2475 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2481 mp_key = copy_remote_class_key (domain, key);
2485 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2487 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2488 rc->proxy_class = remote_class->proxy_class;
2489 rc->interface_count = remote_class->interface_count + 1;
2491 // Keep the list of interfaces sorted, since the hash key of
2492 // the remote class depends on this
2493 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2494 if (remote_class->interfaces [i] > extra_class && i == j)
2495 rc->interfaces [j++] = extra_class;
2496 rc->interfaces [j] = remote_class->interfaces [i];
2499 rc->interfaces [j] = extra_class;
2501 // Replace the old class. The interface array is the same
2502 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2503 rc->proxy_class = extra_class;
2504 rc->interface_count = remote_class->interface_count;
2505 if (rc->interface_count > 0)
2506 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2509 rc->default_vtable = NULL;
2510 rc->xdomain_vtable = NULL;
2511 rc->proxy_class_name = remote_class->proxy_class_name;
2513 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2519 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2521 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2522 mono_domain_lock (domain);
2523 if (rp->target_domain_id != -1) {
2524 if (remote_class->xdomain_vtable == NULL)
2525 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2526 mono_domain_unlock (domain);
2527 mono_loader_unlock ();
2528 return remote_class->xdomain_vtable;
2530 if (remote_class->default_vtable == NULL) {
2533 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2534 klass = mono_class_from_mono_type (type);
2535 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2536 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2538 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2541 mono_domain_unlock (domain);
2542 mono_loader_unlock ();
2543 return remote_class->default_vtable;
2547 * mono_upgrade_remote_class:
2548 * @domain: the application domain
2549 * @tproxy: the proxy whose remote class has to be upgraded.
2550 * @klass: class to which the remote class can be casted.
2552 * Updates the vtable of the remote class by adding the necessary method slots
2553 * and interface offsets so it can be safely casted to klass. klass can be a
2554 * class or an interface.
2557 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2559 MonoTransparentProxy *tproxy;
2560 MonoRemoteClass *remote_class;
2561 gboolean redo_vtable;
2563 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2564 mono_domain_lock (domain);
2566 tproxy = (MonoTransparentProxy*) proxy_object;
2567 remote_class = tproxy->remote_class;
2569 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2572 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2573 if (remote_class->interfaces [i] == klass)
2574 redo_vtable = FALSE;
2577 redo_vtable = (remote_class->proxy_class != klass);
2581 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2582 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2585 mono_domain_unlock (domain);
2586 mono_loader_unlock ();
2591 * mono_object_get_virtual_method:
2592 * @obj: object to operate on.
2595 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2596 * the instance of a callvirt of method.
2599 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2602 MonoMethod **vtable;
2604 MonoMethod *res = NULL;
2606 klass = mono_object_class (obj);
2607 if (klass == mono_defaults.transparent_proxy_class) {
2608 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2614 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2617 mono_class_setup_vtable (klass);
2618 vtable = klass->vtable;
2620 if (method->slot == -1) {
2621 /* method->slot might not be set for instances of generic methods */
2622 if (method->is_inflated) {
2623 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2624 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2627 g_assert_not_reached ();
2631 /* check method->slot is a valid index: perform isinstance? */
2632 if (method->slot != -1) {
2633 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2635 gboolean variance_used = FALSE;
2636 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2637 g_assert (iface_offset > 0);
2638 res = vtable [iface_offset + method->slot];
2641 res = vtable [method->slot];
2646 /* It may be an interface, abstract class method or generic method */
2647 if (!res || mono_method_signature (res)->generic_param_count)
2650 /* generic methods demand invoke_with_check */
2651 if (mono_method_signature (res)->generic_param_count)
2652 res = mono_marshal_get_remoting_invoke_with_check (res);
2655 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2656 res = mono_cominterop_get_invoke (res);
2659 res = mono_marshal_get_remoting_invoke (res);
2662 if (method->is_inflated) {
2663 /* Have to inflate the result */
2664 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2674 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2676 g_error ("runtime invoke called on uninitialized runtime");
2680 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2683 * mono_runtime_invoke:
2684 * @method: method to invoke
2685 * @obJ: object instance
2686 * @params: arguments to the method
2687 * @exc: exception information.
2689 * Invokes the method represented by @method on the object @obj.
2691 * obj is the 'this' pointer, it should be NULL for static
2692 * methods, a MonoObject* for object instances and a pointer to
2693 * the value type for value types.
2695 * The params array contains the arguments to the method with the
2696 * same convention: MonoObject* pointers for object instances and
2697 * pointers to the value type otherwise.
2699 * From unmanaged code you'll usually use the
2700 * mono_runtime_invoke() variant.
2702 * Note that this function doesn't handle virtual methods for
2703 * you, it will exec the exact method you pass: we still need to
2704 * expose a function to lookup the derived class implementation
2705 * of a virtual method (there are examples of this in the code,
2708 * You can pass NULL as the exc argument if you don't want to
2709 * catch exceptions, otherwise, *exc will be set to the exception
2710 * thrown, if any. if an exception is thrown, you can't use the
2711 * MonoObject* result from the function.
2713 * If the method returns a value type, it is boxed in an object
2717 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2721 if (mono_runtime_get_no_exec ())
2722 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2724 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2725 mono_profiler_method_start_invoke (method);
2727 result = default_mono_runtime_invoke (method, obj, params, exc);
2729 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2730 mono_profiler_method_end_invoke (method);
2736 * mono_method_get_unmanaged_thunk:
2737 * @method: method to generate a thunk for.
2739 * Returns an unmanaged->managed thunk that can be used to call
2740 * a managed method directly from C.
2742 * The thunk's C signature closely matches the managed signature:
2744 * C#: public bool Equals (object obj);
2745 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2746 * MonoObject*, MonoException**);
2748 * The 1st ("this") parameter must not be used with static methods:
2750 * C#: public static bool ReferenceEquals (object a, object b);
2751 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2754 * The last argument must be a non-null pointer of a MonoException* pointer.
2755 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2756 * exception has been thrown in managed code. Otherwise it will point
2757 * to the MonoException* caught by the thunk. In this case, the result of
2758 * the thunk is undefined:
2760 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2761 * MonoException *ex = NULL;
2762 * Equals func = mono_method_get_unmanaged_thunk (method);
2763 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2765 * // handle exception
2768 * The calling convention of the thunk matches the platform's default
2769 * convention. This means that under Windows, C declarations must
2770 * contain the __stdcall attribute:
2772 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2773 * MonoObject*, MonoException**);
2777 * Value type arguments and return values are treated as they were objects:
2779 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2780 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2782 * Arguments must be properly boxed upon trunk's invocation, while return
2783 * values must be unboxed.
2786 mono_method_get_unmanaged_thunk (MonoMethod *method)
2788 method = mono_marshal_get_thunk_invoke_wrapper (method);
2789 return mono_compile_method (method);
2793 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2797 /* object fields cannot be byref, so we don't need a
2799 gpointer *p = (gpointer*)dest;
2806 case MONO_TYPE_BOOLEAN:
2808 case MONO_TYPE_U1: {
2809 guint8 *p = (guint8*)dest;
2810 *p = value ? *(guint8*)value : 0;
2815 case MONO_TYPE_CHAR: {
2816 guint16 *p = (guint16*)dest;
2817 *p = value ? *(guint16*)value : 0;
2820 #if SIZEOF_VOID_P == 4
2825 case MONO_TYPE_U4: {
2826 gint32 *p = (gint32*)dest;
2827 *p = value ? *(gint32*)value : 0;
2830 #if SIZEOF_VOID_P == 8
2835 case MONO_TYPE_U8: {
2836 gint64 *p = (gint64*)dest;
2837 *p = value ? *(gint64*)value : 0;
2840 case MONO_TYPE_R4: {
2841 float *p = (float*)dest;
2842 *p = value ? *(float*)value : 0;
2845 case MONO_TYPE_R8: {
2846 double *p = (double*)dest;
2847 *p = value ? *(double*)value : 0;
2850 case MONO_TYPE_STRING:
2851 case MONO_TYPE_SZARRAY:
2852 case MONO_TYPE_CLASS:
2853 case MONO_TYPE_OBJECT:
2854 case MONO_TYPE_ARRAY:
2855 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2857 case MONO_TYPE_FNPTR:
2858 case MONO_TYPE_PTR: {
2859 gpointer *p = (gpointer*)dest;
2860 *p = deref_pointer? *(gpointer*)value: value;
2863 case MONO_TYPE_VALUETYPE:
2864 /* note that 't' and 'type->type' can be different */
2865 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2866 t = mono_class_enum_basetype (type->data.klass)->type;
2869 MonoClass *class = mono_class_from_mono_type (type);
2870 int size = mono_class_value_size (class, NULL);
2872 memset (dest, 0, size);
2874 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2877 case MONO_TYPE_GENERICINST:
2878 t = type->data.generic_class->container_class->byval_arg.type;
2881 g_warning ("got type %x", type->type);
2882 g_assert_not_reached ();
2887 * mono_field_set_value:
2888 * @obj: Instance object
2889 * @field: MonoClassField describing the field to set
2890 * @value: The value to be set
2892 * Sets the value of the field described by @field in the object instance @obj
2893 * to the value passed in @value. This method should only be used for instance
2894 * fields. For static fields, use mono_field_static_set_value.
2896 * The value must be on the native format of the field type.
2899 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2903 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2905 dest = (char*)obj + field->offset;
2906 set_value (field->type, dest, value, FALSE);
2910 * mono_field_static_set_value:
2911 * @field: MonoClassField describing the field to set
2912 * @value: The value to be set
2914 * Sets the value of the static field described by @field
2915 * to the value passed in @value.
2917 * The value must be on the native format of the field type.
2920 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2924 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2925 /* you cant set a constant! */
2926 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2928 if (field->offset == -1) {
2929 /* Special static */
2932 mono_domain_lock (vt->domain);
2933 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2934 mono_domain_unlock (vt->domain);
2935 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2937 dest = (char*)vt->data + field->offset;
2939 set_value (field->type, dest, value, FALSE);
2942 /* Used by the debugger */
2944 mono_vtable_get_static_field_data (MonoVTable *vt)
2950 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2954 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2955 if (field->offset == -1) {
2956 /* Special static */
2959 mono_domain_lock (vt->domain);
2960 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2961 mono_domain_unlock (vt->domain);
2962 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2964 src = (guint8*)vt->data + field->offset;
2967 src = (guint8*)obj + field->offset;
2974 * mono_field_get_value:
2975 * @obj: Object instance
2976 * @field: MonoClassField describing the field to fetch information from
2977 * @value: pointer to the location where the value will be stored
2979 * Use this routine to get the value of the field @field in the object
2982 * The pointer provided by value must be of the field type, for reference
2983 * types this is a MonoObject*, for value types its the actual pointer to
2988 * mono_field_get_value (obj, int_field, &i);
2991 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2997 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2999 src = (char*)obj + field->offset;
3000 set_value (field->type, value, src, TRUE);
3004 * mono_field_get_value_object:
3005 * @domain: domain where the object will be created (if boxing)
3006 * @field: MonoClassField describing the field to fetch information from
3007 * @obj: The object instance for the field.
3009 * Returns: a new MonoObject with the value from the given field. If the
3010 * field represents a value type, the value is boxed.
3014 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3018 MonoVTable *vtable = NULL;
3020 gboolean is_static = FALSE;
3021 gboolean is_ref = FALSE;
3022 gboolean is_literal = FALSE;
3023 gboolean is_ptr = FALSE;
3025 MonoType *type = mono_field_get_type_checked (field, &error);
3027 if (!mono_error_ok (&error))
3028 mono_error_raise_exception (&error);
3030 switch (type->type) {
3031 case MONO_TYPE_STRING:
3032 case MONO_TYPE_OBJECT:
3033 case MONO_TYPE_CLASS:
3034 case MONO_TYPE_ARRAY:
3035 case MONO_TYPE_SZARRAY:
3040 case MONO_TYPE_BOOLEAN:
3043 case MONO_TYPE_CHAR:
3052 case MONO_TYPE_VALUETYPE:
3053 is_ref = type->byref;
3055 case MONO_TYPE_GENERICINST:
3056 is_ref = !mono_type_generic_inst_is_valuetype (type);
3062 g_error ("type 0x%x not handled in "
3063 "mono_field_get_value_object", type->type);
3067 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3070 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3074 vtable = mono_class_vtable (domain, field->parent);
3076 char *name = mono_type_get_full_name (field->parent);
3077 /*FIXME extend this to use the MonoError api*/
3078 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3082 if (!vtable->initialized)
3083 mono_runtime_class_init (vtable);
3091 get_default_field_value (domain, field, &o);
3092 } else if (is_static) {
3093 mono_field_static_get_value (vtable, field, &o);
3095 mono_field_get_value (obj, field, &o);
3101 static MonoMethod *m;
3107 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3108 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3114 get_default_field_value (domain, field, v);
3115 } else if (is_static) {
3116 mono_field_static_get_value (vtable, field, v);
3118 mono_field_get_value (obj, field, v);
3121 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3123 args [1] = mono_type_get_object (mono_domain_get (), type);
3125 return mono_runtime_invoke (m, NULL, args, NULL);
3128 /* boxed value type */
3129 klass = mono_class_from_mono_type (type);
3131 if (mono_class_is_nullable (klass))
3132 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3134 o = mono_object_new (domain, klass);
3135 v = ((gchar *) o) + sizeof (MonoObject);
3138 get_default_field_value (domain, field, v);
3139 } else if (is_static) {
3140 mono_field_static_get_value (vtable, field, v);
3142 mono_field_get_value (obj, field, v);
3149 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3152 const char *p = blob;
3153 mono_metadata_decode_blob_size (p, &p);
3156 case MONO_TYPE_BOOLEAN:
3159 *(guint8 *) value = *p;
3161 case MONO_TYPE_CHAR:
3164 *(guint16*) value = read16 (p);
3168 *(guint32*) value = read32 (p);
3172 *(guint64*) value = read64 (p);
3175 readr4 (p, (float*) value);
3178 readr8 (p, (double*) value);
3180 case MONO_TYPE_STRING:
3181 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3183 case MONO_TYPE_CLASS:
3184 *(gpointer*) value = NULL;
3188 g_warning ("type 0x%02x should not be in constant table", type);
3194 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3196 MonoTypeEnum def_type;
3199 data = mono_class_get_field_default_value (field, &def_type);
3200 mono_get_constant_value_from_blob (domain, def_type, data, value);
3204 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3208 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3210 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3211 get_default_field_value (vt->domain, field, value);
3215 if (field->offset == -1) {
3216 /* Special static */
3217 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3218 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3220 src = (char*)vt->data + field->offset;
3222 set_value (field->type, value, src, TRUE);
3226 * mono_field_static_get_value:
3227 * @vt: vtable to the object
3228 * @field: MonoClassField describing the field to fetch information from
3229 * @value: where the value is returned
3231 * Use this routine to get the value of the static field @field value.
3233 * The pointer provided by value must be of the field type, for reference
3234 * types this is a MonoObject*, for value types its the actual pointer to
3239 * mono_field_static_get_value (vt, int_field, &i);
3242 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3244 return mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3248 * mono_property_set_value:
3249 * @prop: MonoProperty to set
3250 * @obj: instance object on which to act
3251 * @params: parameters to pass to the propery
3252 * @exc: optional exception
3254 * Invokes the property's set method with the given arguments on the
3255 * object instance obj (or NULL for static properties).
3257 * You can pass NULL as the exc argument if you don't want to
3258 * catch exceptions, otherwise, *exc will be set to the exception
3259 * thrown, if any. if an exception is thrown, you can't use the
3260 * MonoObject* result from the function.
3263 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3265 default_mono_runtime_invoke (prop->set, obj, params, exc);
3269 * mono_property_get_value:
3270 * @prop: MonoProperty to fetch
3271 * @obj: instance object on which to act
3272 * @params: parameters to pass to the propery
3273 * @exc: optional exception
3275 * Invokes the property's get method with the given arguments on the
3276 * object instance obj (or NULL for static properties).
3278 * You can pass NULL as the exc argument if you don't want to
3279 * catch exceptions, otherwise, *exc will be set to the exception
3280 * thrown, if any. if an exception is thrown, you can't use the
3281 * MonoObject* result from the function.
3283 * Returns: the value from invoking the get method on the property.
3286 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3288 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3292 * mono_nullable_init:
3293 * @buf: The nullable structure to initialize.
3294 * @value: the value to initialize from
3295 * @klass: the type for the object
3297 * Initialize the nullable structure pointed to by @buf from @value which
3298 * should be a boxed value type. The size of @buf should be able to hold
3299 * as much data as the @klass->instance_size (which is the number of bytes
3300 * that will be copies).
3302 * Since Nullables have variable structure, we can not define a C
3303 * structure for them.
3306 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3308 MonoClass *param_class = klass->cast_class;
3310 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3311 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3313 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3315 if (param_class->has_references)
3316 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3318 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3320 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3325 * mono_nullable_box:
3326 * @buf: The buffer representing the data to be boxed
3327 * @klass: the type to box it as.
3329 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3333 mono_nullable_box (guint8 *buf, MonoClass *klass)
3335 MonoClass *param_class = klass->cast_class;
3337 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3338 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3340 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3341 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3342 if (param_class->has_references)
3343 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3345 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3353 * mono_get_delegate_invoke:
3354 * @klass: The delegate class
3356 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3359 mono_get_delegate_invoke (MonoClass *klass)
3363 /* This is called at runtime, so avoid the slower search in metadata */
3364 mono_class_setup_methods (klass);
3365 if (klass->exception_type)
3367 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3372 * mono_runtime_delegate_invoke:
3373 * @delegate: pointer to a delegate object.
3374 * @params: parameters for the delegate.
3375 * @exc: Pointer to the exception result.
3377 * Invokes the delegate method @delegate with the parameters provided.
3379 * You can pass NULL as the exc argument if you don't want to
3380 * catch exceptions, otherwise, *exc will be set to the exception
3381 * thrown, if any. if an exception is thrown, you can't use the
3382 * MonoObject* result from the function.
3385 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3389 im = mono_get_delegate_invoke (delegate->vtable->klass);
3392 return mono_runtime_invoke (im, delegate, params, exc);
3395 static char **main_args = NULL;
3396 static int num_main_args;
3399 * mono_runtime_get_main_args:
3401 * Returns: a MonoArray with the arguments passed to the main program
3404 mono_runtime_get_main_args (void)
3408 MonoDomain *domain = mono_domain_get ();
3413 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3415 for (i = 0; i < num_main_args; ++i)
3416 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3422 free_main_args (void)
3426 for (i = 0; i < num_main_args; ++i)
3427 g_free (main_args [i]);
3432 * mono_runtime_run_main:
3433 * @method: the method to start the application with (usually Main)
3434 * @argc: number of arguments from the command line
3435 * @argv: array of strings from the command line
3436 * @exc: excetption results
3438 * Execute a standard Main() method (argc/argv contains the
3439 * executable name). This method also sets the command line argument value
3440 * needed by System.Environment.
3445 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3449 MonoArray *args = NULL;
3450 MonoDomain *domain = mono_domain_get ();
3451 gchar *utf8_fullpath;
3452 MonoMethodSignature *sig;
3454 g_assert (method != NULL);
3456 mono_thread_set_main (mono_thread_current ());
3458 main_args = g_new0 (char*, argc);
3459 num_main_args = argc;
3461 if (!g_path_is_absolute (argv [0])) {
3462 gchar *basename = g_path_get_basename (argv [0]);
3463 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3467 utf8_fullpath = mono_utf8_from_external (fullpath);
3468 if(utf8_fullpath == NULL) {
3469 /* Printing the arg text will cause glib to
3470 * whinge about "Invalid UTF-8", but at least
3471 * its relevant, and shows the problem text
3474 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3475 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3482 utf8_fullpath = mono_utf8_from_external (argv[0]);
3483 if(utf8_fullpath == NULL) {
3484 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3485 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3490 main_args [0] = utf8_fullpath;
3492 for (i = 1; i < argc; ++i) {
3495 utf8_arg=mono_utf8_from_external (argv[i]);
3496 if(utf8_arg==NULL) {
3497 /* Ditto the comment about Invalid UTF-8 here */
3498 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3499 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3503 main_args [i] = utf8_arg;
3508 sig = mono_method_signature (method);
3510 g_print ("Unable to load Main method.\n");
3514 if (sig->param_count) {
3515 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3516 for (i = 0; i < argc; ++i) {
3517 /* The encodings should all work, given that
3518 * we've checked all these args for the
3521 gchar *str = mono_utf8_from_external (argv [i]);
3522 MonoString *arg = mono_string_new (domain, str);
3523 mono_array_setref (args, i, arg);
3527 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3530 mono_assembly_set_main (method->klass->image->assembly);
3532 return mono_runtime_exec_main (method, args, exc);
3536 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3538 static MonoMethod *serialize_method;
3543 if (!serialize_method) {
3544 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3545 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3548 if (!serialize_method) {
3553 g_assert (!mono_object_class (obj)->marshalbyref);
3557 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3565 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3567 static MonoMethod *deserialize_method;
3572 if (!deserialize_method) {
3573 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3574 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3576 if (!deserialize_method) {
3583 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3591 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3593 static MonoMethod *get_proxy_method;
3595 MonoDomain *domain = mono_domain_get ();
3596 MonoRealProxy *real_proxy;
3597 MonoReflectionType *reflection_type;
3598 MonoTransparentProxy *transparent_proxy;
3600 if (!get_proxy_method)
3601 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3603 g_assert (obj->vtable->klass->marshalbyref);
3605 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3606 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3608 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3609 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3612 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3616 return (MonoObject*) transparent_proxy;
3620 * mono_object_xdomain_representation
3622 * @target_domain: a domain
3623 * @exc: pointer to a MonoObject*
3625 * Creates a representation of obj in the domain target_domain. This
3626 * is either a copy of obj arrived through via serialization and
3627 * deserialization or a proxy, depending on whether the object is
3628 * serializable or marshal by ref. obj must not be in target_domain.
3630 * If the object cannot be represented in target_domain, NULL is
3631 * returned and *exc is set to an appropriate exception.
3634 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3636 MonoObject *deserialized = NULL;
3637 gboolean failure = FALSE;
3641 if (mono_object_class (obj)->marshalbyref) {
3642 deserialized = make_transparent_proxy (obj, &failure, exc);
3644 MonoDomain *domain = mono_domain_get ();
3645 MonoObject *serialized;
3647 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3648 serialized = serialize_object (obj, &failure, exc);
3649 mono_domain_set_internal_with_options (target_domain, FALSE);
3651 deserialized = deserialize_object (serialized, &failure, exc);
3652 if (domain != target_domain)
3653 mono_domain_set_internal_with_options (domain, FALSE);
3656 return deserialized;
3659 /* Used in call_unhandled_exception_delegate */
3661 create_unhandled_exception_eventargs (MonoObject *exc)
3665 MonoMethod *method = NULL;
3666 MonoBoolean is_terminating = TRUE;
3669 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3672 mono_class_init (klass);
3674 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3675 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3679 args [1] = &is_terminating;
3681 obj = mono_object_new (mono_domain_get (), klass);
3682 mono_runtime_invoke (method, obj, args, NULL);
3687 /* Used in mono_unhandled_exception */
3689 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3690 MonoObject *e = NULL;
3692 MonoDomain *current_domain = mono_domain_get ();
3694 if (domain != current_domain)
3695 mono_domain_set_internal_with_options (domain, FALSE);
3697 g_assert (domain == mono_object_domain (domain->domain));
3699 if (mono_object_domain (exc) != domain) {
3700 MonoObject *serialization_exc;
3702 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3704 if (serialization_exc) {
3706 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3709 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3710 "System.Runtime.Serialization", "SerializationException",
3711 "Could not serialize unhandled exception.");
3715 g_assert (mono_object_domain (exc) == domain);
3717 pa [0] = domain->domain;
3718 pa [1] = create_unhandled_exception_eventargs (exc);
3719 mono_runtime_delegate_invoke (delegate, pa, &e);
3721 if (domain != current_domain)
3722 mono_domain_set_internal_with_options (current_domain, FALSE);
3726 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3727 if (!mono_error_ok (&error)) {
3728 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3729 mono_error_cleanup (&error);
3731 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3737 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3740 * mono_runtime_unhandled_exception_policy_set:
3741 * @policy: the new policy
3743 * This is a VM internal routine.
3745 * Sets the runtime policy for handling unhandled exceptions.
3748 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3749 runtime_unhandled_exception_policy = policy;
3753 * mono_runtime_unhandled_exception_policy_get:
3755 * This is a VM internal routine.
3757 * Gets the runtime policy for handling unhandled exceptions.
3759 MonoRuntimeUnhandledExceptionPolicy
3760 mono_runtime_unhandled_exception_policy_get (void) {
3761 return runtime_unhandled_exception_policy;
3765 * mono_unhandled_exception:
3766 * @exc: exception thrown
3768 * This is a VM internal routine.
3770 * We call this function when we detect an unhandled exception
3771 * in the default domain.
3773 * It invokes the * UnhandledException event in AppDomain or prints
3774 * a warning to the console
3777 mono_unhandled_exception (MonoObject *exc)
3779 MonoDomain *current_domain = mono_domain_get ();
3780 MonoDomain *root_domain = mono_get_root_domain ();
3781 MonoClassField *field;
3782 MonoObject *current_appdomain_delegate;
3783 MonoObject *root_appdomain_delegate;
3785 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3786 "UnhandledException");
3789 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3790 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3791 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3792 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3793 if (current_domain != root_domain) {
3794 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3796 current_appdomain_delegate = NULL;
3799 /* set exitcode only if we will abort the process */
3801 mono_environment_exitcode_set (1);
3802 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3803 mono_print_unhandled_exception (exc);
3805 if (root_appdomain_delegate) {
3806 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3808 if (current_appdomain_delegate) {
3809 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3816 * mono_runtime_exec_managed_code:
3817 * @domain: Application domain
3818 * @main_func: function to invoke from the execution thread
3819 * @main_args: parameter to the main_func
3821 * Launch a new thread to execute a function
3823 * main_func is called back from the thread with main_args as the
3824 * parameter. The callback function is expected to start Main()
3825 * eventually. This function then waits for all managed threads to
3827 * It is not necesseray anymore to execute managed code in a subthread,
3828 * so this function should not be used anymore by default: just
3829 * execute the code and then call mono_thread_manage ().
3832 mono_runtime_exec_managed_code (MonoDomain *domain,
3833 MonoMainThreadFunc main_func,
3836 mono_thread_create (domain, main_func, main_args);
3838 mono_thread_manage ();
3842 * Execute a standard Main() method (args doesn't contain the
3846 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3851 MonoCustomAttrInfo* cinfo;
3852 gboolean has_stathread_attribute;
3853 MonoInternalThread* thread = mono_thread_internal_current ();
3859 domain = mono_object_domain (args);
3860 if (!domain->entry_assembly) {
3862 MonoAssembly *assembly;
3864 assembly = method->klass->image->assembly;
3865 domain->entry_assembly = assembly;
3866 /* Domains created from another domain already have application_base and configuration_file set */
3867 if (domain->setup->application_base == NULL) {
3868 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3871 if (domain->setup->configuration_file == NULL) {
3872 str = g_strconcat (assembly->image->name, ".config", NULL);
3873 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3875 mono_set_private_bin_path_from_config (domain);
3879 cinfo = mono_custom_attrs_from_method (method);
3881 static MonoClass *stathread_attribute = NULL;
3882 if (!stathread_attribute)
3883 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3884 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3886 mono_custom_attrs_free (cinfo);
3888 has_stathread_attribute = FALSE;
3890 if (has_stathread_attribute) {
3891 thread->apartment_state = ThreadApartmentState_STA;
3893 thread->apartment_state = ThreadApartmentState_MTA;
3895 mono_thread_init_apartment_state ();
3897 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3899 /* FIXME: check signature of method */
3900 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3902 res = mono_runtime_invoke (method, NULL, pa, exc);
3904 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3908 mono_environment_exitcode_set (rval);
3910 mono_runtime_invoke (method, NULL, pa, exc);
3914 /* If the return type of Main is void, only
3915 * set the exitcode if an exception was thrown
3916 * (we don't want to blow away an
3917 * explicitly-set exit code)
3920 mono_environment_exitcode_set (rval);
3924 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3930 * mono_install_runtime_invoke:
3931 * @func: Function to install
3933 * This is a VM internal routine
3936 mono_install_runtime_invoke (MonoInvokeFunc func)
3938 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3943 * mono_runtime_invoke_array:
3944 * @method: method to invoke
3945 * @obJ: object instance
3946 * @params: arguments to the method
3947 * @exc: exception information.
3949 * Invokes the method represented by @method on the object @obj.
3951 * obj is the 'this' pointer, it should be NULL for static
3952 * methods, a MonoObject* for object instances and a pointer to
3953 * the value type for value types.
3955 * The params array contains the arguments to the method with the
3956 * same convention: MonoObject* pointers for object instances and
3957 * pointers to the value type otherwise. The _invoke_array
3958 * variant takes a C# object[] as the params argument (MonoArray
3959 * *params): in this case the value types are boxed inside the
3960 * respective reference representation.
3962 * From unmanaged code you'll usually use the
3963 * mono_runtime_invoke() variant.
3965 * Note that this function doesn't handle virtual methods for
3966 * you, it will exec the exact method you pass: we still need to
3967 * expose a function to lookup the derived class implementation
3968 * of a virtual method (there are examples of this in the code,
3971 * You can pass NULL as the exc argument if you don't want to
3972 * catch exceptions, otherwise, *exc will be set to the exception
3973 * thrown, if any. if an exception is thrown, you can't use the
3974 * MonoObject* result from the function.
3976 * If the method returns a value type, it is boxed in an object
3980 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3983 MonoMethodSignature *sig = mono_method_signature (method);
3984 gpointer *pa = NULL;
3987 gboolean has_byref_nullables = FALSE;
3989 if (NULL != params) {
3990 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3991 for (i = 0; i < mono_array_length (params); i++) {
3992 MonoType *t = sig->params [i];
3998 case MONO_TYPE_BOOLEAN:
4001 case MONO_TYPE_CHAR:
4010 case MONO_TYPE_VALUETYPE:
4011 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4012 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4013 pa [i] = mono_array_get (params, MonoObject*, i);
4015 has_byref_nullables = TRUE;
4017 /* MS seems to create the objects if a null is passed in */
4018 if (!mono_array_get (params, MonoObject*, i))
4019 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4023 * We can't pass the unboxed vtype byref to the callee, since
4024 * that would mean the callee would be able to modify boxed
4025 * primitive types. So we (and MS) make a copy of the boxed
4026 * object, pass that to the callee, and replace the original
4027 * boxed object in the arg array with the copy.
4029 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4030 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4031 mono_array_setref (params, i, copy);
4034 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4037 case MONO_TYPE_STRING:
4038 case MONO_TYPE_OBJECT:
4039 case MONO_TYPE_CLASS:
4040 case MONO_TYPE_ARRAY:
4041 case MONO_TYPE_SZARRAY:
4043 pa [i] = mono_array_addr (params, MonoObject*, i);
4044 // FIXME: I need to check this code path
4046 pa [i] = mono_array_get (params, MonoObject*, i);
4048 case MONO_TYPE_GENERICINST:
4050 t = &t->data.generic_class->container_class->this_arg;
4052 t = &t->data.generic_class->container_class->byval_arg;
4054 case MONO_TYPE_PTR: {
4057 /* The argument should be an IntPtr */
4058 arg = mono_array_get (params, MonoObject*, i);
4062 g_assert (arg->vtable->klass == mono_defaults.int_class);
4063 pa [i] = ((MonoIntPtr*)arg)->m_value;
4068 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4073 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4076 if (mono_class_is_nullable (method->klass)) {
4077 /* Need to create a boxed vtype instead */
4083 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4087 obj = mono_object_new (mono_domain_get (), method->klass);
4088 g_assert (obj); /*maybe we should raise a TLE instead?*/
4089 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4090 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4092 if (method->klass->valuetype)
4093 o = mono_object_unbox (obj);
4096 } else if (method->klass->valuetype) {
4097 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4100 mono_runtime_invoke (method, o, pa, exc);
4103 if (mono_class_is_nullable (method->klass)) {
4104 MonoObject *nullable;
4106 /* Convert the unboxed vtype into a Nullable structure */
4107 nullable = mono_object_new (mono_domain_get (), method->klass);
4109 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4110 obj = mono_object_unbox (nullable);
4113 /* obj must be already unboxed if needed */
4114 res = mono_runtime_invoke (method, obj, pa, exc);
4116 if (sig->ret->type == MONO_TYPE_PTR) {
4117 MonoClass *pointer_class;
4118 static MonoMethod *box_method;
4120 MonoObject *box_exc;
4123 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4124 * convert it to a Pointer object.
4126 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4128 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4130 g_assert (res->vtable->klass == mono_defaults.int_class);
4131 box_args [0] = ((MonoIntPtr*)res)->m_value;
4132 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4133 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4134 g_assert (!box_exc);
4137 if (has_byref_nullables) {
4139 * The runtime invoke wrapper already converted byref nullables back,
4140 * and stored them in pa, we just need to copy them back to the
4143 for (i = 0; i < mono_array_length (params); i++) {
4144 MonoType *t = sig->params [i];
4146 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4147 mono_array_setref (params, i, pa [i]);
4156 arith_overflow (void)
4158 mono_raise_exception (mono_get_exception_overflow ());
4162 * mono_object_allocate:
4163 * @size: number of bytes to allocate
4165 * This is a very simplistic routine until we have our GC-aware
4168 * Returns: an allocated object of size @size, or NULL on failure.
4170 static inline void *
4171 mono_object_allocate (size_t size, MonoVTable *vtable)
4174 mono_stats.new_object_count++;
4175 ALLOC_OBJECT (o, vtable, size);
4181 * mono_object_allocate_ptrfree:
4182 * @size: number of bytes to allocate
4184 * Note that the memory allocated is not zeroed.
4185 * Returns: an allocated object of size @size, or NULL on failure.
4187 static inline void *
4188 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4191 mono_stats.new_object_count++;
4192 ALLOC_PTRFREE (o, vtable, size);
4196 static inline void *
4197 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4200 ALLOC_TYPED (o, size, vtable);
4201 mono_stats.new_object_count++;
4208 * @klass: the class of the object that we want to create
4210 * Returns: a newly created object whose definition is
4211 * looked up using @klass. This will not invoke any constructors,
4212 * so the consumer of this routine has to invoke any constructors on
4213 * its own to initialize the object.
4215 * It returns NULL on failure.
4218 mono_object_new (MonoDomain *domain, MonoClass *klass)
4222 MONO_ARCH_SAVE_REGS;
4223 vtable = mono_class_vtable (domain, klass);
4226 return mono_object_new_specific (vtable);
4230 * mono_object_new_pinned:
4232 * Same as mono_object_new, but the returned object will be pinned.
4233 * For SGEN, these objects will only be freed at appdomain unload.
4236 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4240 MONO_ARCH_SAVE_REGS;
4241 vtable = mono_class_vtable (domain, klass);
4246 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4248 return mono_object_new_specific (vtable);
4253 * mono_object_new_specific:
4254 * @vtable: the vtable of the object that we want to create
4256 * Returns: A newly created object with class and domain specified
4260 mono_object_new_specific (MonoVTable *vtable)
4264 MONO_ARCH_SAVE_REGS;
4266 /* check for is_com_object for COM Interop */
4267 if (vtable->remote || vtable->klass->is_com_object)
4270 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4273 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4276 mono_class_init (klass);
4278 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4280 vtable->domain->create_proxy_for_type_method = im;
4283 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4285 o = mono_runtime_invoke (im, NULL, pa, NULL);
4286 if (o != NULL) return o;
4289 return mono_object_new_alloc_specific (vtable);
4293 mono_object_new_alloc_specific (MonoVTable *vtable)
4297 if (!vtable->klass->has_references) {
4298 o = mono_object_new_ptrfree (vtable);
4299 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4300 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4302 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4303 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4305 if (G_UNLIKELY (vtable->klass->has_finalize))
4306 mono_object_register_finalizer (o);
4308 if (G_UNLIKELY (profile_allocs))
4309 mono_profiler_allocation (o, vtable->klass);
4314 mono_object_new_fast (MonoVTable *vtable)
4317 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4322 mono_object_new_ptrfree (MonoVTable *vtable)
4325 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4326 #if NEED_TO_ZERO_PTRFREE
4327 /* an inline memset is much faster for the common vcase of small objects
4328 * note we assume the allocated size is a multiple of sizeof (void*).
4330 if (vtable->klass->instance_size < 128) {
4332 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4333 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4339 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4346 mono_object_new_ptrfree_box (MonoVTable *vtable)
4349 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4350 /* the object will be boxed right away, no need to memzero it */
4355 * mono_class_get_allocation_ftn:
4357 * @for_box: the object will be used for boxing
4358 * @pass_size_in_words:
4360 * Return the allocation function appropriate for the given class.
4364 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4366 *pass_size_in_words = FALSE;
4368 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4369 profile_allocs = FALSE;
4371 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4372 return mono_object_new_specific;
4374 if (!vtable->klass->has_references) {
4375 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4377 return mono_object_new_ptrfree_box;
4378 return mono_object_new_ptrfree;
4381 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4383 return mono_object_new_fast;
4386 * FIXME: This is actually slower than mono_object_new_fast, because
4387 * of the overhead of parameter passing.
4390 *pass_size_in_words = TRUE;
4391 #ifdef GC_REDIRECT_TO_LOCAL
4392 return GC_local_gcj_fast_malloc;
4394 return GC_gcj_fast_malloc;
4399 return mono_object_new_specific;
4403 * mono_object_new_from_token:
4404 * @image: Context where the type_token is hosted
4405 * @token: a token of the type that we want to create
4407 * Returns: A newly created object whose definition is
4408 * looked up using @token in the @image image
4411 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4415 class = mono_class_get (image, token);
4417 return mono_object_new (domain, class);
4422 * mono_object_clone:
4423 * @obj: the object to clone
4425 * Returns: A newly created object who is a shallow copy of @obj
4428 mono_object_clone (MonoObject *obj)
4431 int size = obj->vtable->klass->instance_size;
4433 o = mono_object_allocate (size, obj->vtable);
4435 if (obj->vtable->klass->has_references) {
4436 mono_gc_wbarrier_object_copy (o, obj);
4438 int size = obj->vtable->klass->instance_size;
4439 /* do not copy the sync state */
4440 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4442 if (G_UNLIKELY (profile_allocs))
4443 mono_profiler_allocation (o, obj->vtable->klass);
4445 if (obj->vtable->klass->has_finalize)
4446 mono_object_register_finalizer (o);
4451 * mono_array_full_copy:
4452 * @src: source array to copy
4453 * @dest: destination array
4455 * Copies the content of one array to another with exactly the same type and size.
4458 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4461 MonoClass *klass = src->obj.vtable->klass;
4463 MONO_ARCH_SAVE_REGS;
4465 g_assert (klass == dest->obj.vtable->klass);
4467 size = mono_array_length (src);
4468 g_assert (size == mono_array_length (dest));
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 (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4475 memcpy (&dest->vector, &src->vector, size);
4477 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4480 memcpy (&dest->vector, &src->vector, size);
4485 * mono_array_clone_in_domain:
4486 * @domain: the domain in which the array will be cloned into
4487 * @array: the array to clone
4489 * This routine returns a copy of the array that is hosted on the
4490 * specified MonoDomain.
4493 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4498 MonoClass *klass = array->obj.vtable->klass;
4500 MONO_ARCH_SAVE_REGS;
4502 if (array->bounds == NULL) {
4503 size = mono_array_length (array);
4504 o = mono_array_new_full (domain, klass, &size, NULL);
4506 size *= mono_array_element_size (klass);
4508 if (klass->element_class->valuetype) {
4509 if (klass->element_class->has_references)
4510 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4512 memcpy (&o->vector, &array->vector, size);
4514 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4517 memcpy (&o->vector, &array->vector, size);
4522 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4523 size = mono_array_element_size (klass);
4524 for (i = 0; i < klass->rank; ++i) {
4525 sizes [i] = array->bounds [i].length;
4526 size *= array->bounds [i].length;
4527 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4529 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4531 if (klass->element_class->valuetype) {
4532 if (klass->element_class->has_references)
4533 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4535 memcpy (&o->vector, &array->vector, size);
4537 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4540 memcpy (&o->vector, &array->vector, size);
4548 * @array: the array to clone
4550 * Returns: A newly created array who is a shallow copy of @array
4553 mono_array_clone (MonoArray *array)
4555 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4558 /* helper macros to check for overflow when calculating the size of arrays */
4559 #ifdef MONO_BIG_ARRAYS
4560 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4561 #define MYGUINT_MAX MYGUINT64_MAX
4562 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4563 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4564 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4565 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4566 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4568 #define MYGUINT32_MAX 4294967295U
4569 #define MYGUINT_MAX MYGUINT32_MAX
4570 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4571 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4572 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4573 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4574 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4578 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4582 byte_len = mono_array_element_size (class);
4583 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4586 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4588 byte_len += sizeof (MonoArray);
4596 * mono_array_new_full:
4597 * @domain: domain where the object is created
4598 * @array_class: array class
4599 * @lengths: lengths for each dimension in the array
4600 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4602 * This routine creates a new array objects with the given dimensions,
4603 * lower bounds and type.
4606 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4608 uintptr_t byte_len, len, bounds_size;
4611 MonoArrayBounds *bounds;
4615 if (!array_class->inited)
4616 mono_class_init (array_class);
4620 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4621 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4623 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4627 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4629 for (i = 0; i < array_class->rank; ++i) {
4630 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4632 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4633 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4638 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4639 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4643 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4644 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4645 byte_len = (byte_len + 3) & ~3;
4646 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4647 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4648 byte_len += bounds_size;
4651 * Following three lines almost taken from mono_object_new ():
4652 * they need to be kept in sync.
4654 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4655 #ifndef HAVE_SGEN_GC
4656 if (!array_class->has_references) {
4657 o = mono_object_allocate_ptrfree (byte_len, vtable);
4658 #if NEED_TO_ZERO_PTRFREE
4659 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4661 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4662 o = mono_object_allocate_spec (byte_len, vtable);
4664 o = mono_object_allocate (byte_len, vtable);
4667 array = (MonoArray*)o;
4668 array->max_length = len;
4671 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4672 array->bounds = bounds;
4676 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4678 o = mono_gc_alloc_vector (vtable, byte_len, len);
4679 array = (MonoArray*)o;
4680 mono_stats.new_object_count++;
4682 bounds = array->bounds;
4686 for (i = 0; i < array_class->rank; ++i) {
4687 bounds [i].length = lengths [i];
4689 bounds [i].lower_bound = lower_bounds [i];
4693 if (G_UNLIKELY (profile_allocs))
4694 mono_profiler_allocation (o, array_class);
4701 * @domain: domain where the object is created
4702 * @eclass: element class
4703 * @n: number of array elements
4705 * This routine creates a new szarray with @n elements of type @eclass.
4708 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4712 MONO_ARCH_SAVE_REGS;
4714 ac = mono_array_class_get (eclass, 1);
4717 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4721 * mono_array_new_specific:
4722 * @vtable: a vtable in the appropriate domain for an initialized class
4723 * @n: number of array elements
4725 * This routine is a fast alternative to mono_array_new() for code which
4726 * can be sure about the domain it operates in.
4729 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4735 MONO_ARCH_SAVE_REGS;
4737 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4742 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4743 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4746 #ifndef HAVE_SGEN_GC
4747 if (!vtable->klass->has_references) {
4748 o = mono_object_allocate_ptrfree (byte_len, vtable);
4749 #if NEED_TO_ZERO_PTRFREE
4750 ((MonoArray*)o)->bounds = NULL;
4751 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4753 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4754 o = mono_object_allocate_spec (byte_len, vtable);
4756 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4757 o = mono_object_allocate (byte_len, vtable);
4760 ao = (MonoArray *)o;
4763 o = mono_gc_alloc_vector (vtable, byte_len, n);
4765 mono_stats.new_object_count++;
4768 if (G_UNLIKELY (profile_allocs))
4769 mono_profiler_allocation (o, vtable->klass);
4775 * mono_string_new_utf16:
4776 * @text: a pointer to an utf16 string
4777 * @len: the length of the string
4779 * Returns: A newly created string object which contains @text.
4782 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4786 s = mono_string_new_size (domain, len);
4787 g_assert (s != NULL);
4789 memcpy (mono_string_chars (s), text, len * 2);
4795 * mono_string_new_size:
4796 * @text: a pointer to an utf16 string
4797 * @len: the length of the string
4799 * Returns: A newly created string object of @len
4802 mono_string_new_size (MonoDomain *domain, gint32 len)
4806 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4808 /* overflow ? can't fit it, can't allocate it! */
4810 mono_gc_out_of_memory (-1);
4812 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4815 #ifndef HAVE_SGEN_GC
4816 s = mono_object_allocate_ptrfree (size, vtable);
4820 s = mono_gc_alloc_string (vtable, size, len);
4822 #if NEED_TO_ZERO_PTRFREE
4825 if (G_UNLIKELY (profile_allocs))
4826 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4832 * mono_string_new_len:
4833 * @text: a pointer to an utf8 string
4834 * @length: number of bytes in @text to consider
4836 * Returns: A newly created string object which contains @text.
4839 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4841 GError *error = NULL;
4842 MonoString *o = NULL;
4844 glong items_written;
4846 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4849 o = mono_string_new_utf16 (domain, ut, items_written);
4851 g_error_free (error);
4860 * @text: a pointer to an utf8 string
4862 * Returns: A newly created string object which contains @text.
4865 mono_string_new (MonoDomain *domain, const char *text)
4867 GError *error = NULL;
4868 MonoString *o = NULL;
4870 glong items_written;
4875 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4878 o = mono_string_new_utf16 (domain, ut, items_written);
4880 g_error_free (error);
4883 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4888 MonoString *o = NULL;
4890 if (!g_utf8_validate (text, -1, &end))
4893 len = g_utf8_strlen (text, -1);
4894 o = mono_string_new_size (domain, len);
4895 str = mono_string_chars (o);
4897 while (text < end) {
4898 *str++ = g_utf8_get_char (text);
4899 text = g_utf8_next_char (text);
4906 * mono_string_new_wrapper:
4907 * @text: pointer to utf8 characters.
4909 * Helper function to create a string object from @text in the current domain.
4912 mono_string_new_wrapper (const char *text)
4914 MonoDomain *domain = mono_domain_get ();
4916 MONO_ARCH_SAVE_REGS;
4919 return mono_string_new (domain, text);
4926 * @class: the class of the value
4927 * @value: a pointer to the unboxed data
4929 * Returns: A newly created object which contains @value.
4932 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4938 g_assert (class->valuetype);
4939 if (mono_class_is_nullable (class))
4940 return mono_nullable_box (value, class);
4942 vtable = mono_class_vtable (domain, class);
4945 size = mono_class_instance_size (class);
4946 res = mono_object_new_alloc_specific (vtable);
4947 if (G_UNLIKELY (profile_allocs))
4948 mono_profiler_allocation (res, class);
4950 size = size - sizeof (MonoObject);
4953 g_assert (size == mono_class_value_size (class, NULL));
4954 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4956 #if NO_UNALIGNED_ACCESS
4957 memcpy ((char *)res + sizeof (MonoObject), value, size);
4961 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4964 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4967 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4970 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4973 memcpy ((char *)res + sizeof (MonoObject), value, size);
4977 if (class->has_finalize)
4978 mono_object_register_finalizer (res);
4984 * @dest: destination pointer
4985 * @src: source pointer
4986 * @klass: a valuetype class
4988 * Copy a valuetype from @src to @dest. This function must be used
4989 * when @klass contains references fields.
4992 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4994 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4998 * mono_value_copy_array:
4999 * @dest: destination array
5000 * @dest_idx: index in the @dest array
5001 * @src: source pointer
5002 * @count: number of items
5004 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5005 * This function must be used when @klass contains references fields.
5006 * Overlap is handled.
5009 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5011 int size = mono_array_element_size (dest->obj.vtable->klass);
5012 char *d = mono_array_addr_with_size (dest, size, dest_idx);
5013 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5014 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5018 * mono_object_get_domain:
5019 * @obj: object to query
5021 * Returns: the MonoDomain where the object is hosted
5024 mono_object_get_domain (MonoObject *obj)
5026 return mono_object_domain (obj);
5030 * mono_object_get_class:
5031 * @obj: object to query
5033 * Returns: the MonOClass of the object.
5036 mono_object_get_class (MonoObject *obj)
5038 return mono_object_class (obj);
5041 * mono_object_get_size:
5042 * @o: object to query
5044 * Returns: the size, in bytes, of @o
5047 mono_object_get_size (MonoObject* o)
5049 MonoClass* klass = mono_object_class (o);
5050 if (klass == mono_defaults.string_class) {
5051 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5052 } else if (o->vtable->rank) {
5053 MonoArray *array = (MonoArray*)o;
5054 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5055 if (array->bounds) {
5058 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5062 return mono_class_instance_size (klass);
5067 * mono_object_unbox:
5068 * @obj: object to unbox
5070 * Returns: a pointer to the start of the valuetype boxed in this
5073 * This method will assert if the object passed is not a valuetype.
5076 mono_object_unbox (MonoObject *obj)
5078 /* add assert for valuetypes? */
5079 g_assert (obj->vtable->klass->valuetype);
5080 return ((char*)obj) + sizeof (MonoObject);
5084 * mono_object_isinst:
5086 * @klass: a pointer to a class
5088 * Returns: @obj if @obj is derived from @klass
5091 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5094 mono_class_init (klass);
5096 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5097 return mono_object_isinst_mbyref (obj, klass);
5102 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5106 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5115 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5116 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5120 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5121 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5124 MonoClass *oklass = vt->klass;
5125 if ((oklass == mono_defaults.transparent_proxy_class))
5126 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5128 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5132 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5134 MonoDomain *domain = mono_domain_get ();
5136 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5137 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5138 MonoMethod *im = NULL;
5141 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5142 im = mono_object_get_virtual_method (rp, im);
5145 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5148 res = mono_runtime_invoke (im, rp, pa, NULL);
5150 if (*(MonoBoolean *) mono_object_unbox(res)) {
5151 /* Update the vtable of the remote type, so it can safely cast to this new type */
5152 mono_upgrade_remote_class (domain, obj, klass);
5161 * mono_object_castclass_mbyref:
5163 * @klass: a pointer to a class
5165 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5168 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5170 if (!obj) return NULL;
5171 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5173 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5175 "InvalidCastException"));
5180 MonoDomain *orig_domain;
5186 str_lookup (MonoDomain *domain, gpointer user_data)
5188 LDStrInfo *info = user_data;
5189 if (info->res || domain == info->orig_domain)
5191 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5197 mono_string_get_pinned (MonoString *str)
5201 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5202 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5204 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5205 news->length = mono_string_length (str);
5211 #define mono_string_get_pinned(str) (str)
5215 mono_string_is_interned_lookup (MonoString *str, int insert)
5217 MonoGHashTable *ldstr_table;
5221 domain = ((MonoObject *)str)->vtable->domain;
5222 ldstr_table = domain->ldstr_table;
5224 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5229 str = mono_string_get_pinned (str);
5231 mono_g_hash_table_insert (ldstr_table, str, str);
5235 LDStrInfo ldstr_info;
5236 ldstr_info.orig_domain = domain;
5237 ldstr_info.ins = str;
5238 ldstr_info.res = NULL;
5240 mono_domain_foreach (str_lookup, &ldstr_info);
5241 if (ldstr_info.res) {
5243 * the string was already interned in some other domain:
5244 * intern it in the current one as well.
5246 mono_g_hash_table_insert (ldstr_table, str, str);
5256 * mono_string_is_interned:
5257 * @o: String to probe
5259 * Returns whether the string has been interned.
5262 mono_string_is_interned (MonoString *o)
5264 return mono_string_is_interned_lookup (o, FALSE);
5268 * mono_string_intern:
5269 * @o: String to intern
5271 * Interns the string passed.
5272 * Returns: The interned string.
5275 mono_string_intern (MonoString *str)
5277 return mono_string_is_interned_lookup (str, TRUE);
5282 * @domain: the domain where the string will be used.
5283 * @image: a metadata context
5284 * @idx: index into the user string table.
5286 * Implementation for the ldstr opcode.
5287 * Returns: a loaded string from the @image/@idx combination.
5290 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5292 MONO_ARCH_SAVE_REGS;
5294 if (image->dynamic) {
5295 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5298 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5299 return NULL; /*FIXME we should probably be raising an exception here*/
5300 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5305 * mono_ldstr_metadata_sig
5306 * @domain: the domain for the string
5307 * @sig: the signature of a metadata string
5309 * Returns: a MonoString for a string stored in the metadata
5312 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5314 const char *str = sig;
5315 MonoString *o, *interned;
5318 len2 = mono_metadata_decode_blob_size (str, &str);
5321 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5322 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5325 guint16 *p2 = (guint16*)mono_string_chars (o);
5326 for (i = 0; i < len2; ++i) {
5327 *p2 = GUINT16_FROM_LE (*p2);
5333 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5335 /* o will get garbage collected */
5339 o = mono_string_get_pinned (o);
5341 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5348 * mono_string_to_utf8:
5349 * @s: a System.String
5351 * Returns the UTF8 representation for @s.
5352 * The resulting buffer needs to be freed with mono_free().
5354 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5357 mono_string_to_utf8 (MonoString *s)
5360 char *result = mono_string_to_utf8_checked (s, &error);
5362 if (!mono_error_ok (&error))
5363 mono_error_raise_exception (&error);
5368 * mono_string_to_utf8_checked:
5369 * @s: a System.String
5370 * @error: a MonoError.
5372 * Converts a MonoString to its UTF8 representation. May fail; check
5373 * @error to determine whether the conversion was successful.
5374 * The resulting buffer should be freed with mono_free().
5377 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5381 GError *gerror = NULL;
5383 mono_error_init (error);
5389 return g_strdup ("");
5391 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5393 mono_error_set_argument (error, "string", "%s", gerror->message);
5394 g_error_free (gerror);
5397 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5398 if (s->length > written) {
5399 /* allocate the total length and copy the part of the string that has been converted */
5400 char *as2 = g_malloc0 (s->length);
5401 memcpy (as2, as, written);
5410 * mono_string_to_utf16:
5413 * Return an null-terminated array of the utf-16 chars
5414 * contained in @s. The result must be freed with g_free().
5415 * This is a temporary helper until our string implementation
5416 * is reworked to always include the null terminating char.
5419 mono_string_to_utf16 (MonoString *s)
5426 as = g_malloc ((s->length * 2) + 2);
5427 as [(s->length * 2)] = '\0';
5428 as [(s->length * 2) + 1] = '\0';
5431 return (gunichar2 *)(as);
5434 memcpy (as, mono_string_chars(s), s->length * 2);
5435 return (gunichar2 *)(as);
5439 * mono_string_from_utf16:
5440 * @data: the UTF16 string (LPWSTR) to convert
5442 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5444 * Returns: a MonoString.
5447 mono_string_from_utf16 (gunichar2 *data)
5449 MonoDomain *domain = mono_domain_get ();
5455 while (data [len]) len++;
5457 return mono_string_new_utf16 (domain, data, len);
5462 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5468 r = mono_string_to_utf8_checked (s, error);
5469 if (!mono_error_ok (error))
5475 len = strlen (r) + 1;
5477 mp_s = mono_mempool_alloc (mp, len);
5479 mp_s = mono_image_alloc (image, len);
5481 memcpy (mp_s, r, len);
5489 * mono_string_to_utf8_image:
5490 * @s: a System.String
5492 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5495 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5497 return mono_string_to_utf8_internal (NULL, image, s, error);
5501 * mono_string_to_utf8_mp:
5502 * @s: a System.String
5504 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5507 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5509 return mono_string_to_utf8_internal (mp, NULL, s, error);
5513 default_ex_handler (MonoException *ex)
5515 MonoObject *o = (MonoObject*)ex;
5516 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5520 static MonoExceptionFunc ex_handler = default_ex_handler;
5523 * mono_install_handler:
5524 * @func: exception handler
5526 * This is an internal JIT routine used to install the handler for exceptions
5530 mono_install_handler (MonoExceptionFunc func)
5532 ex_handler = func? func: default_ex_handler;
5536 * mono_raise_exception:
5537 * @ex: exception object
5539 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5542 mono_raise_exception (MonoException *ex)
5545 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5546 * that will cause gcc to omit the function epilog, causing problems when
5547 * the JIT tries to walk the stack, since the return address on the stack
5548 * will point into the next function in the executable, not this one.
5551 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5552 MonoInternalThread *thread = mono_thread_internal_current ();
5553 g_assert (ex->object.vtable->domain == mono_domain_get ());
5554 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5561 * mono_wait_handle_new:
5562 * @domain: Domain where the object will be created
5563 * @handle: Handle for the wait handle
5565 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5568 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5570 MonoWaitHandle *res;
5571 gpointer params [1];
5572 static MonoMethod *handle_set;
5574 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5576 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5578 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5580 params [0] = &handle;
5581 mono_runtime_invoke (handle_set, res, params, NULL);
5587 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5589 static MonoClassField *f_os_handle;
5590 static MonoClassField *f_safe_handle;
5592 if (!f_os_handle && !f_safe_handle) {
5593 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5594 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5599 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5603 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5610 mono_runtime_capture_context (MonoDomain *domain)
5612 RuntimeInvokeFunction runtime_invoke;
5614 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5615 MonoMethod *method = mono_get_context_capture_method ();
5616 MonoMethod *wrapper;
5619 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5620 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5621 domain->capture_context_method = mono_compile_method (method);
5624 runtime_invoke = domain->capture_context_runtime_invoke;
5626 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5629 * mono_async_result_new:
5630 * @domain:domain where the object will be created.
5631 * @handle: wait handle.
5632 * @state: state to pass to AsyncResult
5633 * @data: C closure data.
5635 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5636 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5640 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5642 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5643 MonoObject *context = mono_runtime_capture_context (domain);
5644 /* we must capture the execution context from the original thread */
5646 MONO_OBJECT_SETREF (res, execution_context, context);
5647 /* note: result may be null if the flow is suppressed */
5651 MONO_OBJECT_SETREF (res, object_data, object_data);
5652 MONO_OBJECT_SETREF (res, async_state, state);
5654 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5656 res->sync_completed = FALSE;
5657 res->completed = FALSE;
5663 mono_message_init (MonoDomain *domain,
5664 MonoMethodMessage *this,
5665 MonoReflectionMethod *method,
5666 MonoArray *out_args)
5668 static MonoClass *object_array_klass;
5669 static MonoClass *byte_array_klass;
5670 static MonoClass *string_array_klass;
5671 MonoMethodSignature *sig = mono_method_signature (method->method);
5677 if (!object_array_klass) {
5680 klass = mono_array_class_get (mono_defaults.object_class, 1);
5683 mono_memory_barrier ();
5684 object_array_klass = klass;
5686 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5689 mono_memory_barrier ();
5690 byte_array_klass = klass;
5692 klass = mono_array_class_get (mono_defaults.string_class, 1);
5695 mono_memory_barrier ();
5696 string_array_klass = klass;
5699 MONO_OBJECT_SETREF (this, method, method);
5701 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5702 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5703 this->async_result = NULL;
5704 this->call_type = CallType_Sync;
5706 names = g_new (char *, sig->param_count);
5707 mono_method_get_param_names (method->method, (const char **) names);
5708 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5710 for (i = 0; i < sig->param_count; i++) {
5711 name = mono_string_new (domain, names [i]);
5712 mono_array_setref (this->names, i, name);
5716 for (i = 0, j = 0; i < sig->param_count; i++) {
5717 if (sig->params [i]->byref) {
5719 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5720 mono_array_setref (this->args, i, arg);
5724 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5728 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5731 mono_array_set (this->arg_types, guint8, i, arg_type);
5736 * mono_remoting_invoke:
5737 * @real_proxy: pointer to a RealProxy object
5738 * @msg: The MonoMethodMessage to execute
5739 * @exc: used to store exceptions
5740 * @out_args: used to store output arguments
5742 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5743 * IMessage interface and it is not trivial to extract results from there. So
5744 * we call an helper method PrivateInvoke instead of calling
5745 * RealProxy::Invoke() directly.
5747 * Returns: the result object.
5750 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5751 MonoObject **exc, MonoArray **out_args)
5753 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5756 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5759 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5761 real_proxy->vtable->domain->private_invoke_method = im;
5764 pa [0] = real_proxy;
5769 return mono_runtime_invoke (im, NULL, pa, exc);
5773 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5774 MonoObject **exc, MonoArray **out_args)
5776 static MonoClass *object_array_klass;
5779 MonoMethodSignature *sig;
5781 int i, j, outarg_count = 0;
5783 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5785 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5786 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5787 target = tp->rp->unwrapped_server;
5789 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5793 domain = mono_domain_get ();
5794 method = msg->method->method;
5795 sig = mono_method_signature (method);
5797 for (i = 0; i < sig->param_count; i++) {
5798 if (sig->params [i]->byref)
5802 if (!object_array_klass) {
5805 klass = mono_array_class_get (mono_defaults.object_class, 1);
5808 mono_memory_barrier ();
5809 object_array_klass = klass;
5812 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5813 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5816 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5818 for (i = 0, j = 0; i < sig->param_count; i++) {
5819 if (sig->params [i]->byref) {
5821 arg = mono_array_get (msg->args, gpointer, i);
5822 mono_array_setref (*out_args, j, arg);
5831 * mono_object_to_string:
5833 * @exc: Any exception thrown by ToString (). May be NULL.
5835 * Returns: the result of calling ToString () on an object.
5838 mono_object_to_string (MonoObject *obj, MonoObject **exc)
5840 static MonoMethod *to_string = NULL;
5846 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5848 method = mono_object_get_virtual_method (obj, to_string);
5850 return (MonoString *) mono_runtime_invoke (method, obj, NULL, exc);
5854 * mono_print_unhandled_exception:
5855 * @exc: The exception
5857 * Prints the unhandled exception.
5860 mono_print_unhandled_exception (MonoObject *exc)
5863 char *message = (char*)"";
5864 gboolean free_message = FALSE;
5867 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
5868 message = g_strdup ("OutOfMemoryException");
5870 str = mono_object_to_string (exc, NULL);
5872 message = mono_string_to_utf8_checked (str, &error);
5873 if (!mono_error_ok (&error)) {
5874 mono_error_cleanup (&error);
5875 message = (char *) "";
5877 free_message = TRUE;
5883 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5884 * exc->vtable->klass->name, message);
5886 g_printerr ("\nUnhandled Exception: %s\n", message);
5893 * mono_delegate_ctor:
5894 * @this: pointer to an uninitialized delegate object
5895 * @target: target object
5896 * @addr: pointer to native code
5899 * Initialize a delegate and sets a specific method, not the one
5900 * associated with addr. This is useful when sharing generic code.
5901 * In that case addr will most probably not be associated with the
5902 * correct instantiation of the method.
5905 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5907 MonoDelegate *delegate = (MonoDelegate *)this;
5914 delegate->method = method;
5916 class = this->vtable->klass;
5917 mono_stats.delegate_creations++;
5919 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5921 method = mono_marshal_get_remoting_invoke (method);
5922 delegate->method_ptr = mono_compile_method (method);
5923 MONO_OBJECT_SETREF (delegate, target, target);
5924 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5925 method = mono_marshal_get_unbox_wrapper (method);
5926 delegate->method_ptr = mono_compile_method (method);
5927 MONO_OBJECT_SETREF (delegate, target, target);
5929 delegate->method_ptr = addr;
5930 MONO_OBJECT_SETREF (delegate, target, target);
5933 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5937 * mono_delegate_ctor:
5938 * @this: pointer to an uninitialized delegate object
5939 * @target: target object
5940 * @addr: pointer to native code
5942 * This is used to initialize a delegate.
5945 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5947 MonoDomain *domain = mono_domain_get ();
5949 MonoMethod *method = NULL;
5953 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5954 method = ji->method;
5955 g_assert (!method->klass->generic_container);
5958 mono_delegate_ctor_with_method (this, target, addr, method);
5962 * mono_method_call_message_new:
5963 * @method: method to encapsulate
5964 * @params: parameters to the method
5965 * @invoke: optional, delegate invoke.
5966 * @cb: async callback delegate.
5967 * @state: state passed to the async callback.
5969 * Translates arguments pointers into a MonoMethodMessage.
5972 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5973 MonoDelegate **cb, MonoObject **state)
5975 MonoDomain *domain = mono_domain_get ();
5976 MonoMethodSignature *sig = mono_method_signature (method);
5977 MonoMethodMessage *msg;
5980 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5983 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5984 count = sig->param_count - 2;
5986 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5987 count = sig->param_count;
5990 for (i = 0; i < count; i++) {
5995 if (sig->params [i]->byref)
5996 vpos = *((gpointer *)params [i]);
6000 type = sig->params [i]->type;
6001 class = mono_class_from_mono_type (sig->params [i]);
6003 if (class->valuetype)
6004 arg = mono_value_box (domain, class, vpos);
6006 arg = *((MonoObject **)vpos);
6008 mono_array_setref (msg->args, i, arg);
6011 if (cb != NULL && state != NULL) {
6012 *cb = *((MonoDelegate **)params [i]);
6014 *state = *((MonoObject **)params [i]);
6021 * mono_method_return_message_restore:
6023 * Restore results from message based processing back to arguments pointers
6026 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6028 MonoMethodSignature *sig = mono_method_signature (method);
6029 int i, j, type, size, out_len;
6031 if (out_args == NULL)
6033 out_len = mono_array_length (out_args);
6037 for (i = 0, j = 0; i < sig->param_count; i++) {
6038 MonoType *pt = sig->params [i];
6043 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6045 arg = mono_array_get (out_args, gpointer, j);
6048 g_assert (type != MONO_TYPE_VOID);
6050 if (MONO_TYPE_IS_REFERENCE (pt)) {
6051 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6054 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6055 size = mono_class_value_size (class, NULL);
6056 if (class->has_references)
6057 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6059 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6061 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6062 memset (*((gpointer *)params [i]), 0, size);
6072 * mono_load_remote_field:
6073 * @this: pointer to an object
6074 * @klass: klass of the object containing @field
6075 * @field: the field to load
6076 * @res: a storage to store the result
6078 * This method is called by the runtime on attempts to load fields of
6079 * transparent proxy objects. @this points to such TP, @klass is the class of
6080 * the object containing @field. @res is a storage location which can be
6081 * used to store the result.
6083 * Returns: an address pointing to the value of field.
6086 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6088 static MonoMethod *getter = NULL;
6089 MonoDomain *domain = mono_domain_get ();
6090 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6091 MonoClass *field_class;
6092 MonoMethodMessage *msg;
6093 MonoArray *out_args;
6097 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6098 g_assert (res != NULL);
6100 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6101 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6106 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6110 field_class = mono_class_from_mono_type (field->type);
6112 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6113 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6114 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6116 full_name = mono_type_get_full_name (klass);
6117 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6118 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6121 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6123 if (exc) mono_raise_exception ((MonoException *)exc);
6125 if (mono_array_length (out_args) == 0)
6128 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6130 if (field_class->valuetype) {
6131 return ((char *)*res) + sizeof (MonoObject);
6137 * mono_load_remote_field_new:
6142 * Missing documentation.
6145 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6147 static MonoMethod *getter = NULL;
6148 MonoDomain *domain = mono_domain_get ();
6149 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6150 MonoClass *field_class;
6151 MonoMethodMessage *msg;
6152 MonoArray *out_args;
6153 MonoObject *exc, *res;
6156 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6158 field_class = mono_class_from_mono_type (field->type);
6160 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6162 if (field_class->valuetype) {
6163 res = mono_object_new (domain, field_class);
6164 val = ((gchar *) res) + sizeof (MonoObject);
6168 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6173 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6177 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6178 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6180 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6182 full_name = mono_type_get_full_name (klass);
6183 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6184 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6187 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6189 if (exc) mono_raise_exception ((MonoException *)exc);
6191 if (mono_array_length (out_args) == 0)
6194 res = mono_array_get (out_args, MonoObject *, 0);
6200 * mono_store_remote_field:
6201 * @this: pointer to an object
6202 * @klass: klass of the object containing @field
6203 * @field: the field to load
6204 * @val: the value/object to store
6206 * This method is called by the runtime on attempts to store fields of
6207 * transparent proxy objects. @this points to such TP, @klass is the class of
6208 * the object containing @field. @val is the new value to store in @field.
6211 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6213 static MonoMethod *setter = NULL;
6214 MonoDomain *domain = mono_domain_get ();
6215 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6216 MonoClass *field_class;
6217 MonoMethodMessage *msg;
6218 MonoArray *out_args;
6223 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6225 field_class = mono_class_from_mono_type (field->type);
6227 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6228 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6229 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6234 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6238 if (field_class->valuetype)
6239 arg = mono_value_box (domain, field_class, val);
6241 arg = *((MonoObject **)val);
6244 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6245 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6247 full_name = mono_type_get_full_name (klass);
6248 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6249 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6250 mono_array_setref (msg->args, 2, arg);
6253 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6255 if (exc) mono_raise_exception ((MonoException *)exc);
6259 * mono_store_remote_field_new:
6265 * Missing documentation
6268 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6270 static MonoMethod *setter = NULL;
6271 MonoDomain *domain = mono_domain_get ();
6272 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6273 MonoClass *field_class;
6274 MonoMethodMessage *msg;
6275 MonoArray *out_args;
6279 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6281 field_class = mono_class_from_mono_type (field->type);
6283 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6284 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6285 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6290 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6294 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6295 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6297 full_name = mono_type_get_full_name (klass);
6298 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6299 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6300 mono_array_setref (msg->args, 2, arg);
6303 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6305 if (exc) mono_raise_exception ((MonoException *)exc);
6309 * mono_create_ftnptr:
6311 * Given a function address, create a function descriptor for it.
6312 * This is only needed on some platforms.
6315 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6317 return callbacks.create_ftnptr (domain, addr);
6321 * mono_get_addr_from_ftnptr:
6323 * Given a pointer to a function descriptor, return the function address.
6324 * This is only needed on some platforms.
6327 mono_get_addr_from_ftnptr (gpointer descr)
6329 return callbacks.get_addr_from_ftnptr (descr);
6333 * mono_string_chars:
6336 * Returns a pointer to the UCS16 characters stored in the MonoString
6339 mono_string_chars (MonoString *s)
6345 * mono_string_length:
6348 * Returns the lenght in characters of the string
6351 mono_string_length (MonoString *s)
6357 * mono_array_length:
6358 * @array: a MonoArray*
6360 * Returns the total number of elements in the array. This works for
6361 * both vectors and multidimensional arrays.
6364 mono_array_length (MonoArray *array)
6366 return array->max_length;
6370 * mono_array_addr_with_size:
6371 * @array: a MonoArray*
6372 * @size: size of the array elements
6373 * @idx: index into the array
6375 * Returns the address of the @idx element in the array.
6378 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6380 return ((char*)(array)->vector) + size * idx;