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);
82 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
83 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
84 static CRITICAL_SECTION ldstr_section;
86 static gboolean profile_allocs = TRUE;
89 mono_runtime_object_init (MonoObject *this)
91 MonoMethod *method = NULL;
92 MonoClass *klass = this->vtable->klass;
94 method = mono_class_get_method_from_name (klass, ".ctor", 0);
97 if (method->klass->valuetype)
98 this = mono_object_unbox (this);
99 mono_runtime_invoke (method, this, NULL, NULL);
102 /* The pseudo algorithm for type initialization from the spec
103 Note it doesn't say anything about domains - only threads.
105 2. If the type is initialized you are done.
106 2.1. If the type is not yet initialized, try to take an
108 2.2. If successful, record this thread as responsible for
109 initializing the type and proceed to step 2.3.
110 2.2.1. If not, see whether this thread or any thread
111 waiting for this thread to complete already holds the lock.
112 2.2.2. If so, return since blocking would create a deadlock. This thread
113 will now see an incompletely initialized state for the type,
114 but no deadlock will arise.
115 2.2.3 If not, block until the type is initialized then return.
116 2.3 Initialize the parent type and then all interfaces implemented
118 2.4 Execute the type initialization code for this type.
119 2.5 Mark the type as initialized, release the initialization lock,
120 awaken any threads waiting for this type to be initialized,
127 guint32 initializing_tid;
128 guint32 waiting_count;
130 CRITICAL_SECTION initialization_section;
131 } TypeInitializationLock;
133 /* for locking access to type_initialization_hash and blocked_thread_hash */
134 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
135 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
136 static CRITICAL_SECTION type_initialization_section;
138 /* from vtable to lock */
139 static GHashTable *type_initialization_hash;
141 /* from thread id to thread id being waited on */
142 static GHashTable *blocked_thread_hash;
145 static MonoThread *main_thread;
147 /* Functions supplied by the runtime */
148 static MonoRuntimeCallbacks callbacks;
151 * mono_thread_set_main:
152 * @thread: thread to set as the main thread
154 * This function can be used to instruct the runtime to treat @thread
155 * as the main thread, ie, the thread that would normally execute the Main()
156 * method. This basically means that at the end of @thread, the runtime will
157 * wait for the existing foreground threads to quit and other such details.
160 mono_thread_set_main (MonoThread *thread)
162 main_thread = thread;
166 mono_thread_get_main (void)
172 mono_type_initialization_init (void)
174 InitializeCriticalSection (&type_initialization_section);
175 type_initialization_hash = g_hash_table_new (NULL, NULL);
176 blocked_thread_hash = g_hash_table_new (NULL, NULL);
177 InitializeCriticalSection (&ldstr_section);
181 mono_type_initialization_cleanup (void)
184 /* This is causing race conditions with
185 * mono_release_type_locks
187 DeleteCriticalSection (&type_initialization_section);
189 DeleteCriticalSection (&ldstr_section);
193 * get_type_init_exception_for_vtable:
195 * Return the stored type initialization exception for VTABLE.
197 static MonoException*
198 get_type_init_exception_for_vtable (MonoVTable *vtable)
200 MonoDomain *domain = vtable->domain;
201 MonoClass *klass = vtable->klass;
205 g_assert (vtable->init_failed);
208 * If the initializing thread was rudely aborted, the exception is not stored
212 mono_domain_lock (domain);
213 if (domain->type_init_exception_hash)
214 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
215 mono_domain_unlock (domain);
218 if (klass->name_space && *klass->name_space)
219 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
221 full_name = g_strdup (klass->name);
222 ex = mono_get_exception_type_initialization (full_name, NULL);
229 * mono_runtime_class_init:
230 * @vtable: vtable that needs to be initialized
232 * This routine calls the class constructor for @vtable.
235 mono_runtime_class_init (MonoVTable *vtable)
237 mono_runtime_class_init_full (vtable, TRUE);
241 * mono_runtime_class_init_full:
242 * @vtable that neeeds to be initialized
243 * @raise_exception is TRUE, exceptions are raised intead of returned
247 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
250 MonoException *exc_to_throw;
251 MonoMethod *method = NULL;
257 if (vtable->initialized)
261 klass = vtable->klass;
263 if (!klass->image->checked_module_cctor) {
264 mono_image_check_for_module_cctor (klass->image);
265 if (klass->image->has_module_cctor) {
266 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
267 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
270 mono_runtime_class_init (module_vtable);
273 method = mono_class_get_cctor (klass);
276 MonoDomain *domain = vtable->domain;
277 TypeInitializationLock *lock;
278 guint32 tid = GetCurrentThreadId();
279 int do_initialization = 0;
280 MonoDomain *last_domain = NULL;
282 mono_type_initialization_lock ();
283 /* double check... */
284 if (vtable->initialized) {
285 mono_type_initialization_unlock ();
288 if (vtable->init_failed) {
289 mono_type_initialization_unlock ();
291 /* The type initialization already failed once, rethrow the same exception */
293 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
294 return get_type_init_exception_for_vtable (vtable);
296 lock = g_hash_table_lookup (type_initialization_hash, vtable);
298 /* This thread will get to do the initialization */
299 if (mono_domain_get () != domain) {
300 /* Transfer into the target domain */
301 last_domain = mono_domain_get ();
302 if (!mono_domain_set (domain, FALSE)) {
303 vtable->initialized = 1;
304 mono_type_initialization_unlock ();
306 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
307 return mono_get_exception_appdomain_unloaded ();
310 lock = g_malloc (sizeof(TypeInitializationLock));
311 InitializeCriticalSection (&lock->initialization_section);
312 lock->initializing_tid = tid;
313 lock->waiting_count = 1;
315 /* grab the vtable lock while this thread still owns type_initialization_section */
316 EnterCriticalSection (&lock->initialization_section);
317 g_hash_table_insert (type_initialization_hash, vtable, lock);
318 do_initialization = 1;
321 TypeInitializationLock *pending_lock;
323 if (lock->initializing_tid == tid || lock->done) {
324 mono_type_initialization_unlock ();
327 /* see if the thread doing the initialization is already blocked on this thread */
328 blocked = GUINT_TO_POINTER (lock->initializing_tid);
329 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
330 if (pending_lock->initializing_tid == tid) {
331 if (!pending_lock->done) {
332 mono_type_initialization_unlock ();
335 /* the thread doing the initialization is blocked on this thread,
336 but on a lock that has already been freed. It just hasn't got
341 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
343 ++lock->waiting_count;
344 /* record the fact that we are waiting on the initializing thread */
345 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
347 mono_type_initialization_unlock ();
349 if (do_initialization) {
350 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
352 /* If the initialization failed, mark the class as unusable. */
353 /* Avoid infinite loops */
355 (klass->image == mono_defaults.corlib &&
356 !strcmp (klass->name_space, "System") &&
357 !strcmp (klass->name, "TypeInitializationException")))) {
358 vtable->init_failed = 1;
360 if (klass->name_space && *klass->name_space)
361 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
363 full_name = g_strdup (klass->name);
364 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
368 * Store the exception object so it could be thrown on subsequent
371 mono_domain_lock (domain);
372 if (!domain->type_init_exception_hash)
373 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
374 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
375 mono_domain_unlock (domain);
379 mono_domain_set (last_domain, TRUE);
381 LeaveCriticalSection (&lock->initialization_section);
383 /* this just blocks until the initializing thread is done */
384 EnterCriticalSection (&lock->initialization_section);
385 LeaveCriticalSection (&lock->initialization_section);
388 mono_type_initialization_lock ();
389 if (lock->initializing_tid != tid)
390 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
391 --lock->waiting_count;
392 if (lock->waiting_count == 0) {
393 DeleteCriticalSection (&lock->initialization_section);
394 g_hash_table_remove (type_initialization_hash, vtable);
397 if (!vtable->init_failed)
398 vtable->initialized = 1;
399 mono_type_initialization_unlock ();
401 if (vtable->init_failed) {
402 /* Either we were the initializing thread or we waited for the initialization */
404 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
405 return get_type_init_exception_for_vtable (vtable);
408 vtable->initialized = 1;
415 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
417 MonoVTable *vtable = (MonoVTable*)key;
419 TypeInitializationLock *lock = (TypeInitializationLock*) value;
420 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
423 * Have to set this since it cannot be set by the normal code in
424 * mono_runtime_class_init (). In this case, the exception object is not stored,
425 * and get_type_init_exception_for_class () needs to be aware of this.
427 vtable->init_failed = 1;
428 LeaveCriticalSection (&lock->initialization_section);
429 --lock->waiting_count;
430 if (lock->waiting_count == 0) {
431 DeleteCriticalSection (&lock->initialization_section);
440 mono_release_type_locks (MonoInternalThread *thread)
442 mono_type_initialization_lock ();
443 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
444 mono_type_initialization_unlock ();
448 default_trampoline (MonoMethod *method)
454 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
456 g_assert_not_reached ();
462 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
464 g_error ("remoting not installed");
469 default_delegate_trampoline (MonoClass *klass)
471 g_assert_not_reached ();
475 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
476 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
477 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
478 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
479 static MonoImtThunkBuilder imt_thunk_builder = NULL;
480 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
481 #if (MONO_IMT_SIZE > 32)
482 #error "MONO_IMT_SIZE cannot be larger than 32"
486 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
488 memcpy (&callbacks, cbs, sizeof (*cbs));
491 MonoRuntimeCallbacks*
492 mono_get_runtime_callbacks (void)
498 mono_install_trampoline (MonoTrampoline func)
500 arch_create_jit_trampoline = func? func: default_trampoline;
504 mono_install_jump_trampoline (MonoJumpTrampoline func)
506 arch_create_jump_trampoline = func? func: default_jump_trampoline;
510 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
512 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
516 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
518 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
522 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
523 imt_thunk_builder = func;
526 static MonoCompileFunc default_mono_compile_method = NULL;
529 * mono_install_compile_method:
530 * @func: function to install
532 * This is a VM internal routine
535 mono_install_compile_method (MonoCompileFunc func)
537 default_mono_compile_method = func;
541 * mono_compile_method:
542 * @method: The method to compile.
544 * This JIT-compiles the method, and returns the pointer to the native code
548 mono_compile_method (MonoMethod *method)
550 if (!default_mono_compile_method) {
551 g_error ("compile method called on uninitialized runtime");
554 return default_mono_compile_method (method);
558 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
560 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
564 mono_runtime_create_delegate_trampoline (MonoClass *klass)
566 return arch_create_delegate_trampoline (klass);
569 static MonoFreeMethodFunc default_mono_free_method = NULL;
572 * mono_install_free_method:
573 * @func: pointer to the MonoFreeMethodFunc used to release a method
575 * This is an internal VM routine, it is used for the engines to
576 * register a handler to release the resources associated with a method.
578 * Methods are freed when no more references to the delegate that holds
582 mono_install_free_method (MonoFreeMethodFunc func)
584 default_mono_free_method = func;
588 * mono_runtime_free_method:
589 * @domain; domain where the method is hosted
590 * @method: method to release
592 * This routine is invoked to free the resources associated with
593 * a method that has been JIT compiled. This is used to discard
594 * methods that were used only temporarily (for example, used in marshalling)
598 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
600 if (default_mono_free_method != NULL)
601 default_mono_free_method (domain, method);
603 mono_method_clear_object (domain, method);
605 mono_free_method (method);
609 * The vtables in the root appdomain are assumed to be reachable by other
610 * roots, and we don't use typed allocation in the other domains.
613 /* The sync block is no longer a GC pointer */
614 #define GC_HEADER_BITMAP (0)
616 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
619 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
621 MonoClassField *field;
627 max_size = mono_class_data_size (class) / sizeof (gpointer);
629 max_size = class->instance_size / sizeof (gpointer);
630 if (max_size > size) {
631 g_assert (offset <= 0);
632 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
636 for (p = class; p != NULL; p = p->parent) {
637 gpointer iter = NULL;
638 while ((field = mono_class_get_fields (p, &iter))) {
642 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
644 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
647 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
650 /* FIXME: should not happen, flag as type load error */
651 if (field->type->byref)
654 if (static_fields && field->offset == -1)
658 pos = field->offset / sizeof (gpointer);
661 type = mono_type_get_underlying_type (field->type);
662 switch (type->type) {
665 case MONO_TYPE_FNPTR:
667 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
672 if (class->image != mono_defaults.corlib)
675 case MONO_TYPE_STRING:
676 case MONO_TYPE_SZARRAY:
677 case MONO_TYPE_CLASS:
678 case MONO_TYPE_OBJECT:
679 case MONO_TYPE_ARRAY:
680 g_assert ((field->offset % sizeof(gpointer)) == 0);
682 g_assert (pos < size || pos <= max_size);
683 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
684 *max_set = MAX (*max_set, pos);
686 case MONO_TYPE_GENERICINST:
687 if (!mono_type_generic_inst_is_valuetype (type)) {
688 g_assert ((field->offset % sizeof(gpointer)) == 0);
690 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
691 *max_set = MAX (*max_set, pos);
696 case MONO_TYPE_VALUETYPE: {
697 MonoClass *fclass = mono_class_from_mono_type (field->type);
698 if (fclass->has_references) {
699 /* remove the object header */
700 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
714 case MONO_TYPE_BOOLEAN:
718 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
730 * similar to the above, but sets the bits in the bitmap for any non-ref field
731 * and ignores static fields
734 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
736 MonoClassField *field;
741 max_size = class->instance_size / sizeof (gpointer);
742 if (max_size >= size) {
743 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
746 for (p = class; p != NULL; p = p->parent) {
747 gpointer iter = NULL;
748 while ((field = mono_class_get_fields (p, &iter))) {
751 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
753 /* FIXME: should not happen, flag as type load error */
754 if (field->type->byref)
757 pos = field->offset / sizeof (gpointer);
760 type = mono_type_get_underlying_type (field->type);
761 switch (type->type) {
762 #if SIZEOF_VOID_P == 8
766 case MONO_TYPE_FNPTR:
771 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
772 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
773 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
776 #if SIZEOF_VOID_P == 4
780 case MONO_TYPE_FNPTR:
785 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
786 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
787 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
793 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
794 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
795 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
798 case MONO_TYPE_BOOLEAN:
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
803 case MONO_TYPE_STRING:
804 case MONO_TYPE_SZARRAY:
805 case MONO_TYPE_CLASS:
806 case MONO_TYPE_OBJECT:
807 case MONO_TYPE_ARRAY:
809 case MONO_TYPE_GENERICINST:
810 if (!mono_type_generic_inst_is_valuetype (type)) {
815 case MONO_TYPE_VALUETYPE: {
816 MonoClass *fclass = mono_class_from_mono_type (field->type);
817 /* remove the object header */
818 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
822 g_assert_not_reached ();
831 * mono_class_insecure_overlapping:
832 * check if a class with explicit layout has references and non-references
833 * fields overlapping.
835 * Returns: TRUE if it is insecure to load the type.
838 mono_class_insecure_overlapping (MonoClass *klass)
842 gsize default_bitmap [4] = {0};
844 gsize default_nrbitmap [4] = {0};
845 int i, insecure = FALSE;
848 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
849 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
851 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
852 int idx = i % (sizeof (bitmap [0]) * 8);
853 if (bitmap [idx] & nrbitmap [idx]) {
858 if (bitmap != default_bitmap)
860 if (nrbitmap != default_nrbitmap)
863 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
871 mono_string_alloc (int length)
873 return mono_string_new_size (mono_domain_get (), length);
877 mono_class_compute_gc_descriptor (MonoClass *class)
881 gsize default_bitmap [4] = {0};
882 static gboolean gcj_inited = FALSE;
887 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
888 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
889 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
890 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
892 #ifdef HAVE_GC_GCJ_MALLOC
894 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
898 #ifdef GC_REDIRECT_TO_LOCAL
899 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
900 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
902 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
903 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
908 mono_loader_unlock ();
912 mono_class_init (class);
914 if (class->gc_descr_inited)
917 class->gc_descr_inited = TRUE;
918 class->gc_descr = GC_NO_DESCRIPTOR;
920 bitmap = default_bitmap;
921 if (class == mono_defaults.string_class) {
922 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
923 } else if (class->rank) {
924 mono_class_compute_gc_descriptor (class->element_class);
925 if (!class->element_class->valuetype) {
927 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
928 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
929 class->name_space, class->name);*/
931 /* remove the object header */
932 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
933 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
934 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
935 class->name_space, class->name);*/
936 if (bitmap != default_bitmap)
940 /*static int count = 0;
943 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
944 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
946 if (class->gc_descr == GC_NO_DESCRIPTOR)
947 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
949 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
950 if (bitmap != default_bitmap)
956 * field_is_special_static:
957 * @fklass: The MonoClass to look up.
958 * @field: The MonoClassField describing the field.
960 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
961 * SPECIAL_STATIC_NONE otherwise.
964 field_is_special_static (MonoClass *fklass, MonoClassField *field)
966 MonoCustomAttrInfo *ainfo;
968 ainfo = mono_custom_attrs_from_field (fklass, field);
971 for (i = 0; i < ainfo->num_attrs; ++i) {
972 MonoClass *klass = ainfo->attrs [i].ctor->klass;
973 if (klass->image == mono_defaults.corlib) {
974 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
975 mono_custom_attrs_free (ainfo);
976 return SPECIAL_STATIC_THREAD;
978 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
979 mono_custom_attrs_free (ainfo);
980 return SPECIAL_STATIC_CONTEXT;
984 mono_custom_attrs_free (ainfo);
985 return SPECIAL_STATIC_NONE;
988 static gpointer imt_trampoline = NULL;
991 mono_install_imt_trampoline (gpointer tramp_code)
993 imt_trampoline = tramp_code;
996 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
997 #define mix(a,b,c) { \
998 a -= c; a ^= rot(c, 4); c += b; \
999 b -= a; b ^= rot(a, 6); a += c; \
1000 c -= b; c ^= rot(b, 8); b += a; \
1001 a -= c; a ^= rot(c,16); c += b; \
1002 b -= a; b ^= rot(a,19); a += c; \
1003 c -= b; c ^= rot(b, 4); b += a; \
1005 #define final(a,b,c) { \
1006 c ^= b; c -= rot(b,14); \
1007 a ^= c; a -= rot(c,11); \
1008 b ^= a; b -= rot(a,25); \
1009 c ^= b; c -= rot(b,16); \
1010 a ^= c; a -= rot(c,4); \
1011 b ^= a; b -= rot(a,14); \
1012 c ^= b; c -= rot(b,24); \
1016 * mono_method_get_imt_slot:
1018 * The IMT slot is embedded into AOTed code, so this must return the same value
1019 * for the same method across all executions. This means:
1020 * - pointers shouldn't be used as hash values.
1021 * - mono_metadata_str_hash () should be used for hashing strings.
1024 mono_method_get_imt_slot (MonoMethod *method)
1026 MonoMethodSignature *sig;
1028 guint32 *hashes_start, *hashes;
1032 /* This can be used to stress tests the collision code */
1036 * We do this to simplify generic sharing. It will hurt
1037 * performance in cases where a class implements two different
1038 * instantiations of the same generic interface.
1039 * The code in build_imt_slots () depends on this.
1041 if (method->is_inflated)
1042 method = ((MonoMethodInflated*)method)->declaring;
1044 sig = mono_method_signature (method);
1045 hashes_count = sig->param_count + 4;
1046 hashes_start = malloc (hashes_count * sizeof (guint32));
1047 hashes = hashes_start;
1049 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1050 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1051 method->klass->name_space, method->klass->name, method->name);
1052 g_assert_not_reached ();
1055 /* Initialize hashes */
1056 hashes [0] = mono_metadata_str_hash (method->klass->name);
1057 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1058 hashes [2] = mono_metadata_str_hash (method->name);
1059 hashes [3] = mono_metadata_type_hash (sig->ret);
1060 for (i = 0; i < sig->param_count; i++) {
1061 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1064 /* Setup internal state */
1065 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1067 /* Handle most of the hashes */
1068 while (hashes_count > 3) {
1077 /* Handle the last 3 hashes (all the case statements fall through) */
1078 switch (hashes_count) {
1079 case 3 : c += hashes [2];
1080 case 2 : b += hashes [1];
1081 case 1 : a += hashes [0];
1083 case 0: /* nothing left to add */
1087 free (hashes_start);
1088 /* Report the result */
1089 return c % MONO_IMT_SIZE;
1098 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1099 guint32 imt_slot = mono_method_get_imt_slot (method);
1100 MonoImtBuilderEntry *entry;
1102 if (slot_num >= 0 && imt_slot != slot_num) {
1103 /* we build just a single imt slot and this is not it */
1107 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1108 entry->key = method;
1109 entry->value.vtable_slot = vtable_slot;
1110 entry->next = imt_builder [imt_slot];
1111 if (imt_builder [imt_slot] != NULL) {
1112 entry->children = imt_builder [imt_slot]->children + 1;
1113 if (entry->children == 1) {
1114 mono_stats.imt_slots_with_collisions++;
1115 *imt_collisions_bitmap |= (1 << imt_slot);
1118 entry->children = 0;
1119 mono_stats.imt_used_slots++;
1121 imt_builder [imt_slot] = entry;
1124 char *method_name = mono_method_full_name (method, TRUE);
1125 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1126 method, method_name, imt_slot, vtable_slot, entry->children);
1127 g_free (method_name);
1134 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1136 MonoMethod *method = e->key;
1137 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1141 method->klass->name_space,
1142 method->klass->name,
1145 printf (" * %s: NULL\n", message);
1151 compare_imt_builder_entries (const void *p1, const void *p2) {
1152 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1153 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1155 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1159 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1161 int count = end - start;
1162 int chunk_start = out_array->len;
1165 for (i = start; i < end; ++i) {
1166 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1167 item->key = sorted_array [i]->key;
1168 item->value = sorted_array [i]->value;
1169 item->has_target_code = sorted_array [i]->has_target_code;
1170 item->is_equals = TRUE;
1172 item->check_target_idx = out_array->len + 1;
1174 item->check_target_idx = 0;
1175 g_ptr_array_add (out_array, item);
1178 int middle = start + count / 2;
1179 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1181 item->key = sorted_array [middle]->key;
1182 item->is_equals = FALSE;
1183 g_ptr_array_add (out_array, item);
1184 imt_emit_ir (sorted_array, start, middle, out_array);
1185 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1191 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1192 int number_of_entries = entries->children + 1;
1193 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1194 GPtrArray *result = g_ptr_array_new ();
1195 MonoImtBuilderEntry *current_entry;
1198 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1199 sorted_array [i] = current_entry;
1201 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1203 /*for (i = 0; i < number_of_entries; i++) {
1204 print_imt_entry (" sorted array:", sorted_array [i], i);
1207 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1209 free (sorted_array);
1214 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1216 if (imt_builder_entry != NULL) {
1217 if (imt_builder_entry->children == 0 && !fail_tramp) {
1218 /* No collision, return the vtable slot contents */
1219 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1221 /* Collision, build the thunk */
1222 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1225 result = imt_thunk_builder (vtable, domain,
1226 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1227 for (i = 0; i < imt_ir->len; ++i)
1228 g_free (g_ptr_array_index (imt_ir, i));
1229 g_ptr_array_free (imt_ir, TRUE);
1241 static MonoImtBuilderEntry*
1242 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1245 * LOCKING: requires the loader and domain locks.
1249 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1253 guint32 imt_collisions_bitmap = 0;
1254 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1255 int method_count = 0;
1256 gboolean record_method_count_for_max_collisions = FALSE;
1257 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1260 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1262 for (i = 0; i < klass->interface_offsets_count; ++i) {
1263 MonoClass *iface = klass->interfaces_packed [i];
1264 int interface_offset = klass->interface_offsets_packed [i];
1265 int method_slot_in_interface, vt_slot;
1267 if (mono_class_has_variant_generic_params (iface))
1268 has_variant_iface = TRUE;
1270 vt_slot = interface_offset;
1271 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1274 if (slot_num >= 0 && iface->is_inflated) {
1276 * The imt slot of the method is the same as for its declaring method,
1277 * see the comment in mono_method_get_imt_slot (), so we can
1278 * avoid inflating methods which will be discarded by
1279 * add_imt_builder_entry anyway.
1281 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1282 if (mono_method_get_imt_slot (method) != slot_num) {
1287 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1288 if (method->is_generic) {
1289 has_generic_virtual = TRUE;
1294 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1295 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1300 if (extra_interfaces) {
1301 int interface_offset = klass->vtable_size;
1303 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1304 MonoClass* iface = list_item->data;
1305 int method_slot_in_interface;
1306 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1307 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1308 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1310 interface_offset += iface->method.count;
1313 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1314 /* overwrite the imt slot only if we're building all the entries or if
1315 * we're building this specific one
1317 if (slot_num < 0 || i == slot_num) {
1318 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1321 if (imt_builder [i]) {
1322 MonoImtBuilderEntry *entry;
1324 /* Link entries with imt_builder [i] */
1325 for (entry = entries; entry->next; entry = entry->next) {
1327 MonoMethod *method = (MonoMethod*)entry->key;
1328 char *method_name = mono_method_full_name (method, TRUE);
1329 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1330 g_free (method_name);
1333 entry->next = imt_builder [i];
1334 entries->children += imt_builder [i]->children + 1;
1336 imt_builder [i] = entries;
1339 if (has_generic_virtual || has_variant_iface) {
1341 * There might be collisions later when the the thunk is expanded.
1343 imt_collisions_bitmap |= (1 << i);
1346 * The IMT thunk might be called with an instance of one of the
1347 * generic virtual methods, so has to fallback to the IMT trampoline.
1349 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1351 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1354 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1358 if (imt_builder [i] != NULL) {
1359 int methods_in_slot = imt_builder [i]->children + 1;
1360 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1361 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1362 record_method_count_for_max_collisions = TRUE;
1364 method_count += methods_in_slot;
1368 mono_stats.imt_number_of_methods += method_count;
1369 if (record_method_count_for_max_collisions) {
1370 mono_stats.imt_method_count_when_max_collisions = method_count;
1373 for (i = 0; i < MONO_IMT_SIZE; i++) {
1374 MonoImtBuilderEntry* entry = imt_builder [i];
1375 while (entry != NULL) {
1376 MonoImtBuilderEntry* next = entry->next;
1382 /* we OR the bitmap since we may build just a single imt slot at a time */
1383 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1387 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1388 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1392 * mono_vtable_build_imt_slot:
1393 * @vtable: virtual object table struct
1394 * @imt_slot: slot in the IMT table
1396 * Fill the given @imt_slot in the IMT table of @vtable with
1397 * a trampoline or a thunk for the case of collisions.
1398 * This is part of the internal mono API.
1400 * LOCKING: Take the domain lock.
1403 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1405 gpointer *imt = (gpointer*)vtable;
1406 imt -= MONO_IMT_SIZE;
1407 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1409 /* no support for extra interfaces: the proxy objects will need
1410 * to build the complete IMT
1411 * Update and heck needs to ahppen inside the proper domain lock, as all
1412 * the changes made to a MonoVTable.
1414 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1415 mono_domain_lock (vtable->domain);
1416 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1417 if (imt [imt_slot] == imt_trampoline)
1418 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1419 mono_domain_unlock (vtable->domain);
1420 mono_loader_unlock ();
1425 * The first two free list entries both belong to the wait list: The
1426 * first entry is the pointer to the head of the list and the second
1427 * entry points to the last element. That way appending and removing
1428 * the first element are both O(1) operations.
1430 #define NUM_FREE_LISTS 12
1431 #define FIRST_FREE_LIST_SIZE 64
1432 #define MAX_WAIT_LENGTH 50
1433 #define THUNK_THRESHOLD 10
1436 * LOCKING: The domain lock must be held.
1439 init_thunk_free_lists (MonoDomain *domain)
1441 if (domain->thunk_free_lists)
1443 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1447 list_index_for_size (int item_size)
1450 int size = FIRST_FREE_LIST_SIZE;
1452 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1461 * mono_method_alloc_generic_virtual_thunk:
1463 * @size: size in bytes
1465 * Allocs size bytes to be used for the code of a generic virtual
1466 * thunk. It's either allocated from the domain's code manager or
1467 * reused from a previously invalidated piece.
1469 * LOCKING: The domain lock must be held.
1472 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1474 static gboolean inited = FALSE;
1475 static int generic_virtual_thunks_size = 0;
1479 MonoThunkFreeList **l;
1481 init_thunk_free_lists (domain);
1483 size += sizeof (guint32);
1484 if (size < sizeof (MonoThunkFreeList))
1485 size = sizeof (MonoThunkFreeList);
1487 i = list_index_for_size (size);
1488 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1489 if ((*l)->size >= size) {
1490 MonoThunkFreeList *item = *l;
1492 return ((guint32*)item) + 1;
1496 /* no suitable item found - search lists of larger sizes */
1497 while (++i < NUM_FREE_LISTS) {
1498 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1501 g_assert (item->size > size);
1502 domain->thunk_free_lists [i] = item->next;
1503 return ((guint32*)item) + 1;
1506 /* still nothing found - allocate it */
1508 mono_counters_register ("Generic virtual thunk bytes",
1509 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1512 generic_virtual_thunks_size += size;
1514 p = mono_domain_code_reserve (domain, size);
1521 * LOCKING: The domain lock must be held.
1524 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1527 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1529 init_thunk_free_lists (domain);
1531 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1532 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1533 int length = item->length;
1536 /* unlink the first item from the wait list */
1537 domain->thunk_free_lists [0] = item->next;
1538 domain->thunk_free_lists [0]->length = length - 1;
1540 i = list_index_for_size (item->size);
1542 /* put it in the free list */
1543 item->next = domain->thunk_free_lists [i];
1544 domain->thunk_free_lists [i] = item;
1548 if (domain->thunk_free_lists [1]) {
1549 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1550 domain->thunk_free_lists [0]->length++;
1552 g_assert (!domain->thunk_free_lists [0]);
1554 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1555 domain->thunk_free_lists [0]->length = 1;
1559 typedef struct _GenericVirtualCase {
1563 struct _GenericVirtualCase *next;
1564 } GenericVirtualCase;
1567 * get_generic_virtual_entries:
1569 * Return IMT entries for the generic virtual method instances and
1570 * variant interface methods for vtable slot
1573 static MonoImtBuilderEntry*
1574 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1576 GenericVirtualCase *list;
1577 MonoImtBuilderEntry *entries;
1579 mono_domain_lock (domain);
1580 if (!domain->generic_virtual_cases)
1581 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1583 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1586 for (; list; list = list->next) {
1587 MonoImtBuilderEntry *entry;
1589 if (list->count < THUNK_THRESHOLD)
1592 entry = g_new0 (MonoImtBuilderEntry, 1);
1593 entry->key = list->method;
1594 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1595 entry->has_target_code = 1;
1597 entry->children = entries->children + 1;
1598 entry->next = entries;
1602 mono_domain_unlock (domain);
1604 /* FIXME: Leaking memory ? */
1609 * mono_method_add_generic_virtual_invocation:
1611 * @vtable_slot: pointer to the vtable slot
1612 * @method: the inflated generic virtual method
1613 * @code: the method's code
1615 * Registers a call via unmanaged code to a generic virtual method
1616 * instantiation or variant interface method. If the number of calls reaches a threshold
1617 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1618 * virtual method thunk.
1621 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1622 gpointer *vtable_slot,
1623 MonoMethod *method, gpointer code)
1625 static gboolean inited = FALSE;
1626 static int num_added = 0;
1628 GenericVirtualCase *gvc, *list;
1629 MonoImtBuilderEntry *entries;
1633 mono_domain_lock (domain);
1634 if (!domain->generic_virtual_cases)
1635 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1637 /* Check whether the case was already added */
1638 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1641 if (gvc->method == method)
1646 /* If not found, make a new one */
1648 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1649 gvc->method = method;
1652 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1654 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1657 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1663 if (++gvc->count == THUNK_THRESHOLD) {
1664 gpointer *old_thunk = *vtable_slot;
1665 gpointer vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable) : NULL;
1667 if ((gpointer)vtable_slot < (gpointer)vtable)
1668 /* Force the rebuild of the thunk at the next call */
1669 *vtable_slot = imt_trampoline;
1671 entries = get_generic_virtual_entries (domain, vtable_slot);
1673 sorted = imt_sort_slot_entries (entries);
1675 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1679 MonoImtBuilderEntry *next = entries->next;
1684 for (i = 0; i < sorted->len; ++i)
1685 g_free (g_ptr_array_index (sorted, i));
1686 g_ptr_array_free (sorted, TRUE);
1689 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1690 invalidate_generic_virtual_thunk (domain, old_thunk);
1693 mono_domain_unlock (domain);
1696 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1699 * mono_class_vtable:
1700 * @domain: the application domain
1701 * @class: the class to initialize
1703 * VTables are domain specific because we create domain specific code, and
1704 * they contain the domain specific static class data.
1705 * On failure, NULL is returned, and class->exception_type is set.
1708 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1710 return mono_class_vtable_full (domain, class, FALSE);
1714 * mono_class_vtable_full:
1715 * @domain: the application domain
1716 * @class: the class to initialize
1717 * @raise_on_error if an exception should be raised on failure or not
1719 * VTables are domain specific because we create domain specific code, and
1720 * they contain the domain specific static class data.
1723 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1725 MonoClassRuntimeInfo *runtime_info;
1729 if (class->exception_type) {
1731 mono_raise_exception (mono_class_get_exception_for_failure (class));
1735 /* this check can be inlined in jitted code, too */
1736 runtime_info = class->runtime_info;
1737 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1738 return runtime_info->domain_vtables [domain->domain_id];
1739 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1743 * mono_class_try_get_vtable:
1744 * @domain: the application domain
1745 * @class: the class to initialize
1747 * This function tries to get the associated vtable from @class if
1748 * it was already created.
1751 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1753 MonoClassRuntimeInfo *runtime_info;
1757 runtime_info = class->runtime_info;
1758 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1759 return runtime_info->domain_vtables [domain->domain_id];
1764 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1767 MonoClassRuntimeInfo *runtime_info, *old_info;
1768 MonoClassField *field;
1771 int imt_table_bytes = 0;
1772 guint32 vtable_size, class_size;
1775 gpointer *interface_offsets;
1777 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1778 mono_domain_lock (domain);
1779 runtime_info = class->runtime_info;
1780 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1781 mono_domain_unlock (domain);
1782 mono_loader_unlock ();
1783 return runtime_info->domain_vtables [domain->domain_id];
1785 if (!class->inited || class->exception_type) {
1786 if (!mono_class_init (class) || class->exception_type) {
1787 mono_domain_unlock (domain);
1788 mono_loader_unlock ();
1790 mono_raise_exception (mono_class_get_exception_for_failure (class));
1795 /* Array types require that their element type be valid*/
1796 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1797 MonoClass *element_class = class->element_class;
1798 if (!element_class->inited)
1799 mono_class_init (element_class);
1801 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1802 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1803 mono_class_setup_vtable (element_class);
1805 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1806 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1807 if (class->exception_type == MONO_EXCEPTION_NONE)
1808 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1809 mono_domain_unlock (domain);
1810 mono_loader_unlock ();
1812 mono_raise_exception (mono_class_get_exception_for_failure (class));
1818 * For some classes, mono_class_init () already computed class->vtable_size, and
1819 * that is all that is needed because of the vtable trampolines.
1821 if (!class->vtable_size)
1822 mono_class_setup_vtable (class);
1824 if (class->exception_type) {
1825 mono_domain_unlock (domain);
1826 mono_loader_unlock ();
1828 mono_raise_exception (mono_class_get_exception_for_failure (class));
1833 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1834 if (class->interface_offsets_count) {
1835 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1836 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1837 mono_stats.imt_number_of_tables++;
1838 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1841 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1842 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1845 mono_stats.used_class_count++;
1846 mono_stats.class_vtable_size += vtable_size;
1847 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1850 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1852 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1854 vt->rank = class->rank;
1855 vt->domain = domain;
1857 mono_class_compute_gc_descriptor (class);
1859 * We can't use typed allocation in the non-root domains, since the
1860 * collector needs the GC descriptor stored in the vtable even after
1861 * the mempool containing the vtable is destroyed when the domain is
1862 * unloaded. An alternative might be to allocate vtables in the GC
1863 * heap, but this does not seem to work (it leads to crashes inside
1864 * libgc). If that approach is tried, two gc descriptors need to be
1865 * allocated for each class: one for the root domain, and one for all
1866 * other domains. The second descriptor should contain a bit for the
1867 * vtable field in MonoObject, since we can no longer assume the
1868 * vtable is reachable by other roots after the appdomain is unloaded.
1870 #ifdef HAVE_BOEHM_GC
1871 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1872 vt->gc_descr = GC_NO_DESCRIPTOR;
1875 vt->gc_descr = class->gc_descr;
1877 if ((class_size = mono_class_data_size (class))) {
1878 if (class->has_static_refs) {
1879 gpointer statics_gc_descr;
1881 gsize default_bitmap [4] = {0};
1884 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1885 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1886 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1887 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1888 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1889 if (bitmap != default_bitmap)
1892 vt->data = mono_domain_alloc0 (domain, class_size);
1894 mono_stats.class_static_data_size += class_size;
1899 while ((field = mono_class_get_fields (class, &iter))) {
1900 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1902 if (mono_field_is_deleted (field))
1904 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1905 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1906 if (special_static != SPECIAL_STATIC_NONE) {
1907 guint32 size, offset;
1909 size = mono_type_size (field->type, &align);
1910 offset = mono_alloc_special_static_data (special_static, size, align);
1911 if (!domain->special_static_fields)
1912 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1913 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1915 * This marks the field as special static to speed up the
1916 * checks in mono_field_static_get/set_value ().
1922 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1923 MonoClass *fklass = mono_class_from_mono_type (field->type);
1924 const char *data = mono_field_get_data (field);
1926 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1927 t = (char*)vt->data + field->offset;
1928 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1931 if (fklass->valuetype) {
1932 memcpy (t, data, mono_class_value_size (fklass, NULL));
1934 /* it's a pointer type: add check */
1935 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1942 vt->max_interface_id = class->max_interface_id;
1943 vt->interface_bitmap = class->interface_bitmap;
1945 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1946 // class->name, class->interface_offsets_count);
1948 if (! ARCH_USE_IMT) {
1949 /* initialize interface offsets */
1950 for (i = 0; i < class->interface_offsets_count; ++i) {
1951 int interface_id = class->interfaces_packed [i]->interface_id;
1952 int slot = class->interface_offsets_packed [i];
1953 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1957 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1958 * as we change the code in appdomain.c to invalidate vtables by
1959 * looking at the possible MonoClasses created for the domain.
1961 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1962 /* class->runtime_info is protected by the loader lock, both when
1963 * it it enlarged and when it is stored info.
1966 old_info = class->runtime_info;
1967 if (old_info && old_info->max_domain >= domain->domain_id) {
1968 /* someone already created a large enough runtime info */
1969 mono_memory_barrier ();
1970 old_info->domain_vtables [domain->domain_id] = vt;
1972 int new_size = domain->domain_id;
1974 new_size = MAX (new_size, old_info->max_domain);
1976 /* make the new size a power of two */
1978 while (new_size > i)
1981 /* this is a bounded memory retention issue: may want to
1982 * handle it differently when we'll have a rcu-like system.
1984 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1985 runtime_info->max_domain = new_size - 1;
1986 /* copy the stuff from the older info */
1988 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1990 runtime_info->domain_vtables [domain->domain_id] = vt;
1992 mono_memory_barrier ();
1993 class->runtime_info = runtime_info;
1996 /* Initialize vtable */
1997 if (callbacks.get_vtable_trampoline) {
1998 // This also covers the AOT case
1999 for (i = 0; i < class->vtable_size; ++i) {
2000 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2003 mono_class_setup_vtable (class);
2005 for (i = 0; i < class->vtable_size; ++i) {
2008 if ((cm = class->vtable [i]))
2009 vt->vtable [i] = arch_create_jit_trampoline (cm);
2013 if (ARCH_USE_IMT && imt_table_bytes) {
2014 /* Now that the vtable is full, we can actually fill up the IMT */
2015 if (imt_trampoline) {
2016 /* lazy construction of the IMT entries enabled */
2017 for (i = 0; i < MONO_IMT_SIZE; ++i)
2018 interface_offsets [i] = imt_trampoline;
2020 build_imt (class, vt, domain, interface_offsets, NULL);
2024 mono_domain_unlock (domain);
2025 mono_loader_unlock ();
2027 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2028 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2029 mono_raise_exception (mono_class_get_exception_for_failure (class));
2031 /* make sure the parent is initialized */
2032 /*FIXME shouldn't this fail the current type?*/
2034 mono_class_vtable_full (domain, class->parent, raise_on_error);
2036 /*FIXME check for OOM*/
2037 vt->type = mono_type_get_object (domain, &class->byval_arg);
2039 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2040 static void *type_desc = NULL;
2044 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2047 /* This is unregistered in
2048 unregister_vtable_reflection_type() in
2050 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2053 if (class->contextbound)
2062 * mono_class_proxy_vtable:
2063 * @domain: the application domain
2064 * @remove_class: the remote class
2066 * Creates a vtable for transparent proxies. It is basically
2067 * a copy of the real vtable of the class wrapped in @remote_class,
2068 * but all function pointers invoke the remoting functions, and
2069 * vtable->klass points to the transparent proxy class, and not to @class.
2072 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2075 MonoVTable *vt, *pvt;
2076 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2078 GSList *extra_interfaces = NULL;
2079 MonoClass *class = remote_class->proxy_class;
2080 gpointer *interface_offsets;
2082 vt = mono_class_vtable (domain, class);
2083 g_assert (vt); /*FIXME property handle failure*/
2084 max_interface_id = vt->max_interface_id;
2086 /* Calculate vtable space for extra interfaces */
2087 for (j = 0; j < remote_class->interface_count; j++) {
2088 MonoClass* iclass = remote_class->interfaces[j];
2092 /*FIXME test for interfaces with variant generic arguments*/
2093 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2094 continue; /* interface implemented by the class */
2095 if (g_slist_find (extra_interfaces, iclass))
2098 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2100 method_count = mono_class_num_methods (iclass);
2102 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2103 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2105 for (i = 0; i < ifaces->len; ++i) {
2106 MonoClass *ic = g_ptr_array_index (ifaces, i);
2107 /*FIXME test for interfaces with variant generic arguments*/
2108 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2109 continue; /* interface implemented by the class */
2110 if (g_slist_find (extra_interfaces, ic))
2112 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2113 method_count += mono_class_num_methods (ic);
2115 g_ptr_array_free (ifaces, TRUE);
2118 extra_interface_vtsize += method_count * sizeof (gpointer);
2119 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2123 mono_stats.imt_number_of_tables++;
2124 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2125 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2126 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2128 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2129 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2132 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2134 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2136 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2138 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2139 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2141 pvt->klass = mono_defaults.transparent_proxy_class;
2142 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2143 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2145 /* initialize vtable */
2146 mono_class_setup_vtable (class);
2147 for (i = 0; i < class->vtable_size; ++i) {
2150 if ((cm = class->vtable [i]))
2151 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2153 pvt->vtable [i] = NULL;
2156 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2157 /* create trampolines for abstract methods */
2158 for (k = class; k; k = k->parent) {
2160 gpointer iter = NULL;
2161 while ((m = mono_class_get_methods (k, &iter)))
2162 if (!pvt->vtable [m->slot])
2163 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2167 pvt->max_interface_id = max_interface_id;
2168 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2170 if (! ARCH_USE_IMT) {
2171 /* initialize interface offsets */
2172 for (i = 0; i < class->interface_offsets_count; ++i) {
2173 int interface_id = class->interfaces_packed [i]->interface_id;
2174 int slot = class->interface_offsets_packed [i];
2175 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2178 for (i = 0; i < class->interface_offsets_count; ++i) {
2179 int interface_id = class->interfaces_packed [i]->interface_id;
2180 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2183 if (extra_interfaces) {
2184 int slot = class->vtable_size;
2190 /* Create trampolines for the methods of the interfaces */
2191 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2192 interf = list_item->data;
2194 if (! ARCH_USE_IMT) {
2195 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2197 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2201 while ((cm = mono_class_get_methods (interf, &iter)))
2202 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2204 slot += mono_class_num_methods (interf);
2206 if (! ARCH_USE_IMT) {
2207 g_slist_free (extra_interfaces);
2212 /* Now that the vtable is full, we can actually fill up the IMT */
2213 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2214 if (extra_interfaces) {
2215 g_slist_free (extra_interfaces);
2223 * mono_class_field_is_special_static:
2225 * Returns whether @field is a thread/context static field.
2228 mono_class_field_is_special_static (MonoClassField *field)
2230 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2232 if (mono_field_is_deleted (field))
2234 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2235 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2242 * mono_class_has_special_static_fields:
2244 * Returns whenever @klass has any thread/context static fields.
2247 mono_class_has_special_static_fields (MonoClass *klass)
2249 MonoClassField *field;
2253 while ((field = mono_class_get_fields (klass, &iter))) {
2254 g_assert (field->parent == klass);
2255 if (mono_class_field_is_special_static (field))
2263 * create_remote_class_key:
2264 * Creates an array of pointers that can be used as a hash key for a remote class.
2265 * The first element of the array is the number of pointers.
2268 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2273 if (remote_class == NULL) {
2274 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2275 key = g_malloc (sizeof(gpointer) * 3);
2276 key [0] = GINT_TO_POINTER (2);
2277 key [1] = mono_defaults.marshalbyrefobject_class;
2278 key [2] = extra_class;
2280 key = g_malloc (sizeof(gpointer) * 2);
2281 key [0] = GINT_TO_POINTER (1);
2282 key [1] = extra_class;
2285 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2286 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2287 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2288 key [1] = remote_class->proxy_class;
2290 // Keep the list of interfaces sorted
2291 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2292 if (extra_class && remote_class->interfaces [i] > extra_class) {
2293 key [j++] = extra_class;
2296 key [j] = remote_class->interfaces [i];
2299 key [j] = extra_class;
2301 // Replace the old class. The interface list is the same
2302 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2303 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2304 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2305 for (i = 0; i < remote_class->interface_count; i++)
2306 key [2 + i] = remote_class->interfaces [i];
2314 * copy_remote_class_key:
2316 * Make a copy of KEY in the domain and return the copy.
2319 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2321 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2322 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2324 memcpy (mp_key, key, key_size);
2330 * mono_remote_class:
2331 * @domain: the application domain
2332 * @class_name: name of the remote class
2334 * Creates and initializes a MonoRemoteClass object for a remote type.
2336 * Can raise an exception on failure.
2339 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2342 MonoRemoteClass *rc;
2343 gpointer* key, *mp_key;
2346 key = create_remote_class_key (NULL, proxy_class);
2348 mono_domain_lock (domain);
2349 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2353 mono_domain_unlock (domain);
2357 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2358 if (!mono_error_ok (&error)) {
2360 mono_domain_unlock (domain);
2361 mono_error_raise_exception (&error);
2364 mp_key = copy_remote_class_key (domain, key);
2368 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2369 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2370 rc->interface_count = 1;
2371 rc->interfaces [0] = proxy_class;
2372 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2374 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2375 rc->interface_count = 0;
2376 rc->proxy_class = proxy_class;
2379 rc->default_vtable = NULL;
2380 rc->xdomain_vtable = NULL;
2381 rc->proxy_class_name = name;
2382 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2384 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2386 mono_domain_unlock (domain);
2391 * clone_remote_class:
2392 * Creates a copy of the remote_class, adding the provided class or interface
2394 static MonoRemoteClass*
2395 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2397 MonoRemoteClass *rc;
2398 gpointer* key, *mp_key;
2400 key = create_remote_class_key (remote_class, extra_class);
2401 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2407 mp_key = copy_remote_class_key (domain, key);
2411 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2413 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2414 rc->proxy_class = remote_class->proxy_class;
2415 rc->interface_count = remote_class->interface_count + 1;
2417 // Keep the list of interfaces sorted, since the hash key of
2418 // the remote class depends on this
2419 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2420 if (remote_class->interfaces [i] > extra_class && i == j)
2421 rc->interfaces [j++] = extra_class;
2422 rc->interfaces [j] = remote_class->interfaces [i];
2425 rc->interfaces [j] = extra_class;
2427 // Replace the old class. The interface array is the same
2428 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2429 rc->proxy_class = extra_class;
2430 rc->interface_count = remote_class->interface_count;
2431 if (rc->interface_count > 0)
2432 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2435 rc->default_vtable = NULL;
2436 rc->xdomain_vtable = NULL;
2437 rc->proxy_class_name = remote_class->proxy_class_name;
2439 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2445 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2447 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2448 mono_domain_lock (domain);
2449 if (rp->target_domain_id != -1) {
2450 if (remote_class->xdomain_vtable == NULL)
2451 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2452 mono_domain_unlock (domain);
2453 mono_loader_unlock ();
2454 return remote_class->xdomain_vtable;
2456 if (remote_class->default_vtable == NULL) {
2459 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2460 klass = mono_class_from_mono_type (type);
2461 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2462 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2464 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2467 mono_domain_unlock (domain);
2468 mono_loader_unlock ();
2469 return remote_class->default_vtable;
2473 * mono_upgrade_remote_class:
2474 * @domain: the application domain
2475 * @tproxy: the proxy whose remote class has to be upgraded.
2476 * @klass: class to which the remote class can be casted.
2478 * Updates the vtable of the remote class by adding the necessary method slots
2479 * and interface offsets so it can be safely casted to klass. klass can be a
2480 * class or an interface.
2483 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2485 MonoTransparentProxy *tproxy;
2486 MonoRemoteClass *remote_class;
2487 gboolean redo_vtable;
2489 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2490 mono_domain_lock (domain);
2492 tproxy = (MonoTransparentProxy*) proxy_object;
2493 remote_class = tproxy->remote_class;
2495 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2498 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2499 if (remote_class->interfaces [i] == klass)
2500 redo_vtable = FALSE;
2503 redo_vtable = (remote_class->proxy_class != klass);
2507 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2508 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2511 mono_domain_unlock (domain);
2512 mono_loader_unlock ();
2517 * mono_object_get_virtual_method:
2518 * @obj: object to operate on.
2521 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2522 * the instance of a callvirt of method.
2525 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2528 MonoMethod **vtable;
2530 MonoMethod *res = NULL;
2532 klass = mono_object_class (obj);
2533 if (klass == mono_defaults.transparent_proxy_class) {
2534 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2540 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2543 mono_class_setup_vtable (klass);
2544 vtable = klass->vtable;
2546 if (method->slot == -1) {
2547 /* method->slot might not be set for instances of generic methods */
2548 if (method->is_inflated) {
2549 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2550 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2553 g_assert_not_reached ();
2557 /* check method->slot is a valid index: perform isinstance? */
2558 if (method->slot != -1) {
2559 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2561 gboolean variance_used = FALSE;
2562 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2563 g_assert (iface_offset > 0);
2564 res = vtable [iface_offset + method->slot];
2567 res = vtable [method->slot];
2572 /* It may be an interface, abstract class method or generic method */
2573 if (!res || mono_method_signature (res)->generic_param_count)
2576 /* generic methods demand invoke_with_check */
2577 if (mono_method_signature (res)->generic_param_count)
2578 res = mono_marshal_get_remoting_invoke_with_check (res);
2581 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2582 res = mono_cominterop_get_invoke (res);
2585 res = mono_marshal_get_remoting_invoke (res);
2588 if (method->is_inflated) {
2589 /* Have to inflate the result */
2590 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2600 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2602 g_error ("runtime invoke called on uninitialized runtime");
2606 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2609 * mono_runtime_invoke:
2610 * @method: method to invoke
2611 * @obJ: object instance
2612 * @params: arguments to the method
2613 * @exc: exception information.
2615 * Invokes the method represented by @method on the object @obj.
2617 * obj is the 'this' pointer, it should be NULL for static
2618 * methods, a MonoObject* for object instances and a pointer to
2619 * the value type for value types.
2621 * The params array contains the arguments to the method with the
2622 * same convention: MonoObject* pointers for object instances and
2623 * pointers to the value type otherwise.
2625 * From unmanaged code you'll usually use the
2626 * mono_runtime_invoke() variant.
2628 * Note that this function doesn't handle virtual methods for
2629 * you, it will exec the exact method you pass: we still need to
2630 * expose a function to lookup the derived class implementation
2631 * of a virtual method (there are examples of this in the code,
2634 * You can pass NULL as the exc argument if you don't want to
2635 * catch exceptions, otherwise, *exc will be set to the exception
2636 * thrown, if any. if an exception is thrown, you can't use the
2637 * MonoObject* result from the function.
2639 * If the method returns a value type, it is boxed in an object
2643 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2647 if (mono_runtime_get_no_exec ())
2648 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2650 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2651 mono_profiler_method_start_invoke (method);
2653 result = default_mono_runtime_invoke (method, obj, params, exc);
2655 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2656 mono_profiler_method_end_invoke (method);
2662 * mono_method_get_unmanaged_thunk:
2663 * @method: method to generate a thunk for.
2665 * Returns an unmanaged->managed thunk that can be used to call
2666 * a managed method directly from C.
2668 * The thunk's C signature closely matches the managed signature:
2670 * C#: public bool Equals (object obj);
2671 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2672 * MonoObject*, MonoException**);
2674 * The 1st ("this") parameter must not be used with static methods:
2676 * C#: public static bool ReferenceEquals (object a, object b);
2677 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2680 * The last argument must be a non-null pointer of a MonoException* pointer.
2681 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2682 * exception has been thrown in managed code. Otherwise it will point
2683 * to the MonoException* caught by the thunk. In this case, the result of
2684 * the thunk is undefined:
2686 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2687 * MonoException *ex = NULL;
2688 * Equals func = mono_method_get_unmanaged_thunk (method);
2689 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2691 * // handle exception
2694 * The calling convention of the thunk matches the platform's default
2695 * convention. This means that under Windows, C declarations must
2696 * contain the __stdcall attribute:
2698 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2699 * MonoObject*, MonoException**);
2703 * Value type arguments and return values are treated as they were objects:
2705 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2706 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2708 * Arguments must be properly boxed upon trunk's invocation, while return
2709 * values must be unboxed.
2712 mono_method_get_unmanaged_thunk (MonoMethod *method)
2714 method = mono_marshal_get_thunk_invoke_wrapper (method);
2715 return mono_compile_method (method);
2719 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2723 /* object fields cannot be byref, so we don't need a
2725 gpointer *p = (gpointer*)dest;
2732 case MONO_TYPE_BOOLEAN:
2734 case MONO_TYPE_U1: {
2735 guint8 *p = (guint8*)dest;
2736 *p = value ? *(guint8*)value : 0;
2741 case MONO_TYPE_CHAR: {
2742 guint16 *p = (guint16*)dest;
2743 *p = value ? *(guint16*)value : 0;
2746 #if SIZEOF_VOID_P == 4
2751 case MONO_TYPE_U4: {
2752 gint32 *p = (gint32*)dest;
2753 *p = value ? *(gint32*)value : 0;
2756 #if SIZEOF_VOID_P == 8
2761 case MONO_TYPE_U8: {
2762 gint64 *p = (gint64*)dest;
2763 *p = value ? *(gint64*)value : 0;
2766 case MONO_TYPE_R4: {
2767 float *p = (float*)dest;
2768 *p = value ? *(float*)value : 0;
2771 case MONO_TYPE_R8: {
2772 double *p = (double*)dest;
2773 *p = value ? *(double*)value : 0;
2776 case MONO_TYPE_STRING:
2777 case MONO_TYPE_SZARRAY:
2778 case MONO_TYPE_CLASS:
2779 case MONO_TYPE_OBJECT:
2780 case MONO_TYPE_ARRAY:
2781 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2783 case MONO_TYPE_FNPTR:
2784 case MONO_TYPE_PTR: {
2785 gpointer *p = (gpointer*)dest;
2786 *p = deref_pointer? *(gpointer*)value: value;
2789 case MONO_TYPE_VALUETYPE:
2790 /* note that 't' and 'type->type' can be different */
2791 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2792 t = mono_class_enum_basetype (type->data.klass)->type;
2795 MonoClass *class = mono_class_from_mono_type (type);
2796 int size = mono_class_value_size (class, NULL);
2798 memset (dest, 0, size);
2800 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2803 case MONO_TYPE_GENERICINST:
2804 t = type->data.generic_class->container_class->byval_arg.type;
2807 g_warning ("got type %x", type->type);
2808 g_assert_not_reached ();
2813 * mono_field_set_value:
2814 * @obj: Instance object
2815 * @field: MonoClassField describing the field to set
2816 * @value: The value to be set
2818 * Sets the value of the field described by @field in the object instance @obj
2819 * to the value passed in @value. This method should only be used for instance
2820 * fields. For static fields, use mono_field_static_set_value.
2822 * The value must be on the native format of the field type.
2825 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2829 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2831 dest = (char*)obj + field->offset;
2832 set_value (field->type, dest, value, FALSE);
2836 * mono_field_static_set_value:
2837 * @field: MonoClassField describing the field to set
2838 * @value: The value to be set
2840 * Sets the value of the static field described by @field
2841 * to the value passed in @value.
2843 * The value must be on the native format of the field type.
2846 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2850 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2851 /* you cant set a constant! */
2852 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2854 if (field->offset == -1) {
2855 /* Special static */
2856 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2857 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2859 dest = (char*)vt->data + field->offset;
2861 set_value (field->type, dest, value, FALSE);
2864 /* Used by the debugger */
2866 mono_vtable_get_static_field_data (MonoVTable *vt)
2872 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2876 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2877 if (field->offset == -1) {
2878 /* Special static */
2879 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2880 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2882 src = (guint8*)vt->data + field->offset;
2885 src = (guint8*)obj + field->offset;
2892 * mono_field_get_value:
2893 * @obj: Object instance
2894 * @field: MonoClassField describing the field to fetch information from
2895 * @value: pointer to the location where the value will be stored
2897 * Use this routine to get the value of the field @field in the object
2900 * The pointer provided by value must be of the field type, for reference
2901 * types this is a MonoObject*, for value types its the actual pointer to
2906 * mono_field_get_value (obj, int_field, &i);
2909 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2913 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2915 src = (char*)obj + field->offset;
2916 set_value (field->type, value, src, TRUE);
2920 * mono_field_get_value_object:
2921 * @domain: domain where the object will be created (if boxing)
2922 * @field: MonoClassField describing the field to fetch information from
2923 * @obj: The object instance for the field.
2925 * Returns: a new MonoObject with the value from the given field. If the
2926 * field represents a value type, the value is boxed.
2930 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2934 MonoVTable *vtable = NULL;
2936 gboolean is_static = FALSE;
2937 gboolean is_ref = FALSE;
2939 switch (field->type->type) {
2940 case MONO_TYPE_STRING:
2941 case MONO_TYPE_OBJECT:
2942 case MONO_TYPE_CLASS:
2943 case MONO_TYPE_ARRAY:
2944 case MONO_TYPE_SZARRAY:
2949 case MONO_TYPE_BOOLEAN:
2952 case MONO_TYPE_CHAR:
2961 case MONO_TYPE_VALUETYPE:
2962 is_ref = field->type->byref;
2964 case MONO_TYPE_GENERICINST:
2965 is_ref = !field->type->data.generic_class->container_class->valuetype;
2968 g_error ("type 0x%x not handled in "
2969 "mono_field_get_value_object", field->type->type);
2973 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2975 vtable = mono_class_vtable (domain, field->parent);
2977 char *name = mono_type_get_full_name (field->parent);
2978 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2982 if (!vtable->initialized)
2983 mono_runtime_class_init (vtable);
2988 mono_field_static_get_value (vtable, field, &o);
2990 mono_field_get_value (obj, field, &o);
2995 /* boxed value type */
2996 klass = mono_class_from_mono_type (field->type);
2998 if (mono_class_is_nullable (klass))
2999 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3001 o = mono_object_new (domain, klass);
3002 v = ((gchar *) o) + sizeof (MonoObject);
3004 mono_field_static_get_value (vtable, field, v);
3006 mono_field_get_value (obj, field, v);
3013 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3016 const char *p = blob;
3017 mono_metadata_decode_blob_size (p, &p);
3020 case MONO_TYPE_BOOLEAN:
3023 *(guint8 *) value = *p;
3025 case MONO_TYPE_CHAR:
3028 *(guint16*) value = read16 (p);
3032 *(guint32*) value = read32 (p);
3036 *(guint64*) value = read64 (p);
3039 readr4 (p, (float*) value);
3042 readr8 (p, (double*) value);
3044 case MONO_TYPE_STRING:
3045 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3047 case MONO_TYPE_CLASS:
3048 *(gpointer*) value = NULL;
3052 g_warning ("type 0x%02x should not be in constant table", type);
3058 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3060 MonoTypeEnum def_type;
3063 data = mono_class_get_field_default_value (field, &def_type);
3064 mono_get_constant_value_from_blob (domain, def_type, data, value);
3068 * mono_field_static_get_value:
3069 * @vt: vtable to the object
3070 * @field: MonoClassField describing the field to fetch information from
3071 * @value: where the value is returned
3073 * Use this routine to get the value of the static field @field value.
3075 * The pointer provided by value must be of the field type, for reference
3076 * types this is a MonoObject*, for value types its the actual pointer to
3081 * mono_field_static_get_value (vt, int_field, &i);
3084 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3088 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3090 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3091 get_default_field_value (vt->domain, field, value);
3095 if (field->offset == -1) {
3096 /* Special static */
3097 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3098 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3100 src = (char*)vt->data + field->offset;
3102 set_value (field->type, value, src, TRUE);
3106 * mono_property_set_value:
3107 * @prop: MonoProperty to set
3108 * @obj: instance object on which to act
3109 * @params: parameters to pass to the propery
3110 * @exc: optional exception
3112 * Invokes the property's set method with the given arguments on the
3113 * object instance obj (or NULL for static properties).
3115 * You can pass NULL as the exc argument if you don't want to
3116 * catch exceptions, otherwise, *exc will be set to the exception
3117 * thrown, if any. if an exception is thrown, you can't use the
3118 * MonoObject* result from the function.
3121 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3123 default_mono_runtime_invoke (prop->set, obj, params, exc);
3127 * mono_property_get_value:
3128 * @prop: MonoProperty to fetch
3129 * @obj: instance object on which to act
3130 * @params: parameters to pass to the propery
3131 * @exc: optional exception
3133 * Invokes the property's get method with the given arguments on the
3134 * object instance obj (or NULL for static properties).
3136 * You can pass NULL as the exc argument if you don't want to
3137 * catch exceptions, otherwise, *exc will be set to the exception
3138 * thrown, if any. if an exception is thrown, you can't use the
3139 * MonoObject* result from the function.
3141 * Returns: the value from invoking the get method on the property.
3144 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3146 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3150 * mono_nullable_init:
3151 * @buf: The nullable structure to initialize.
3152 * @value: the value to initialize from
3153 * @klass: the type for the object
3155 * Initialize the nullable structure pointed to by @buf from @value which
3156 * should be a boxed value type. The size of @buf should be able to hold
3157 * as much data as the @klass->instance_size (which is the number of bytes
3158 * that will be copies).
3160 * Since Nullables have variable structure, we can not define a C
3161 * structure for them.
3164 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3166 MonoClass *param_class = klass->cast_class;
3168 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3169 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3171 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3173 if (param_class->has_references)
3174 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3176 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3178 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3183 * mono_nullable_box:
3184 * @buf: The buffer representing the data to be boxed
3185 * @klass: the type to box it as.
3187 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3191 mono_nullable_box (guint8 *buf, MonoClass *klass)
3193 MonoClass *param_class = klass->cast_class;
3195 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3196 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3198 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3199 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3200 if (param_class->has_references)
3201 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3203 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3211 * mono_get_delegate_invoke:
3212 * @klass: The delegate class
3214 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3217 mono_get_delegate_invoke (MonoClass *klass)
3221 /* This is called at runtime, so avoid the slower search in metadata */
3222 mono_class_setup_methods (klass);
3223 if (klass->exception_type)
3225 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3232 * mono_runtime_delegate_invoke:
3233 * @delegate: pointer to a delegate object.
3234 * @params: parameters for the delegate.
3235 * @exc: Pointer to the exception result.
3237 * Invokes the delegate method @delegate with the parameters provided.
3239 * You can pass NULL as the exc argument if you don't want to
3240 * catch exceptions, otherwise, *exc will be set to the exception
3241 * thrown, if any. if an exception is thrown, you can't use the
3242 * MonoObject* result from the function.
3245 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3249 im = mono_get_delegate_invoke (delegate->vtable->klass);
3252 return mono_runtime_invoke (im, delegate, params, exc);
3255 static char **main_args = NULL;
3256 static int num_main_args;
3259 * mono_runtime_get_main_args:
3261 * Returns: a MonoArray with the arguments passed to the main program
3264 mono_runtime_get_main_args (void)
3268 MonoDomain *domain = mono_domain_get ();
3273 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3275 for (i = 0; i < num_main_args; ++i)
3276 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3282 fire_process_exit_event (void)
3284 MonoClassField *field;
3285 MonoDomain *domain = mono_domain_get ();
3287 MonoObject *delegate, *exc;
3289 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3292 if (domain != mono_get_root_domain ())
3295 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3296 if (delegate == NULL)
3301 mono_runtime_delegate_invoke (delegate, pa, &exc);
3305 * mono_runtime_run_main:
3306 * @method: the method to start the application with (usually Main)
3307 * @argc: number of arguments from the command line
3308 * @argv: array of strings from the command line
3309 * @exc: excetption results
3311 * Execute a standard Main() method (argc/argv contains the
3312 * executable name). This method also sets the command line argument value
3313 * needed by System.Environment.
3318 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3322 MonoArray *args = NULL;
3323 MonoDomain *domain = mono_domain_get ();
3324 gchar *utf8_fullpath;
3327 g_assert (method != NULL);
3329 mono_thread_set_main (mono_thread_current ());
3331 main_args = g_new0 (char*, argc);
3332 num_main_args = argc;
3334 if (!g_path_is_absolute (argv [0])) {
3335 gchar *basename = g_path_get_basename (argv [0]);
3336 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3340 utf8_fullpath = mono_utf8_from_external (fullpath);
3341 if(utf8_fullpath == NULL) {
3342 /* Printing the arg text will cause glib to
3343 * whinge about "Invalid UTF-8", but at least
3344 * its relevant, and shows the problem text
3347 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3348 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3355 utf8_fullpath = mono_utf8_from_external (argv[0]);
3356 if(utf8_fullpath == NULL) {
3357 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3358 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3363 main_args [0] = utf8_fullpath;
3365 for (i = 1; i < argc; ++i) {
3368 utf8_arg=mono_utf8_from_external (argv[i]);
3369 if(utf8_arg==NULL) {
3370 /* Ditto the comment about Invalid UTF-8 here */
3371 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3372 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3376 main_args [i] = utf8_arg;
3380 if (mono_method_signature (method)->param_count) {
3381 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3382 for (i = 0; i < argc; ++i) {
3383 /* The encodings should all work, given that
3384 * we've checked all these args for the
3387 gchar *str = mono_utf8_from_external (argv [i]);
3388 MonoString *arg = mono_string_new (domain, str);
3389 mono_array_setref (args, i, arg);
3393 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3396 mono_assembly_set_main (method->klass->image->assembly);
3398 result = mono_runtime_exec_main (method, args, exc);
3399 fire_process_exit_event ();
3404 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3406 static MonoMethod *serialize_method;
3411 if (!serialize_method) {
3412 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3413 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3416 if (!serialize_method) {
3421 g_assert (!mono_object_class (obj)->marshalbyref);
3425 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3433 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3435 static MonoMethod *deserialize_method;
3440 if (!deserialize_method) {
3441 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3442 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3444 if (!deserialize_method) {
3451 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3459 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3461 static MonoMethod *get_proxy_method;
3463 MonoDomain *domain = mono_domain_get ();
3464 MonoRealProxy *real_proxy;
3465 MonoReflectionType *reflection_type;
3466 MonoTransparentProxy *transparent_proxy;
3468 if (!get_proxy_method)
3469 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3471 g_assert (obj->vtable->klass->marshalbyref);
3473 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3474 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3476 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3477 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3480 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3484 return (MonoObject*) transparent_proxy;
3488 * mono_object_xdomain_representation
3490 * @target_domain: a domain
3491 * @exc: pointer to a MonoObject*
3493 * Creates a representation of obj in the domain target_domain. This
3494 * is either a copy of obj arrived through via serialization and
3495 * deserialization or a proxy, depending on whether the object is
3496 * serializable or marshal by ref. obj must not be in target_domain.
3498 * If the object cannot be represented in target_domain, NULL is
3499 * returned and *exc is set to an appropriate exception.
3502 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3504 MonoObject *deserialized = NULL;
3505 gboolean failure = FALSE;
3509 if (mono_object_class (obj)->marshalbyref) {
3510 deserialized = make_transparent_proxy (obj, &failure, exc);
3512 MonoDomain *domain = mono_domain_get ();
3513 MonoObject *serialized;
3515 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3516 serialized = serialize_object (obj, &failure, exc);
3517 mono_domain_set_internal_with_options (target_domain, FALSE);
3519 deserialized = deserialize_object (serialized, &failure, exc);
3520 if (domain != target_domain)
3521 mono_domain_set_internal_with_options (domain, FALSE);
3524 return deserialized;
3527 /* Used in call_unhandled_exception_delegate */
3529 create_unhandled_exception_eventargs (MonoObject *exc)
3533 MonoMethod *method = NULL;
3534 MonoBoolean is_terminating = TRUE;
3537 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3540 mono_class_init (klass);
3542 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3543 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3547 args [1] = &is_terminating;
3549 obj = mono_object_new (mono_domain_get (), klass);
3550 mono_runtime_invoke (method, obj, args, NULL);
3555 /* Used in mono_unhandled_exception */
3557 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3558 MonoObject *e = NULL;
3560 MonoDomain *current_domain = mono_domain_get ();
3562 if (domain != current_domain)
3563 mono_domain_set_internal_with_options (domain, FALSE);
3565 g_assert (domain == mono_object_domain (domain->domain));
3567 if (mono_object_domain (exc) != domain) {
3568 MonoObject *serialization_exc;
3570 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3572 if (serialization_exc) {
3574 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3577 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3578 "System.Runtime.Serialization", "SerializationException",
3579 "Could not serialize unhandled exception.");
3583 g_assert (mono_object_domain (exc) == domain);
3585 pa [0] = domain->domain;
3586 pa [1] = create_unhandled_exception_eventargs (exc);
3587 mono_runtime_delegate_invoke (delegate, pa, &e);
3589 if (domain != current_domain)
3590 mono_domain_set_internal_with_options (current_domain, FALSE);
3594 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3595 if (!mono_error_ok (&error)) {
3596 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3597 mono_error_cleanup (&error);
3599 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3605 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3608 * mono_runtime_unhandled_exception_policy_set:
3609 * @policy: the new policy
3611 * This is a VM internal routine.
3613 * Sets the runtime policy for handling unhandled exceptions.
3616 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3617 runtime_unhandled_exception_policy = policy;
3621 * mono_runtime_unhandled_exception_policy_get:
3623 * This is a VM internal routine.
3625 * Gets the runtime policy for handling unhandled exceptions.
3627 MonoRuntimeUnhandledExceptionPolicy
3628 mono_runtime_unhandled_exception_policy_get (void) {
3629 return runtime_unhandled_exception_policy;
3633 * mono_unhandled_exception:
3634 * @exc: exception thrown
3636 * This is a VM internal routine.
3638 * We call this function when we detect an unhandled exception
3639 * in the default domain.
3641 * It invokes the * UnhandledException event in AppDomain or prints
3642 * a warning to the console
3645 mono_unhandled_exception (MonoObject *exc)
3647 MonoDomain *current_domain = mono_domain_get ();
3648 MonoDomain *root_domain = mono_get_root_domain ();
3649 MonoClassField *field;
3650 MonoObject *current_appdomain_delegate;
3651 MonoObject *root_appdomain_delegate;
3653 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3654 "UnhandledException");
3657 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3658 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3659 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3660 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3661 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3662 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3664 current_appdomain_delegate = NULL;
3667 /* set exitcode only if we will abort the process */
3669 mono_environment_exitcode_set (1);
3670 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3671 mono_print_unhandled_exception (exc);
3673 if (root_appdomain_delegate) {
3674 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3676 if (current_appdomain_delegate) {
3677 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3684 * Launch a new thread to execute a function
3686 * main_func is called back from the thread with main_args as the
3687 * parameter. The callback function is expected to start Main()
3688 * eventually. This function then waits for all managed threads to
3690 * It is not necesseray anymore to execute managed code in a subthread,
3691 * so this function should not be used anymore by default: just
3692 * execute the code and then call mono_thread_manage ().
3695 mono_runtime_exec_managed_code (MonoDomain *domain,
3696 MonoMainThreadFunc main_func,
3699 mono_thread_create (domain, main_func, main_args);
3701 mono_thread_manage ();
3705 * Execute a standard Main() method (args doesn't contain the
3709 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3714 MonoCustomAttrInfo* cinfo;
3715 gboolean has_stathread_attribute;
3716 MonoInternalThread* thread = mono_thread_internal_current ();
3722 domain = mono_object_domain (args);
3723 if (!domain->entry_assembly) {
3725 MonoAssembly *assembly;
3727 assembly = method->klass->image->assembly;
3728 domain->entry_assembly = assembly;
3729 /* Domains created from another domain already have application_base and configuration_file set */
3730 if (domain->setup->application_base == NULL) {
3731 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3734 if (domain->setup->configuration_file == NULL) {
3735 str = g_strconcat (assembly->image->name, ".config", NULL);
3736 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3738 mono_set_private_bin_path_from_config (domain);
3742 cinfo = mono_custom_attrs_from_method (method);
3744 static MonoClass *stathread_attribute = NULL;
3745 if (!stathread_attribute)
3746 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3747 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3749 mono_custom_attrs_free (cinfo);
3751 has_stathread_attribute = FALSE;
3753 if (has_stathread_attribute) {
3754 thread->apartment_state = ThreadApartmentState_STA;
3755 } else if (mono_framework_version () == 1) {
3756 thread->apartment_state = ThreadApartmentState_Unknown;
3758 thread->apartment_state = ThreadApartmentState_MTA;
3760 mono_thread_init_apartment_state ();
3762 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3764 /* FIXME: check signature of method */
3765 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3767 res = mono_runtime_invoke (method, NULL, pa, exc);
3769 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3773 mono_environment_exitcode_set (rval);
3775 mono_runtime_invoke (method, NULL, pa, exc);
3779 /* If the return type of Main is void, only
3780 * set the exitcode if an exception was thrown
3781 * (we don't want to blow away an
3782 * explicitly-set exit code)
3785 mono_environment_exitcode_set (rval);
3789 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3795 * mono_install_runtime_invoke:
3796 * @func: Function to install
3798 * This is a VM internal routine
3801 mono_install_runtime_invoke (MonoInvokeFunc func)
3803 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3808 * mono_runtime_invoke_array:
3809 * @method: method to invoke
3810 * @obJ: object instance
3811 * @params: arguments to the method
3812 * @exc: exception information.
3814 * Invokes the method represented by @method on the object @obj.
3816 * obj is the 'this' pointer, it should be NULL for static
3817 * methods, a MonoObject* for object instances and a pointer to
3818 * the value type for value types.
3820 * The params array contains the arguments to the method with the
3821 * same convention: MonoObject* pointers for object instances and
3822 * pointers to the value type otherwise. The _invoke_array
3823 * variant takes a C# object[] as the params argument (MonoArray
3824 * *params): in this case the value types are boxed inside the
3825 * respective reference representation.
3827 * From unmanaged code you'll usually use the
3828 * mono_runtime_invoke() variant.
3830 * Note that this function doesn't handle virtual methods for
3831 * you, it will exec the exact method you pass: we still need to
3832 * expose a function to lookup the derived class implementation
3833 * of a virtual method (there are examples of this in the code,
3836 * You can pass NULL as the exc argument if you don't want to
3837 * catch exceptions, otherwise, *exc will be set to the exception
3838 * thrown, if any. if an exception is thrown, you can't use the
3839 * MonoObject* result from the function.
3841 * If the method returns a value type, it is boxed in an object
3845 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3848 MonoMethodSignature *sig = mono_method_signature (method);
3849 gpointer *pa = NULL;
3852 gboolean has_byref_nullables = FALSE;
3854 if (NULL != params) {
3855 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3856 for (i = 0; i < mono_array_length (params); i++) {
3857 MonoType *t = sig->params [i];
3863 case MONO_TYPE_BOOLEAN:
3866 case MONO_TYPE_CHAR:
3875 case MONO_TYPE_VALUETYPE:
3876 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3877 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3878 pa [i] = mono_array_get (params, MonoObject*, i);
3880 has_byref_nullables = TRUE;
3882 /* MS seems to create the objects if a null is passed in */
3883 if (!mono_array_get (params, MonoObject*, i))
3884 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3888 * We can't pass the unboxed vtype byref to the callee, since
3889 * that would mean the callee would be able to modify boxed
3890 * primitive types. So we (and MS) make a copy of the boxed
3891 * object, pass that to the callee, and replace the original
3892 * boxed object in the arg array with the copy.
3894 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3895 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3896 mono_array_setref (params, i, copy);
3899 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3902 case MONO_TYPE_STRING:
3903 case MONO_TYPE_OBJECT:
3904 case MONO_TYPE_CLASS:
3905 case MONO_TYPE_ARRAY:
3906 case MONO_TYPE_SZARRAY:
3908 pa [i] = mono_array_addr (params, MonoObject*, i);
3909 // FIXME: I need to check this code path
3911 pa [i] = mono_array_get (params, MonoObject*, i);
3913 case MONO_TYPE_GENERICINST:
3915 t = &t->data.generic_class->container_class->this_arg;
3917 t = &t->data.generic_class->container_class->byval_arg;
3919 case MONO_TYPE_PTR: {
3922 /* The argument should be an IntPtr */
3923 arg = mono_array_get (params, MonoObject*, i);
3927 g_assert (arg->vtable->klass == mono_defaults.int_class);
3928 pa [i] = ((MonoIntPtr*)arg)->m_value;
3933 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3938 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3941 if (mono_class_is_nullable (method->klass)) {
3942 /* Need to create a boxed vtype instead */
3948 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3952 obj = mono_object_new (mono_domain_get (), method->klass);
3953 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3954 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3956 if (method->klass->valuetype)
3957 o = mono_object_unbox (obj);
3960 } else if (method->klass->valuetype) {
3961 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3964 mono_runtime_invoke (method, o, pa, exc);
3967 if (mono_class_is_nullable (method->klass)) {
3968 MonoObject *nullable;
3970 /* Convert the unboxed vtype into a Nullable structure */
3971 nullable = mono_object_new (mono_domain_get (), method->klass);
3973 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3974 obj = mono_object_unbox (nullable);
3977 /* obj must be already unboxed if needed */
3978 res = mono_runtime_invoke (method, obj, pa, exc);
3980 if (sig->ret->type == MONO_TYPE_PTR) {
3981 MonoClass *pointer_class;
3982 static MonoMethod *box_method;
3984 MonoObject *box_exc;
3987 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3988 * convert it to a Pointer object.
3990 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3992 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3994 g_assert (res->vtable->klass == mono_defaults.int_class);
3995 box_args [0] = ((MonoIntPtr*)res)->m_value;
3996 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3997 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3998 g_assert (!box_exc);
4001 if (has_byref_nullables) {
4003 * The runtime invoke wrapper already converted byref nullables back,
4004 * and stored them in pa, we just need to copy them back to the
4007 for (i = 0; i < mono_array_length (params); i++) {
4008 MonoType *t = sig->params [i];
4010 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4011 mono_array_setref (params, i, pa [i]);
4020 arith_overflow (void)
4022 mono_raise_exception (mono_get_exception_overflow ());
4026 * mono_object_allocate:
4027 * @size: number of bytes to allocate
4029 * This is a very simplistic routine until we have our GC-aware
4032 * Returns: an allocated object of size @size, or NULL on failure.
4034 static inline void *
4035 mono_object_allocate (size_t size, MonoVTable *vtable)
4038 mono_stats.new_object_count++;
4039 ALLOC_OBJECT (o, vtable, size);
4045 * mono_object_allocate_ptrfree:
4046 * @size: number of bytes to allocate
4048 * Note that the memory allocated is not zeroed.
4049 * Returns: an allocated object of size @size, or NULL on failure.
4051 static inline void *
4052 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4055 mono_stats.new_object_count++;
4056 ALLOC_PTRFREE (o, vtable, size);
4060 static inline void *
4061 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4064 ALLOC_TYPED (o, size, vtable);
4065 mono_stats.new_object_count++;
4072 * @klass: the class of the object that we want to create
4074 * Returns: a newly created object whose definition is
4075 * looked up using @klass. This will not invoke any constructors,
4076 * so the consumer of this routine has to invoke any constructors on
4077 * its own to initialize the object.
4079 * It returns NULL on failure.
4082 mono_object_new (MonoDomain *domain, MonoClass *klass)
4086 MONO_ARCH_SAVE_REGS;
4087 vtable = mono_class_vtable (domain, klass);
4090 return mono_object_new_specific (vtable);
4094 * mono_object_new_specific:
4095 * @vtable: the vtable of the object that we want to create
4097 * Returns: A newly created object with class and domain specified
4101 mono_object_new_specific (MonoVTable *vtable)
4105 MONO_ARCH_SAVE_REGS;
4107 /* check for is_com_object for COM Interop */
4108 if (vtable->remote || vtable->klass->is_com_object)
4111 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4114 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4117 mono_class_init (klass);
4119 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4121 vtable->domain->create_proxy_for_type_method = im;
4124 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4126 o = mono_runtime_invoke (im, NULL, pa, NULL);
4127 if (o != NULL) return o;
4130 return mono_object_new_alloc_specific (vtable);
4134 mono_object_new_alloc_specific (MonoVTable *vtable)
4138 if (!vtable->klass->has_references) {
4139 o = mono_object_new_ptrfree (vtable);
4140 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4141 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4143 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4144 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4146 if (G_UNLIKELY (vtable->klass->has_finalize))
4147 mono_object_register_finalizer (o);
4149 if (G_UNLIKELY (profile_allocs))
4150 mono_profiler_allocation (o, vtable->klass);
4155 mono_object_new_fast (MonoVTable *vtable)
4158 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4163 mono_object_new_ptrfree (MonoVTable *vtable)
4166 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4167 #if NEED_TO_ZERO_PTRFREE
4168 /* an inline memset is much faster for the common vcase of small objects
4169 * note we assume the allocated size is a multiple of sizeof (void*).
4171 if (vtable->klass->instance_size < 128) {
4173 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4174 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4180 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4187 mono_object_new_ptrfree_box (MonoVTable *vtable)
4190 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4191 /* the object will be boxed right away, no need to memzero it */
4196 * mono_class_get_allocation_ftn:
4198 * @for_box: the object will be used for boxing
4199 * @pass_size_in_words:
4201 * Return the allocation function appropriate for the given class.
4205 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4207 *pass_size_in_words = FALSE;
4209 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4210 profile_allocs = FALSE;
4212 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4213 return mono_object_new_specific;
4215 if (!vtable->klass->has_references) {
4216 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4218 return mono_object_new_ptrfree_box;
4219 return mono_object_new_ptrfree;
4222 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4224 return mono_object_new_fast;
4227 * FIXME: This is actually slower than mono_object_new_fast, because
4228 * of the overhead of parameter passing.
4231 *pass_size_in_words = TRUE;
4232 #ifdef GC_REDIRECT_TO_LOCAL
4233 return GC_local_gcj_fast_malloc;
4235 return GC_gcj_fast_malloc;
4240 return mono_object_new_specific;
4244 * mono_object_new_from_token:
4245 * @image: Context where the type_token is hosted
4246 * @token: a token of the type that we want to create
4248 * Returns: A newly created object whose definition is
4249 * looked up using @token in the @image image
4252 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4256 class = mono_class_get (image, token);
4258 return mono_object_new (domain, class);
4263 * mono_object_clone:
4264 * @obj: the object to clone
4266 * Returns: A newly created object who is a shallow copy of @obj
4269 mono_object_clone (MonoObject *obj)
4272 int size = obj->vtable->klass->instance_size;
4274 o = mono_object_allocate (size, obj->vtable);
4276 if (obj->vtable->klass->has_references) {
4277 mono_gc_wbarrier_object_copy (o, obj);
4279 int size = obj->vtable->klass->instance_size;
4280 /* do not copy the sync state */
4281 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4283 if (G_UNLIKELY (profile_allocs))
4284 mono_profiler_allocation (o, obj->vtable->klass);
4286 if (obj->vtable->klass->has_finalize)
4287 mono_object_register_finalizer (o);
4292 * mono_array_full_copy:
4293 * @src: source array to copy
4294 * @dest: destination array
4296 * Copies the content of one array to another with exactly the same type and size.
4299 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4301 mono_array_size_t size;
4302 MonoClass *klass = src->obj.vtable->klass;
4304 MONO_ARCH_SAVE_REGS;
4306 g_assert (klass == dest->obj.vtable->klass);
4308 size = mono_array_length (src);
4309 g_assert (size == mono_array_length (dest));
4310 size *= mono_array_element_size (klass);
4312 if (klass->element_class->valuetype) {
4313 if (klass->element_class->has_references)
4314 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4316 memcpy (&dest->vector, &src->vector, size);
4318 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4321 memcpy (&dest->vector, &src->vector, size);
4326 * mono_array_clone_in_domain:
4327 * @domain: the domain in which the array will be cloned into
4328 * @array: the array to clone
4330 * This routine returns a copy of the array that is hosted on the
4331 * specified MonoDomain.
4334 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4337 mono_array_size_t size, i;
4338 mono_array_size_t *sizes;
4339 MonoClass *klass = array->obj.vtable->klass;
4341 MONO_ARCH_SAVE_REGS;
4343 if (array->bounds == NULL) {
4344 size = mono_array_length (array);
4345 o = mono_array_new_full (domain, klass, &size, NULL);
4347 size *= mono_array_element_size (klass);
4349 if (klass->element_class->valuetype) {
4350 if (klass->element_class->has_references)
4351 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4353 memcpy (&o->vector, &array->vector, size);
4355 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4358 memcpy (&o->vector, &array->vector, size);
4363 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4364 size = mono_array_element_size (klass);
4365 for (i = 0; i < klass->rank; ++i) {
4366 sizes [i] = array->bounds [i].length;
4367 size *= array->bounds [i].length;
4368 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4370 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4372 if (klass->element_class->valuetype) {
4373 if (klass->element_class->has_references)
4374 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4376 memcpy (&o->vector, &array->vector, size);
4378 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4381 memcpy (&o->vector, &array->vector, size);
4389 * @array: the array to clone
4391 * Returns: A newly created array who is a shallow copy of @array
4394 mono_array_clone (MonoArray *array)
4396 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4399 /* helper macros to check for overflow when calculating the size of arrays */
4400 #ifdef MONO_BIG_ARRAYS
4401 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4402 #define MYGUINT_MAX MYGUINT64_MAX
4403 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4404 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4405 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4406 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4407 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4409 #define MYGUINT32_MAX 4294967295U
4410 #define MYGUINT_MAX MYGUINT32_MAX
4411 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4412 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4413 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4414 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4415 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4419 mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
4421 mono_array_size_t byte_len;
4423 byte_len = mono_array_element_size (class);
4424 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4427 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4429 byte_len += sizeof (MonoArray);
4437 * mono_array_new_full:
4438 * @domain: domain where the object is created
4439 * @array_class: array class
4440 * @lengths: lengths for each dimension in the array
4441 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4443 * This routine creates a new array objects with the given dimensions,
4444 * lower bounds and type.
4447 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4449 mono_array_size_t byte_len, len, bounds_size;
4452 MonoArrayBounds *bounds;
4456 if (!array_class->inited)
4457 mono_class_init (array_class);
4461 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4462 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4464 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4468 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4470 for (i = 0; i < array_class->rank; ++i) {
4471 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4473 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4474 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4479 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4480 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4484 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4485 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4486 byte_len = (byte_len + 3) & ~3;
4487 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4488 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4489 byte_len += bounds_size;
4492 * Following three lines almost taken from mono_object_new ():
4493 * they need to be kept in sync.
4495 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4496 #ifndef HAVE_SGEN_GC
4497 if (!array_class->has_references) {
4498 o = mono_object_allocate_ptrfree (byte_len, vtable);
4499 #if NEED_TO_ZERO_PTRFREE
4500 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4502 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4503 o = mono_object_allocate_spec (byte_len, vtable);
4505 o = mono_object_allocate (byte_len, vtable);
4508 array = (MonoArray*)o;
4509 array->max_length = len;
4512 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4513 array->bounds = bounds;
4517 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4519 o = mono_gc_alloc_vector (vtable, byte_len, len);
4520 array = (MonoArray*)o;
4521 mono_stats.new_object_count++;
4523 bounds = array->bounds;
4527 for (i = 0; i < array_class->rank; ++i) {
4528 bounds [i].length = lengths [i];
4530 bounds [i].lower_bound = lower_bounds [i];
4534 if (G_UNLIKELY (profile_allocs))
4535 mono_profiler_allocation (o, array_class);
4542 * @domain: domain where the object is created
4543 * @eclass: element class
4544 * @n: number of array elements
4546 * This routine creates a new szarray with @n elements of type @eclass.
4549 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4553 MONO_ARCH_SAVE_REGS;
4555 ac = mono_array_class_get (eclass, 1);
4558 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4562 * mono_array_new_specific:
4563 * @vtable: a vtable in the appropriate domain for an initialized class
4564 * @n: number of array elements
4566 * This routine is a fast alternative to mono_array_new() for code which
4567 * can be sure about the domain it operates in.
4570 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4576 MONO_ARCH_SAVE_REGS;
4578 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4583 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4584 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4587 #ifndef HAVE_SGEN_GC
4588 if (!vtable->klass->has_references) {
4589 o = mono_object_allocate_ptrfree (byte_len, vtable);
4590 #if NEED_TO_ZERO_PTRFREE
4591 ((MonoArray*)o)->bounds = NULL;
4592 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4594 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4595 o = mono_object_allocate_spec (byte_len, vtable);
4597 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4598 o = mono_object_allocate (byte_len, vtable);
4601 ao = (MonoArray *)o;
4604 o = mono_gc_alloc_vector (vtable, byte_len, n);
4606 mono_stats.new_object_count++;
4609 if (G_UNLIKELY (profile_allocs))
4610 mono_profiler_allocation (o, vtable->klass);
4616 * mono_string_new_utf16:
4617 * @text: a pointer to an utf16 string
4618 * @len: the length of the string
4620 * Returns: A newly created string object which contains @text.
4623 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4627 s = mono_string_new_size (domain, len);
4628 g_assert (s != NULL);
4630 memcpy (mono_string_chars (s), text, len * 2);
4636 * mono_string_new_size:
4637 * @text: a pointer to an utf16 string
4638 * @len: the length of the string
4640 * Returns: A newly created string object of @len
4643 mono_string_new_size (MonoDomain *domain, gint32 len)
4647 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4649 /* overflow ? can't fit it, can't allocate it! */
4651 mono_gc_out_of_memory (-1);
4653 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4656 #ifndef HAVE_SGEN_GC
4657 s = mono_object_allocate_ptrfree (size, vtable);
4661 s = mono_gc_alloc_string (vtable, size, len);
4663 #if NEED_TO_ZERO_PTRFREE
4666 if (G_UNLIKELY (profile_allocs))
4667 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4673 * mono_string_new_len:
4674 * @text: a pointer to an utf8 string
4675 * @length: number of bytes in @text to consider
4677 * Returns: A newly created string object which contains @text.
4680 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4682 GError *error = NULL;
4683 MonoString *o = NULL;
4685 glong items_written;
4687 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4690 o = mono_string_new_utf16 (domain, ut, items_written);
4692 g_error_free (error);
4701 * @text: a pointer to an utf8 string
4703 * Returns: A newly created string object which contains @text.
4706 mono_string_new (MonoDomain *domain, const char *text)
4708 GError *error = NULL;
4709 MonoString *o = NULL;
4711 glong items_written;
4716 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4719 o = mono_string_new_utf16 (domain, ut, items_written);
4721 g_error_free (error);
4724 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4729 MonoString *o = NULL;
4731 if (!g_utf8_validate (text, -1, &end))
4734 len = g_utf8_strlen (text, -1);
4735 o = mono_string_new_size (domain, len);
4736 str = mono_string_chars (o);
4738 while (text < end) {
4739 *str++ = g_utf8_get_char (text);
4740 text = g_utf8_next_char (text);
4747 * mono_string_new_wrapper:
4748 * @text: pointer to utf8 characters.
4750 * Helper function to create a string object from @text in the current domain.
4753 mono_string_new_wrapper (const char *text)
4755 MonoDomain *domain = mono_domain_get ();
4757 MONO_ARCH_SAVE_REGS;
4760 return mono_string_new (domain, text);
4767 * @class: the class of the value
4768 * @value: a pointer to the unboxed data
4770 * Returns: A newly created object which contains @value.
4773 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4779 g_assert (class->valuetype);
4780 if (mono_class_is_nullable (class))
4781 return mono_nullable_box (value, class);
4783 vtable = mono_class_vtable (domain, class);
4786 size = mono_class_instance_size (class);
4787 res = mono_object_new_alloc_specific (vtable);
4788 if (G_UNLIKELY (profile_allocs))
4789 mono_profiler_allocation (res, class);
4791 size = size - sizeof (MonoObject);
4794 g_assert (size == mono_class_value_size (class, NULL));
4795 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4797 #if NO_UNALIGNED_ACCESS
4798 memcpy ((char *)res + sizeof (MonoObject), value, size);
4802 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4805 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4808 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4811 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4814 memcpy ((char *)res + sizeof (MonoObject), value, size);
4818 if (class->has_finalize)
4819 mono_object_register_finalizer (res);
4825 * @dest: destination pointer
4826 * @src: source pointer
4827 * @klass: a valuetype class
4829 * Copy a valuetype from @src to @dest. This function must be used
4830 * when @klass contains references fields.
4833 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4835 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4839 * mono_value_copy_array:
4840 * @dest: destination array
4841 * @dest_idx: index in the @dest array
4842 * @src: source pointer
4843 * @count: number of items
4845 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4846 * This function must be used when @klass contains references fields.
4847 * Overlap is handled.
4850 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4852 int size = mono_array_element_size (dest->obj.vtable->klass);
4853 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4854 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4855 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4859 * mono_object_get_domain:
4860 * @obj: object to query
4862 * Returns: the MonoDomain where the object is hosted
4865 mono_object_get_domain (MonoObject *obj)
4867 return mono_object_domain (obj);
4871 * mono_object_get_class:
4872 * @obj: object to query
4874 * Returns: the MonOClass of the object.
4877 mono_object_get_class (MonoObject *obj)
4879 return mono_object_class (obj);
4882 * mono_object_get_size:
4883 * @o: object to query
4885 * Returns: the size, in bytes, of @o
4888 mono_object_get_size (MonoObject* o)
4890 MonoClass* klass = mono_object_class (o);
4891 if (klass == mono_defaults.string_class) {
4892 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4893 } else if (o->vtable->rank) {
4894 MonoArray *array = (MonoArray*)o;
4895 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4896 if (array->bounds) {
4899 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4903 return mono_class_instance_size (klass);
4908 * mono_object_unbox:
4909 * @obj: object to unbox
4911 * Returns: a pointer to the start of the valuetype boxed in this
4914 * This method will assert if the object passed is not a valuetype.
4917 mono_object_unbox (MonoObject *obj)
4919 /* add assert for valuetypes? */
4920 g_assert (obj->vtable->klass->valuetype);
4921 return ((char*)obj) + sizeof (MonoObject);
4925 * mono_object_isinst:
4927 * @klass: a pointer to a class
4929 * Returns: @obj if @obj is derived from @klass
4932 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4935 mono_class_init (klass);
4937 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
4938 return mono_object_isinst_mbyref (obj, klass);
4943 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4947 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4956 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4957 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4961 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
4962 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
4965 MonoClass *oklass = vt->klass;
4966 if ((oklass == mono_defaults.transparent_proxy_class))
4967 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4969 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4973 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4975 MonoDomain *domain = mono_domain_get ();
4977 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4978 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4979 MonoMethod *im = NULL;
4982 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4983 im = mono_object_get_virtual_method (rp, im);
4986 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4989 res = mono_runtime_invoke (im, rp, pa, NULL);
4991 if (*(MonoBoolean *) mono_object_unbox(res)) {
4992 /* Update the vtable of the remote type, so it can safely cast to this new type */
4993 mono_upgrade_remote_class (domain, obj, klass);
5002 * mono_object_castclass_mbyref:
5004 * @klass: a pointer to a class
5006 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5009 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5011 if (!obj) return NULL;
5012 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5014 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5016 "InvalidCastException"));
5021 MonoDomain *orig_domain;
5027 str_lookup (MonoDomain *domain, gpointer user_data)
5029 LDStrInfo *info = user_data;
5030 if (info->res || domain == info->orig_domain)
5032 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5038 mono_string_get_pinned (MonoString *str)
5042 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5043 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5044 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5045 news->length = mono_string_length (str);
5050 #define mono_string_get_pinned(str) (str)
5054 mono_string_is_interned_lookup (MonoString *str, int insert)
5056 MonoGHashTable *ldstr_table;
5060 domain = ((MonoObject *)str)->vtable->domain;
5061 ldstr_table = domain->ldstr_table;
5063 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5068 str = mono_string_get_pinned (str);
5069 mono_g_hash_table_insert (ldstr_table, str, str);
5073 LDStrInfo ldstr_info;
5074 ldstr_info.orig_domain = domain;
5075 ldstr_info.ins = str;
5076 ldstr_info.res = NULL;
5078 mono_domain_foreach (str_lookup, &ldstr_info);
5079 if (ldstr_info.res) {
5081 * the string was already interned in some other domain:
5082 * intern it in the current one as well.
5084 mono_g_hash_table_insert (ldstr_table, str, str);
5094 * mono_string_is_interned:
5095 * @o: String to probe
5097 * Returns whether the string has been interned.
5100 mono_string_is_interned (MonoString *o)
5102 return mono_string_is_interned_lookup (o, FALSE);
5106 * mono_string_intern:
5107 * @o: String to intern
5109 * Interns the string passed.
5110 * Returns: The interned string.
5113 mono_string_intern (MonoString *str)
5115 return mono_string_is_interned_lookup (str, TRUE);
5120 * @domain: the domain where the string will be used.
5121 * @image: a metadata context
5122 * @idx: index into the user string table.
5124 * Implementation for the ldstr opcode.
5125 * Returns: a loaded string from the @image/@idx combination.
5128 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5130 MONO_ARCH_SAVE_REGS;
5132 if (image->dynamic) {
5133 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5134 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5135 mono_profiler_string_allocation (domain, str);
5138 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5139 return NULL; /*FIXME we should probably be raising an exception here*/
5140 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5145 * mono_ldstr_metadata_sig
5146 * @domain: the domain for the string
5147 * @sig: the signature of a metadata string
5149 * Returns: a MonoString for a string stored in the metadata
5152 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5154 const char *str = sig;
5155 MonoString *o, *interned;
5158 len2 = mono_metadata_decode_blob_size (str, &str);
5161 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5162 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5165 guint16 *p2 = (guint16*)mono_string_chars (o);
5166 for (i = 0; i < len2; ++i) {
5167 *p2 = GUINT16_FROM_LE (*p2);
5173 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5175 /* o will get garbage collected */
5179 o = mono_string_get_pinned (o);
5180 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5183 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5184 mono_profiler_string_allocation (domain, o);
5190 * mono_string_to_utf8:
5191 * @s: a System.String
5193 * Return the UTF8 representation for @s.
5194 * the resulting buffer nedds to be freed with g_free().
5196 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5199 mono_string_to_utf8 (MonoString *s)
5202 char *result = mono_string_to_utf8_checked (s, &error);
5204 if (!mono_error_ok (&error))
5205 mono_error_raise_exception (&error);
5210 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5214 GError *gerror = NULL;
5216 mono_error_init (error);
5222 return g_strdup ("");
5224 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5226 mono_error_set_argument (error, "string", "%s", gerror->message);
5227 g_error_free (gerror);
5230 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5231 if (s->length > written) {
5232 /* allocate the total length and copy the part of the string that has been converted */
5233 char *as2 = g_malloc0 (s->length);
5234 memcpy (as2, as, written);
5243 * mono_string_to_utf16:
5246 * Return an null-terminated array of the utf-16 chars
5247 * contained in @s. The result must be freed with g_free().
5248 * This is a temporary helper until our string implementation
5249 * is reworked to always include the null terminating char.
5252 mono_string_to_utf16 (MonoString *s)
5259 as = g_malloc ((s->length * 2) + 2);
5260 as [(s->length * 2)] = '\0';
5261 as [(s->length * 2) + 1] = '\0';
5264 return (gunichar2 *)(as);
5267 memcpy (as, mono_string_chars(s), s->length * 2);
5268 return (gunichar2 *)(as);
5272 * mono_string_from_utf16:
5273 * @data: the UTF16 string (LPWSTR) to convert
5275 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5277 * Returns: a MonoString.
5280 mono_string_from_utf16 (gunichar2 *data)
5282 MonoDomain *domain = mono_domain_get ();
5288 while (data [len]) len++;
5290 return mono_string_new_utf16 (domain, data, len);
5295 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5301 r = mono_string_to_utf8_checked (s, error);
5302 if (!mono_error_ok (error))
5308 len = strlen (r) + 1;
5310 mp_s = mono_mempool_alloc (mp, len);
5312 mp_s = mono_image_alloc (image, len);
5314 memcpy (mp_s, r, len);
5322 * mono_string_to_utf8_image:
5323 * @s: a System.String
5325 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5328 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5330 return mono_string_to_utf8_internal (NULL, image, s, error);
5334 * mono_string_to_utf8_mp:
5335 * @s: a System.String
5337 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5340 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5342 return mono_string_to_utf8_internal (mp, NULL, s, error);
5346 default_ex_handler (MonoException *ex)
5348 MonoObject *o = (MonoObject*)ex;
5349 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5353 static MonoExceptionFunc ex_handler = default_ex_handler;
5356 * mono_install_handler:
5357 * @func: exception handler
5359 * This is an internal JIT routine used to install the handler for exceptions
5363 mono_install_handler (MonoExceptionFunc func)
5365 ex_handler = func? func: default_ex_handler;
5369 * mono_raise_exception:
5370 * @ex: exception object
5372 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5375 mono_raise_exception (MonoException *ex)
5378 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5379 * that will cause gcc to omit the function epilog, causing problems when
5380 * the JIT tries to walk the stack, since the return address on the stack
5381 * will point into the next function in the executable, not this one.
5384 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5385 MonoInternalThread *thread = mono_thread_internal_current ();
5386 g_assert (ex->object.vtable->domain == mono_domain_get ());
5387 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5394 * mono_wait_handle_new:
5395 * @domain: Domain where the object will be created
5396 * @handle: Handle for the wait handle
5398 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5401 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5403 MonoWaitHandle *res;
5404 gpointer params [1];
5405 static MonoMethod *handle_set;
5407 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5409 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5411 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5413 params [0] = &handle;
5414 mono_runtime_invoke (handle_set, res, params, NULL);
5420 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5422 static MonoClassField *f_os_handle;
5423 static MonoClassField *f_safe_handle;
5425 if (!f_os_handle && !f_safe_handle) {
5426 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5427 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5432 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5436 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5443 mono_runtime_capture_context (MonoDomain *domain)
5445 RuntimeInvokeFunction runtime_invoke;
5447 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5448 MonoMethod *method = mono_get_context_capture_method ();
5449 MonoMethod *wrapper;
5452 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5453 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5454 domain->capture_context_method = mono_compile_method (method);
5457 runtime_invoke = domain->capture_context_runtime_invoke;
5459 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5462 * mono_async_result_new:
5463 * @domain:domain where the object will be created.
5464 * @handle: wait handle.
5465 * @state: state to pass to AsyncResult
5466 * @data: C closure data.
5468 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5469 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5473 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5475 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5476 MonoObject *context = mono_runtime_capture_context (domain);
5477 /* we must capture the execution context from the original thread */
5479 MONO_OBJECT_SETREF (res, execution_context, context);
5480 /* note: result may be null if the flow is suppressed */
5484 MONO_OBJECT_SETREF (res, object_data, object_data);
5485 MONO_OBJECT_SETREF (res, async_state, state);
5487 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5489 res->sync_completed = FALSE;
5490 res->completed = FALSE;
5496 mono_message_init (MonoDomain *domain,
5497 MonoMethodMessage *this,
5498 MonoReflectionMethod *method,
5499 MonoArray *out_args)
5501 static MonoClass *object_array_klass;
5502 static MonoClass *byte_array_klass;
5503 static MonoClass *string_array_klass;
5504 MonoMethodSignature *sig = mono_method_signature (method->method);
5510 if (!object_array_klass) {
5513 klass = mono_array_class_get (mono_defaults.object_class, 1);
5516 mono_memory_barrier ();
5517 object_array_klass = klass;
5519 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5522 mono_memory_barrier ();
5523 byte_array_klass = klass;
5525 klass = mono_array_class_get (mono_defaults.string_class, 1);
5528 mono_memory_barrier ();
5529 string_array_klass = klass;
5532 MONO_OBJECT_SETREF (this, method, method);
5534 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5535 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5536 this->async_result = NULL;
5537 this->call_type = CallType_Sync;
5539 names = g_new (char *, sig->param_count);
5540 mono_method_get_param_names (method->method, (const char **) names);
5541 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5543 for (i = 0; i < sig->param_count; i++) {
5544 name = mono_string_new (domain, names [i]);
5545 mono_array_setref (this->names, i, name);
5549 for (i = 0, j = 0; i < sig->param_count; i++) {
5550 if (sig->params [i]->byref) {
5552 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5553 mono_array_setref (this->args, i, arg);
5557 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5561 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5564 mono_array_set (this->arg_types, guint8, i, arg_type);
5569 * mono_remoting_invoke:
5570 * @real_proxy: pointer to a RealProxy object
5571 * @msg: The MonoMethodMessage to execute
5572 * @exc: used to store exceptions
5573 * @out_args: used to store output arguments
5575 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5576 * IMessage interface and it is not trivial to extract results from there. So
5577 * we call an helper method PrivateInvoke instead of calling
5578 * RealProxy::Invoke() directly.
5580 * Returns: the result object.
5583 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5584 MonoObject **exc, MonoArray **out_args)
5586 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5589 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5592 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5594 real_proxy->vtable->domain->private_invoke_method = im;
5597 pa [0] = real_proxy;
5602 return mono_runtime_invoke (im, NULL, pa, exc);
5606 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5607 MonoObject **exc, MonoArray **out_args)
5609 static MonoClass *object_array_klass;
5612 MonoMethodSignature *sig;
5614 int i, j, outarg_count = 0;
5616 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5618 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5619 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5620 target = tp->rp->unwrapped_server;
5622 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5626 domain = mono_domain_get ();
5627 method = msg->method->method;
5628 sig = mono_method_signature (method);
5630 for (i = 0; i < sig->param_count; i++) {
5631 if (sig->params [i]->byref)
5635 if (!object_array_klass) {
5638 klass = mono_array_class_get (mono_defaults.object_class, 1);
5641 mono_memory_barrier ();
5642 object_array_klass = klass;
5645 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5646 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5649 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5651 for (i = 0, j = 0; i < sig->param_count; i++) {
5652 if (sig->params [i]->byref) {
5654 arg = mono_array_get (msg->args, gpointer, i);
5655 mono_array_setref (*out_args, j, arg);
5664 * mono_print_unhandled_exception:
5665 * @exc: The exception
5667 * Prints the unhandled exception.
5670 mono_print_unhandled_exception (MonoObject *exc)
5673 char *message = (char *) "";
5677 gboolean free_message = FALSE;
5679 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5680 klass = exc->vtable->klass;
5682 while (klass && method == NULL) {
5683 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5685 klass = klass->parent;
5690 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5692 message = mono_string_to_utf8_checked (str, &error);
5693 if (!mono_error_ok (&error)) {
5694 mono_error_cleanup (&error);
5695 message = (char *)"";
5697 free_message = TRUE;
5703 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5704 * exc->vtable->klass->name, message);
5706 g_printerr ("\nUnhandled Exception: %s\n", message);
5713 * mono_delegate_ctor:
5714 * @this: pointer to an uninitialized delegate object
5715 * @target: target object
5716 * @addr: pointer to native code
5719 * Initialize a delegate and sets a specific method, not the one
5720 * associated with addr. This is useful when sharing generic code.
5721 * In that case addr will most probably not be associated with the
5722 * correct instantiation of the method.
5725 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5727 MonoDelegate *delegate = (MonoDelegate *)this;
5734 delegate->method = method;
5736 class = this->vtable->klass;
5737 mono_stats.delegate_creations++;
5739 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5741 method = mono_marshal_get_remoting_invoke (method);
5742 delegate->method_ptr = mono_compile_method (method);
5743 MONO_OBJECT_SETREF (delegate, target, target);
5744 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5745 method = mono_marshal_get_unbox_wrapper (method);
5746 delegate->method_ptr = mono_compile_method (method);
5747 MONO_OBJECT_SETREF (delegate, target, target);
5749 delegate->method_ptr = addr;
5750 MONO_OBJECT_SETREF (delegate, target, target);
5753 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5757 * mono_delegate_ctor:
5758 * @this: pointer to an uninitialized delegate object
5759 * @target: target object
5760 * @addr: pointer to native code
5762 * This is used to initialize a delegate.
5765 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5767 MonoDomain *domain = mono_domain_get ();
5769 MonoMethod *method = NULL;
5773 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5774 method = ji->method;
5775 g_assert (!method->klass->generic_container);
5778 mono_delegate_ctor_with_method (this, target, addr, method);
5782 * mono_method_call_message_new:
5783 * @method: method to encapsulate
5784 * @params: parameters to the method
5785 * @invoke: optional, delegate invoke.
5786 * @cb: async callback delegate.
5787 * @state: state passed to the async callback.
5789 * Translates arguments pointers into a MonoMethodMessage.
5792 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5793 MonoDelegate **cb, MonoObject **state)
5795 MonoDomain *domain = mono_domain_get ();
5796 MonoMethodSignature *sig = mono_method_signature (method);
5797 MonoMethodMessage *msg;
5800 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5803 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5804 count = sig->param_count - 2;
5806 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5807 count = sig->param_count;
5810 for (i = 0; i < count; i++) {
5815 if (sig->params [i]->byref)
5816 vpos = *((gpointer *)params [i]);
5820 type = sig->params [i]->type;
5821 class = mono_class_from_mono_type (sig->params [i]);
5823 if (class->valuetype)
5824 arg = mono_value_box (domain, class, vpos);
5826 arg = *((MonoObject **)vpos);
5828 mono_array_setref (msg->args, i, arg);
5831 if (cb != NULL && state != NULL) {
5832 *cb = *((MonoDelegate **)params [i]);
5834 *state = *((MonoObject **)params [i]);
5841 * mono_method_return_message_restore:
5843 * Restore results from message based processing back to arguments pointers
5846 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5848 MonoMethodSignature *sig = mono_method_signature (method);
5849 int i, j, type, size, out_len;
5851 if (out_args == NULL)
5853 out_len = mono_array_length (out_args);
5857 for (i = 0, j = 0; i < sig->param_count; i++) {
5858 MonoType *pt = sig->params [i];
5863 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5865 arg = mono_array_get (out_args, gpointer, j);
5868 g_assert (type != MONO_TYPE_VOID);
5870 if (MONO_TYPE_IS_REFERENCE (pt)) {
5871 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5874 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5875 size = mono_class_value_size (class, NULL);
5876 if (class->has_references)
5877 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5879 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5881 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5882 memset (*((gpointer *)params [i]), 0, size);
5892 * mono_load_remote_field:
5893 * @this: pointer to an object
5894 * @klass: klass of the object containing @field
5895 * @field: the field to load
5896 * @res: a storage to store the result
5898 * This method is called by the runtime on attempts to load fields of
5899 * transparent proxy objects. @this points to such TP, @klass is the class of
5900 * the object containing @field. @res is a storage location which can be
5901 * used to store the result.
5903 * Returns: an address pointing to the value of field.
5906 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5908 static MonoMethod *getter = NULL;
5909 MonoDomain *domain = mono_domain_get ();
5910 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5911 MonoClass *field_class;
5912 MonoMethodMessage *msg;
5913 MonoArray *out_args;
5917 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5918 g_assert (res != NULL);
5920 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5921 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5926 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5930 field_class = mono_class_from_mono_type (field->type);
5932 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5933 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5934 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5936 full_name = mono_type_get_full_name (klass);
5937 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5938 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5941 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5943 if (exc) mono_raise_exception ((MonoException *)exc);
5945 if (mono_array_length (out_args) == 0)
5948 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5950 if (field_class->valuetype) {
5951 return ((char *)*res) + sizeof (MonoObject);
5957 * mono_load_remote_field_new:
5962 * Missing documentation.
5965 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5967 static MonoMethod *getter = NULL;
5968 MonoDomain *domain = mono_domain_get ();
5969 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5970 MonoClass *field_class;
5971 MonoMethodMessage *msg;
5972 MonoArray *out_args;
5973 MonoObject *exc, *res;
5976 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5978 field_class = mono_class_from_mono_type (field->type);
5980 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5982 if (field_class->valuetype) {
5983 res = mono_object_new (domain, field_class);
5984 val = ((gchar *) res) + sizeof (MonoObject);
5988 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5993 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5997 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5998 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6000 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6002 full_name = mono_type_get_full_name (klass);
6003 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6004 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6007 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6009 if (exc) mono_raise_exception ((MonoException *)exc);
6011 if (mono_array_length (out_args) == 0)
6014 res = mono_array_get (out_args, MonoObject *, 0);
6020 * mono_store_remote_field:
6021 * @this: pointer to an object
6022 * @klass: klass of the object containing @field
6023 * @field: the field to load
6024 * @val: the value/object to store
6026 * This method is called by the runtime on attempts to store fields of
6027 * transparent proxy objects. @this points to such TP, @klass is the class of
6028 * the object containing @field. @val is the new value to store in @field.
6031 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6033 static MonoMethod *setter = NULL;
6034 MonoDomain *domain = mono_domain_get ();
6035 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6036 MonoClass *field_class;
6037 MonoMethodMessage *msg;
6038 MonoArray *out_args;
6043 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6045 field_class = mono_class_from_mono_type (field->type);
6047 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6048 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6049 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6054 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6058 if (field_class->valuetype)
6059 arg = mono_value_box (domain, field_class, val);
6061 arg = *((MonoObject **)val);
6064 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6065 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6067 full_name = mono_type_get_full_name (klass);
6068 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6069 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6070 mono_array_setref (msg->args, 2, arg);
6073 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6075 if (exc) mono_raise_exception ((MonoException *)exc);
6079 * mono_store_remote_field_new:
6085 * Missing documentation
6088 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6090 static MonoMethod *setter = NULL;
6091 MonoDomain *domain = mono_domain_get ();
6092 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6093 MonoClass *field_class;
6094 MonoMethodMessage *msg;
6095 MonoArray *out_args;
6099 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6101 field_class = mono_class_from_mono_type (field->type);
6103 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6104 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6105 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6110 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6114 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6115 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6117 full_name = mono_type_get_full_name (klass);
6118 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6119 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6120 mono_array_setref (msg->args, 2, arg);
6123 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6125 if (exc) mono_raise_exception ((MonoException *)exc);
6129 * mono_create_ftnptr:
6131 * Given a function address, create a function descriptor for it.
6132 * This is only needed on some platforms.
6135 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6137 return callbacks.create_ftnptr (domain, addr);
6141 * mono_get_addr_from_ftnptr:
6143 * Given a pointer to a function descriptor, return the function address.
6144 * This is only needed on some platforms.
6147 mono_get_addr_from_ftnptr (gpointer descr)
6149 return callbacks.get_addr_from_ftnptr (descr);
6154 * mono_string_chars:
6157 * Returns a pointer to the UCS16 characters stored in the MonoString
6160 mono_string_chars(MonoString *s)
6162 /* This method is here only for documentation extraction, this is a macro */
6166 * mono_string_length:
6169 * Returns the lenght in characters of the string
6172 mono_string_length (MonoString *s)
6174 /* This method is here only for documentation extraction, this is a macro */