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 #ifdef MONO_SMALL_CONFIG
1431 #define NUM_FREE_LISTS 6
1433 #define NUM_FREE_LISTS 12
1435 #define FIRST_FREE_LIST_SIZE 64
1436 #define MAX_WAIT_LENGTH 50
1437 #define THUNK_THRESHOLD 10
1440 * LOCKING: The domain lock must be held.
1443 init_thunk_free_lists (MonoDomain *domain)
1445 if (domain->thunk_free_lists)
1447 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1451 list_index_for_size (int item_size)
1454 int size = FIRST_FREE_LIST_SIZE;
1456 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1465 * mono_method_alloc_generic_virtual_thunk:
1467 * @size: size in bytes
1469 * Allocs size bytes to be used for the code of a generic virtual
1470 * thunk. It's either allocated from the domain's code manager or
1471 * reused from a previously invalidated piece.
1473 * LOCKING: The domain lock must be held.
1476 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1478 static gboolean inited = FALSE;
1479 static int generic_virtual_thunks_size = 0;
1483 MonoThunkFreeList **l;
1485 init_thunk_free_lists (domain);
1487 size += sizeof (guint32);
1488 if (size < sizeof (MonoThunkFreeList))
1489 size = sizeof (MonoThunkFreeList);
1491 i = list_index_for_size (size);
1492 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1493 if ((*l)->size >= size) {
1494 MonoThunkFreeList *item = *l;
1496 return ((guint32*)item) + 1;
1500 /* no suitable item found - search lists of larger sizes */
1501 while (++i < NUM_FREE_LISTS) {
1502 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1505 g_assert (item->size > size);
1506 domain->thunk_free_lists [i] = item->next;
1507 return ((guint32*)item) + 1;
1510 /* still nothing found - allocate it */
1512 mono_counters_register ("Generic virtual thunk bytes",
1513 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1516 generic_virtual_thunks_size += size;
1518 p = mono_domain_code_reserve (domain, size);
1525 * LOCKING: The domain lock must be held.
1528 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1531 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1533 init_thunk_free_lists (domain);
1535 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1536 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1537 int length = item->length;
1540 /* unlink the first item from the wait list */
1541 domain->thunk_free_lists [0] = item->next;
1542 domain->thunk_free_lists [0]->length = length - 1;
1544 i = list_index_for_size (item->size);
1546 /* put it in the free list */
1547 item->next = domain->thunk_free_lists [i];
1548 domain->thunk_free_lists [i] = item;
1552 if (domain->thunk_free_lists [1]) {
1553 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1554 domain->thunk_free_lists [0]->length++;
1556 g_assert (!domain->thunk_free_lists [0]);
1558 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1559 domain->thunk_free_lists [0]->length = 1;
1563 typedef struct _GenericVirtualCase {
1567 struct _GenericVirtualCase *next;
1568 } GenericVirtualCase;
1571 * get_generic_virtual_entries:
1573 * Return IMT entries for the generic virtual method instances and
1574 * variant interface methods for vtable slot
1577 static MonoImtBuilderEntry*
1578 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1580 GenericVirtualCase *list;
1581 MonoImtBuilderEntry *entries;
1583 mono_domain_lock (domain);
1584 if (!domain->generic_virtual_cases)
1585 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1587 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1590 for (; list; list = list->next) {
1591 MonoImtBuilderEntry *entry;
1593 if (list->count < THUNK_THRESHOLD)
1596 entry = g_new0 (MonoImtBuilderEntry, 1);
1597 entry->key = list->method;
1598 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1599 entry->has_target_code = 1;
1601 entry->children = entries->children + 1;
1602 entry->next = entries;
1606 mono_domain_unlock (domain);
1608 /* FIXME: Leaking memory ? */
1613 * mono_method_add_generic_virtual_invocation:
1615 * @vtable_slot: pointer to the vtable slot
1616 * @method: the inflated generic virtual method
1617 * @code: the method's code
1619 * Registers a call via unmanaged code to a generic virtual method
1620 * instantiation or variant interface method. If the number of calls reaches a threshold
1621 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1622 * virtual method thunk.
1625 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1626 gpointer *vtable_slot,
1627 MonoMethod *method, gpointer code)
1629 static gboolean inited = FALSE;
1630 static int num_added = 0;
1632 GenericVirtualCase *gvc, *list;
1633 MonoImtBuilderEntry *entries;
1637 mono_domain_lock (domain);
1638 if (!domain->generic_virtual_cases)
1639 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1641 /* Check whether the case was already added */
1642 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1645 if (gvc->method == method)
1650 /* If not found, make a new one */
1652 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1653 gvc->method = method;
1656 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1658 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1661 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1667 if (++gvc->count == THUNK_THRESHOLD) {
1668 gpointer *old_thunk = *vtable_slot;
1669 gpointer vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable) : NULL;
1671 if ((gpointer)vtable_slot < (gpointer)vtable)
1672 /* Force the rebuild of the thunk at the next call */
1673 *vtable_slot = imt_trampoline;
1675 entries = get_generic_virtual_entries (domain, vtable_slot);
1677 sorted = imt_sort_slot_entries (entries);
1679 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1683 MonoImtBuilderEntry *next = entries->next;
1688 for (i = 0; i < sorted->len; ++i)
1689 g_free (g_ptr_array_index (sorted, i));
1690 g_ptr_array_free (sorted, TRUE);
1693 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1694 invalidate_generic_virtual_thunk (domain, old_thunk);
1697 mono_domain_unlock (domain);
1700 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1703 * mono_class_vtable:
1704 * @domain: the application domain
1705 * @class: the class to initialize
1707 * VTables are domain specific because we create domain specific code, and
1708 * they contain the domain specific static class data.
1709 * On failure, NULL is returned, and class->exception_type is set.
1712 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1714 return mono_class_vtable_full (domain, class, FALSE);
1718 * mono_class_vtable_full:
1719 * @domain: the application domain
1720 * @class: the class to initialize
1721 * @raise_on_error if an exception should be raised on failure or not
1723 * VTables are domain specific because we create domain specific code, and
1724 * they contain the domain specific static class data.
1727 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1729 MonoClassRuntimeInfo *runtime_info;
1733 if (class->exception_type) {
1735 mono_raise_exception (mono_class_get_exception_for_failure (class));
1739 /* this check can be inlined in jitted code, too */
1740 runtime_info = class->runtime_info;
1741 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1742 return runtime_info->domain_vtables [domain->domain_id];
1743 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1747 * mono_class_try_get_vtable:
1748 * @domain: the application domain
1749 * @class: the class to initialize
1751 * This function tries to get the associated vtable from @class if
1752 * it was already created.
1755 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1757 MonoClassRuntimeInfo *runtime_info;
1761 runtime_info = class->runtime_info;
1762 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1763 return runtime_info->domain_vtables [domain->domain_id];
1768 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1771 MonoClassRuntimeInfo *runtime_info, *old_info;
1772 MonoClassField *field;
1775 int imt_table_bytes = 0;
1776 guint32 vtable_size, class_size;
1779 gpointer *interface_offsets;
1781 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1782 mono_domain_lock (domain);
1783 runtime_info = class->runtime_info;
1784 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1785 mono_domain_unlock (domain);
1786 mono_loader_unlock ();
1787 return runtime_info->domain_vtables [domain->domain_id];
1789 if (!class->inited || class->exception_type) {
1790 if (!mono_class_init (class) || class->exception_type) {
1791 mono_domain_unlock (domain);
1792 mono_loader_unlock ();
1794 mono_raise_exception (mono_class_get_exception_for_failure (class));
1799 /* Array types require that their element type be valid*/
1800 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1801 MonoClass *element_class = class->element_class;
1802 if (!element_class->inited)
1803 mono_class_init (element_class);
1805 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1806 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1807 mono_class_setup_vtable (element_class);
1809 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1810 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1811 if (class->exception_type == MONO_EXCEPTION_NONE)
1812 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1813 mono_domain_unlock (domain);
1814 mono_loader_unlock ();
1816 mono_raise_exception (mono_class_get_exception_for_failure (class));
1822 * For some classes, mono_class_init () already computed class->vtable_size, and
1823 * that is all that is needed because of the vtable trampolines.
1825 if (!class->vtable_size)
1826 mono_class_setup_vtable (class);
1828 if (class->exception_type) {
1829 mono_domain_unlock (domain);
1830 mono_loader_unlock ();
1832 mono_raise_exception (mono_class_get_exception_for_failure (class));
1837 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1838 if (class->interface_offsets_count) {
1839 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1840 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1841 mono_stats.imt_number_of_tables++;
1842 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1845 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1846 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1849 mono_stats.used_class_count++;
1850 mono_stats.class_vtable_size += vtable_size;
1851 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1854 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1856 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1858 vt->rank = class->rank;
1859 vt->domain = domain;
1861 mono_class_compute_gc_descriptor (class);
1863 * We can't use typed allocation in the non-root domains, since the
1864 * collector needs the GC descriptor stored in the vtable even after
1865 * the mempool containing the vtable is destroyed when the domain is
1866 * unloaded. An alternative might be to allocate vtables in the GC
1867 * heap, but this does not seem to work (it leads to crashes inside
1868 * libgc). If that approach is tried, two gc descriptors need to be
1869 * allocated for each class: one for the root domain, and one for all
1870 * other domains. The second descriptor should contain a bit for the
1871 * vtable field in MonoObject, since we can no longer assume the
1872 * vtable is reachable by other roots after the appdomain is unloaded.
1874 #ifdef HAVE_BOEHM_GC
1875 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1876 vt->gc_descr = GC_NO_DESCRIPTOR;
1879 vt->gc_descr = class->gc_descr;
1881 if ((class_size = mono_class_data_size (class))) {
1882 if (class->has_static_refs) {
1883 gpointer statics_gc_descr;
1885 gsize default_bitmap [4] = {0};
1888 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1889 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1890 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1891 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1892 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1893 if (bitmap != default_bitmap)
1896 vt->data = mono_domain_alloc0 (domain, class_size);
1898 mono_stats.class_static_data_size += class_size;
1903 while ((field = mono_class_get_fields (class, &iter))) {
1904 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1906 if (mono_field_is_deleted (field))
1908 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1909 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1910 if (special_static != SPECIAL_STATIC_NONE) {
1911 guint32 size, offset;
1913 gsize default_bitmap [4] = {0};
1917 if (mono_type_is_reference (field->type)) {
1918 default_bitmap [0] = 1;
1920 bitmap = default_bitmap;
1921 } else if (mono_type_is_struct (field->type)) {
1922 fclass = mono_class_from_mono_type (field->type);
1923 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1925 default_bitmap [0] = 0;
1927 bitmap = default_bitmap;
1929 size = mono_type_size (field->type, &align);
1930 offset = mono_alloc_special_static_data (special_static, size, align, bitmap, max_set);
1931 if (!domain->special_static_fields)
1932 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1933 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1934 if (bitmap != default_bitmap)
1937 * This marks the field as special static to speed up the
1938 * checks in mono_field_static_get/set_value ().
1944 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1945 MonoClass *fklass = mono_class_from_mono_type (field->type);
1946 const char *data = mono_field_get_data (field);
1948 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1949 t = (char*)vt->data + field->offset;
1950 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1953 if (fklass->valuetype) {
1954 memcpy (t, data, mono_class_value_size (fklass, NULL));
1956 /* it's a pointer type: add check */
1957 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1964 vt->max_interface_id = class->max_interface_id;
1965 vt->interface_bitmap = class->interface_bitmap;
1967 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1968 // class->name, class->interface_offsets_count);
1970 if (! ARCH_USE_IMT) {
1971 /* initialize interface offsets */
1972 for (i = 0; i < class->interface_offsets_count; ++i) {
1973 int interface_id = class->interfaces_packed [i]->interface_id;
1974 int slot = class->interface_offsets_packed [i];
1975 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1979 /* class_vtable_array keeps an array of created vtables
1981 g_ptr_array_add (domain->class_vtable_array, vt);
1982 /* class->runtime_info is protected by the loader lock, both when
1983 * it it enlarged and when it is stored info.
1986 old_info = class->runtime_info;
1987 if (old_info && old_info->max_domain >= domain->domain_id) {
1988 /* someone already created a large enough runtime info */
1989 mono_memory_barrier ();
1990 old_info->domain_vtables [domain->domain_id] = vt;
1992 int new_size = domain->domain_id;
1994 new_size = MAX (new_size, old_info->max_domain);
1996 /* make the new size a power of two */
1998 while (new_size > i)
2001 /* this is a bounded memory retention issue: may want to
2002 * handle it differently when we'll have a rcu-like system.
2004 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2005 runtime_info->max_domain = new_size - 1;
2006 /* copy the stuff from the older info */
2008 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2010 runtime_info->domain_vtables [domain->domain_id] = vt;
2012 mono_memory_barrier ();
2013 class->runtime_info = runtime_info;
2016 /* Initialize vtable */
2017 if (callbacks.get_vtable_trampoline) {
2018 // This also covers the AOT case
2019 for (i = 0; i < class->vtable_size; ++i) {
2020 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2023 mono_class_setup_vtable (class);
2025 for (i = 0; i < class->vtable_size; ++i) {
2028 if ((cm = class->vtable [i]))
2029 vt->vtable [i] = arch_create_jit_trampoline (cm);
2033 if (ARCH_USE_IMT && imt_table_bytes) {
2034 /* Now that the vtable is full, we can actually fill up the IMT */
2035 if (imt_trampoline) {
2036 /* lazy construction of the IMT entries enabled */
2037 for (i = 0; i < MONO_IMT_SIZE; ++i)
2038 interface_offsets [i] = imt_trampoline;
2040 build_imt (class, vt, domain, interface_offsets, NULL);
2044 mono_domain_unlock (domain);
2045 mono_loader_unlock ();
2047 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2048 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2049 mono_raise_exception (mono_class_get_exception_for_failure (class));
2051 /* make sure the parent is initialized */
2052 /*FIXME shouldn't this fail the current type?*/
2054 mono_class_vtable_full (domain, class->parent, raise_on_error);
2056 /*FIXME check for OOM*/
2057 vt->type = mono_type_get_object (domain, &class->byval_arg);
2059 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2060 static void *type_desc = NULL;
2064 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2067 /* This is unregistered in
2068 unregister_vtable_reflection_type() in
2070 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2073 if (class->contextbound)
2082 * mono_class_proxy_vtable:
2083 * @domain: the application domain
2084 * @remove_class: the remote class
2086 * Creates a vtable for transparent proxies. It is basically
2087 * a copy of the real vtable of the class wrapped in @remote_class,
2088 * but all function pointers invoke the remoting functions, and
2089 * vtable->klass points to the transparent proxy class, and not to @class.
2092 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2095 MonoVTable *vt, *pvt;
2096 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2098 GSList *extra_interfaces = NULL;
2099 MonoClass *class = remote_class->proxy_class;
2100 gpointer *interface_offsets;
2104 #ifdef COMPRESSED_INTERFACE_BITMAP
2108 vt = mono_class_vtable (domain, class);
2109 g_assert (vt); /*FIXME property handle failure*/
2110 max_interface_id = vt->max_interface_id;
2112 /* Calculate vtable space for extra interfaces */
2113 for (j = 0; j < remote_class->interface_count; j++) {
2114 MonoClass* iclass = remote_class->interfaces[j];
2118 /*FIXME test for interfaces with variant generic arguments*/
2119 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2120 continue; /* interface implemented by the class */
2121 if (g_slist_find (extra_interfaces, iclass))
2124 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2126 method_count = mono_class_num_methods (iclass);
2128 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2129 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2131 for (i = 0; i < ifaces->len; ++i) {
2132 MonoClass *ic = g_ptr_array_index (ifaces, i);
2133 /*FIXME test for interfaces with variant generic arguments*/
2134 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2135 continue; /* interface implemented by the class */
2136 if (g_slist_find (extra_interfaces, ic))
2138 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2139 method_count += mono_class_num_methods (ic);
2141 g_ptr_array_free (ifaces, TRUE);
2144 extra_interface_vtsize += method_count * sizeof (gpointer);
2145 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2149 mono_stats.imt_number_of_tables++;
2150 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2151 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2152 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2154 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2155 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2158 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2160 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2162 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2164 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2165 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2167 pvt->klass = mono_defaults.transparent_proxy_class;
2168 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2169 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2171 /* initialize vtable */
2172 mono_class_setup_vtable (class);
2173 for (i = 0; i < class->vtable_size; ++i) {
2176 if ((cm = class->vtable [i]))
2177 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2179 pvt->vtable [i] = NULL;
2182 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2183 /* create trampolines for abstract methods */
2184 for (k = class; k; k = k->parent) {
2186 gpointer iter = NULL;
2187 while ((m = mono_class_get_methods (k, &iter)))
2188 if (!pvt->vtable [m->slot])
2189 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2193 pvt->max_interface_id = max_interface_id;
2194 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2195 #ifdef COMPRESSED_INTERFACE_BITMAP
2196 bitmap = g_malloc0 (bsize);
2198 bitmap = mono_domain_alloc0 (domain, bsize);
2201 if (! ARCH_USE_IMT) {
2202 /* initialize interface offsets */
2203 for (i = 0; i < class->interface_offsets_count; ++i) {
2204 int interface_id = class->interfaces_packed [i]->interface_id;
2205 int slot = class->interface_offsets_packed [i];
2206 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2209 for (i = 0; i < class->interface_offsets_count; ++i) {
2210 int interface_id = class->interfaces_packed [i]->interface_id;
2211 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2214 if (extra_interfaces) {
2215 int slot = class->vtable_size;
2221 /* Create trampolines for the methods of the interfaces */
2222 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2223 interf = list_item->data;
2225 if (! ARCH_USE_IMT) {
2226 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2228 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2232 while ((cm = mono_class_get_methods (interf, &iter)))
2233 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2235 slot += mono_class_num_methods (interf);
2237 if (! ARCH_USE_IMT) {
2238 g_slist_free (extra_interfaces);
2243 /* Now that the vtable is full, we can actually fill up the IMT */
2244 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2245 if (extra_interfaces) {
2246 g_slist_free (extra_interfaces);
2250 #ifdef COMPRESSED_INTERFACE_BITMAP
2251 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2252 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2253 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2256 pvt->interface_bitmap = bitmap;
2262 * mono_class_field_is_special_static:
2264 * Returns whether @field is a thread/context static field.
2267 mono_class_field_is_special_static (MonoClassField *field)
2269 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2271 if (mono_field_is_deleted (field))
2273 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2274 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2281 * mono_class_has_special_static_fields:
2283 * Returns whenever @klass has any thread/context static fields.
2286 mono_class_has_special_static_fields (MonoClass *klass)
2288 MonoClassField *field;
2292 while ((field = mono_class_get_fields (klass, &iter))) {
2293 g_assert (field->parent == klass);
2294 if (mono_class_field_is_special_static (field))
2302 * create_remote_class_key:
2303 * Creates an array of pointers that can be used as a hash key for a remote class.
2304 * The first element of the array is the number of pointers.
2307 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2312 if (remote_class == NULL) {
2313 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2314 key = g_malloc (sizeof(gpointer) * 3);
2315 key [0] = GINT_TO_POINTER (2);
2316 key [1] = mono_defaults.marshalbyrefobject_class;
2317 key [2] = extra_class;
2319 key = g_malloc (sizeof(gpointer) * 2);
2320 key [0] = GINT_TO_POINTER (1);
2321 key [1] = extra_class;
2324 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2325 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2326 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2327 key [1] = remote_class->proxy_class;
2329 // Keep the list of interfaces sorted
2330 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2331 if (extra_class && remote_class->interfaces [i] > extra_class) {
2332 key [j++] = extra_class;
2335 key [j] = remote_class->interfaces [i];
2338 key [j] = extra_class;
2340 // Replace the old class. The interface list is the same
2341 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2342 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2343 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2344 for (i = 0; i < remote_class->interface_count; i++)
2345 key [2 + i] = remote_class->interfaces [i];
2353 * copy_remote_class_key:
2355 * Make a copy of KEY in the domain and return the copy.
2358 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2360 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2361 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2363 memcpy (mp_key, key, key_size);
2369 * mono_remote_class:
2370 * @domain: the application domain
2371 * @class_name: name of the remote class
2373 * Creates and initializes a MonoRemoteClass object for a remote type.
2375 * Can raise an exception on failure.
2378 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2381 MonoRemoteClass *rc;
2382 gpointer* key, *mp_key;
2385 key = create_remote_class_key (NULL, proxy_class);
2387 mono_domain_lock (domain);
2388 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2392 mono_domain_unlock (domain);
2396 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2397 if (!mono_error_ok (&error)) {
2399 mono_domain_unlock (domain);
2400 mono_error_raise_exception (&error);
2403 mp_key = copy_remote_class_key (domain, key);
2407 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2408 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2409 rc->interface_count = 1;
2410 rc->interfaces [0] = proxy_class;
2411 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2413 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2414 rc->interface_count = 0;
2415 rc->proxy_class = proxy_class;
2418 rc->default_vtable = NULL;
2419 rc->xdomain_vtable = NULL;
2420 rc->proxy_class_name = name;
2421 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2423 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2425 mono_domain_unlock (domain);
2430 * clone_remote_class:
2431 * Creates a copy of the remote_class, adding the provided class or interface
2433 static MonoRemoteClass*
2434 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2436 MonoRemoteClass *rc;
2437 gpointer* key, *mp_key;
2439 key = create_remote_class_key (remote_class, extra_class);
2440 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2446 mp_key = copy_remote_class_key (domain, key);
2450 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2452 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2453 rc->proxy_class = remote_class->proxy_class;
2454 rc->interface_count = remote_class->interface_count + 1;
2456 // Keep the list of interfaces sorted, since the hash key of
2457 // the remote class depends on this
2458 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2459 if (remote_class->interfaces [i] > extra_class && i == j)
2460 rc->interfaces [j++] = extra_class;
2461 rc->interfaces [j] = remote_class->interfaces [i];
2464 rc->interfaces [j] = extra_class;
2466 // Replace the old class. The interface array is the same
2467 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2468 rc->proxy_class = extra_class;
2469 rc->interface_count = remote_class->interface_count;
2470 if (rc->interface_count > 0)
2471 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2474 rc->default_vtable = NULL;
2475 rc->xdomain_vtable = NULL;
2476 rc->proxy_class_name = remote_class->proxy_class_name;
2478 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2484 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2486 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2487 mono_domain_lock (domain);
2488 if (rp->target_domain_id != -1) {
2489 if (remote_class->xdomain_vtable == NULL)
2490 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2491 mono_domain_unlock (domain);
2492 mono_loader_unlock ();
2493 return remote_class->xdomain_vtable;
2495 if (remote_class->default_vtable == NULL) {
2498 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2499 klass = mono_class_from_mono_type (type);
2500 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2501 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2503 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2506 mono_domain_unlock (domain);
2507 mono_loader_unlock ();
2508 return remote_class->default_vtable;
2512 * mono_upgrade_remote_class:
2513 * @domain: the application domain
2514 * @tproxy: the proxy whose remote class has to be upgraded.
2515 * @klass: class to which the remote class can be casted.
2517 * Updates the vtable of the remote class by adding the necessary method slots
2518 * and interface offsets so it can be safely casted to klass. klass can be a
2519 * class or an interface.
2522 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2524 MonoTransparentProxy *tproxy;
2525 MonoRemoteClass *remote_class;
2526 gboolean redo_vtable;
2528 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2529 mono_domain_lock (domain);
2531 tproxy = (MonoTransparentProxy*) proxy_object;
2532 remote_class = tproxy->remote_class;
2534 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2537 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2538 if (remote_class->interfaces [i] == klass)
2539 redo_vtable = FALSE;
2542 redo_vtable = (remote_class->proxy_class != klass);
2546 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2547 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2550 mono_domain_unlock (domain);
2551 mono_loader_unlock ();
2556 * mono_object_get_virtual_method:
2557 * @obj: object to operate on.
2560 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2561 * the instance of a callvirt of method.
2564 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2567 MonoMethod **vtable;
2569 MonoMethod *res = NULL;
2571 klass = mono_object_class (obj);
2572 if (klass == mono_defaults.transparent_proxy_class) {
2573 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2579 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2582 mono_class_setup_vtable (klass);
2583 vtable = klass->vtable;
2585 if (method->slot == -1) {
2586 /* method->slot might not be set for instances of generic methods */
2587 if (method->is_inflated) {
2588 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2589 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2592 g_assert_not_reached ();
2596 /* check method->slot is a valid index: perform isinstance? */
2597 if (method->slot != -1) {
2598 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2600 gboolean variance_used = FALSE;
2601 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2602 g_assert (iface_offset > 0);
2603 res = vtable [iface_offset + method->slot];
2606 res = vtable [method->slot];
2611 /* It may be an interface, abstract class method or generic method */
2612 if (!res || mono_method_signature (res)->generic_param_count)
2615 /* generic methods demand invoke_with_check */
2616 if (mono_method_signature (res)->generic_param_count)
2617 res = mono_marshal_get_remoting_invoke_with_check (res);
2620 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2621 res = mono_cominterop_get_invoke (res);
2624 res = mono_marshal_get_remoting_invoke (res);
2627 if (method->is_inflated) {
2628 /* Have to inflate the result */
2629 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2639 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2641 g_error ("runtime invoke called on uninitialized runtime");
2645 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2648 * mono_runtime_invoke:
2649 * @method: method to invoke
2650 * @obJ: object instance
2651 * @params: arguments to the method
2652 * @exc: exception information.
2654 * Invokes the method represented by @method on the object @obj.
2656 * obj is the 'this' pointer, it should be NULL for static
2657 * methods, a MonoObject* for object instances and a pointer to
2658 * the value type for value types.
2660 * The params array contains the arguments to the method with the
2661 * same convention: MonoObject* pointers for object instances and
2662 * pointers to the value type otherwise.
2664 * From unmanaged code you'll usually use the
2665 * mono_runtime_invoke() variant.
2667 * Note that this function doesn't handle virtual methods for
2668 * you, it will exec the exact method you pass: we still need to
2669 * expose a function to lookup the derived class implementation
2670 * of a virtual method (there are examples of this in the code,
2673 * You can pass NULL as the exc argument if you don't want to
2674 * catch exceptions, otherwise, *exc will be set to the exception
2675 * thrown, if any. if an exception is thrown, you can't use the
2676 * MonoObject* result from the function.
2678 * If the method returns a value type, it is boxed in an object
2682 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2686 if (mono_runtime_get_no_exec ())
2687 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2689 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2690 mono_profiler_method_start_invoke (method);
2692 result = default_mono_runtime_invoke (method, obj, params, exc);
2694 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2695 mono_profiler_method_end_invoke (method);
2701 * mono_method_get_unmanaged_thunk:
2702 * @method: method to generate a thunk for.
2704 * Returns an unmanaged->managed thunk that can be used to call
2705 * a managed method directly from C.
2707 * The thunk's C signature closely matches the managed signature:
2709 * C#: public bool Equals (object obj);
2710 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2711 * MonoObject*, MonoException**);
2713 * The 1st ("this") parameter must not be used with static methods:
2715 * C#: public static bool ReferenceEquals (object a, object b);
2716 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2719 * The last argument must be a non-null pointer of a MonoException* pointer.
2720 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2721 * exception has been thrown in managed code. Otherwise it will point
2722 * to the MonoException* caught by the thunk. In this case, the result of
2723 * the thunk is undefined:
2725 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2726 * MonoException *ex = NULL;
2727 * Equals func = mono_method_get_unmanaged_thunk (method);
2728 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2730 * // handle exception
2733 * The calling convention of the thunk matches the platform's default
2734 * convention. This means that under Windows, C declarations must
2735 * contain the __stdcall attribute:
2737 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2738 * MonoObject*, MonoException**);
2742 * Value type arguments and return values are treated as they were objects:
2744 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2745 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2747 * Arguments must be properly boxed upon trunk's invocation, while return
2748 * values must be unboxed.
2751 mono_method_get_unmanaged_thunk (MonoMethod *method)
2753 method = mono_marshal_get_thunk_invoke_wrapper (method);
2754 return mono_compile_method (method);
2758 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2762 /* object fields cannot be byref, so we don't need a
2764 gpointer *p = (gpointer*)dest;
2771 case MONO_TYPE_BOOLEAN:
2773 case MONO_TYPE_U1: {
2774 guint8 *p = (guint8*)dest;
2775 *p = value ? *(guint8*)value : 0;
2780 case MONO_TYPE_CHAR: {
2781 guint16 *p = (guint16*)dest;
2782 *p = value ? *(guint16*)value : 0;
2785 #if SIZEOF_VOID_P == 4
2790 case MONO_TYPE_U4: {
2791 gint32 *p = (gint32*)dest;
2792 *p = value ? *(gint32*)value : 0;
2795 #if SIZEOF_VOID_P == 8
2800 case MONO_TYPE_U8: {
2801 gint64 *p = (gint64*)dest;
2802 *p = value ? *(gint64*)value : 0;
2805 case MONO_TYPE_R4: {
2806 float *p = (float*)dest;
2807 *p = value ? *(float*)value : 0;
2810 case MONO_TYPE_R8: {
2811 double *p = (double*)dest;
2812 *p = value ? *(double*)value : 0;
2815 case MONO_TYPE_STRING:
2816 case MONO_TYPE_SZARRAY:
2817 case MONO_TYPE_CLASS:
2818 case MONO_TYPE_OBJECT:
2819 case MONO_TYPE_ARRAY:
2820 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2822 case MONO_TYPE_FNPTR:
2823 case MONO_TYPE_PTR: {
2824 gpointer *p = (gpointer*)dest;
2825 *p = deref_pointer? *(gpointer*)value: value;
2828 case MONO_TYPE_VALUETYPE:
2829 /* note that 't' and 'type->type' can be different */
2830 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2831 t = mono_class_enum_basetype (type->data.klass)->type;
2834 MonoClass *class = mono_class_from_mono_type (type);
2835 int size = mono_class_value_size (class, NULL);
2837 memset (dest, 0, size);
2839 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2842 case MONO_TYPE_GENERICINST:
2843 t = type->data.generic_class->container_class->byval_arg.type;
2846 g_warning ("got type %x", type->type);
2847 g_assert_not_reached ();
2852 * mono_field_set_value:
2853 * @obj: Instance object
2854 * @field: MonoClassField describing the field to set
2855 * @value: The value to be set
2857 * Sets the value of the field described by @field in the object instance @obj
2858 * to the value passed in @value. This method should only be used for instance
2859 * fields. For static fields, use mono_field_static_set_value.
2861 * The value must be on the native format of the field type.
2864 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2868 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2870 dest = (char*)obj + field->offset;
2871 set_value (field->type, dest, value, FALSE);
2875 * mono_field_static_set_value:
2876 * @field: MonoClassField describing the field to set
2877 * @value: The value to be set
2879 * Sets the value of the static field described by @field
2880 * to the value passed in @value.
2882 * The value must be on the native format of the field type.
2885 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2889 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2890 /* you cant set a constant! */
2891 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2893 if (field->offset == -1) {
2894 /* Special static */
2895 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2896 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2898 dest = (char*)vt->data + field->offset;
2900 set_value (field->type, dest, value, FALSE);
2903 /* Used by the debugger */
2905 mono_vtable_get_static_field_data (MonoVTable *vt)
2911 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2915 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2916 if (field->offset == -1) {
2917 /* Special static */
2918 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2919 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2921 src = (guint8*)vt->data + field->offset;
2924 src = (guint8*)obj + field->offset;
2931 * mono_field_get_value:
2932 * @obj: Object instance
2933 * @field: MonoClassField describing the field to fetch information from
2934 * @value: pointer to the location where the value will be stored
2936 * Use this routine to get the value of the field @field in the object
2939 * The pointer provided by value must be of the field type, for reference
2940 * types this is a MonoObject*, for value types its the actual pointer to
2945 * mono_field_get_value (obj, int_field, &i);
2948 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2952 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2954 src = (char*)obj + field->offset;
2955 set_value (field->type, value, src, TRUE);
2959 * mono_field_get_value_object:
2960 * @domain: domain where the object will be created (if boxing)
2961 * @field: MonoClassField describing the field to fetch information from
2962 * @obj: The object instance for the field.
2964 * Returns: a new MonoObject with the value from the given field. If the
2965 * field represents a value type, the value is boxed.
2969 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2973 MonoVTable *vtable = NULL;
2975 gboolean is_static = FALSE;
2976 gboolean is_ref = FALSE;
2977 gboolean is_literal = FALSE;
2979 switch (field->type->type) {
2980 case MONO_TYPE_STRING:
2981 case MONO_TYPE_OBJECT:
2982 case MONO_TYPE_CLASS:
2983 case MONO_TYPE_ARRAY:
2984 case MONO_TYPE_SZARRAY:
2989 case MONO_TYPE_BOOLEAN:
2992 case MONO_TYPE_CHAR:
3001 case MONO_TYPE_VALUETYPE:
3002 is_ref = field->type->byref;
3004 case MONO_TYPE_GENERICINST:
3005 is_ref = !mono_type_generic_inst_is_valuetype (field->type);
3008 g_error ("type 0x%x not handled in "
3009 "mono_field_get_value_object", field->type->type);
3013 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
3016 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3020 vtable = mono_class_vtable (domain, field->parent);
3022 char *name = mono_type_get_full_name (field->parent);
3023 /*FIXME extend this to use the MonoError api*/
3024 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3028 if (!vtable->initialized)
3029 mono_runtime_class_init (vtable);
3035 get_default_field_value (domain, field, &o);
3036 } else if (is_static) {
3037 mono_field_static_get_value (vtable, field, &o);
3039 mono_field_get_value (obj, field, &o);
3044 /* boxed value type */
3045 klass = mono_class_from_mono_type (field->type);
3047 if (mono_class_is_nullable (klass))
3048 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3050 o = mono_object_new (domain, klass);
3051 v = ((gchar *) o) + sizeof (MonoObject);
3054 get_default_field_value (domain, field, v);
3055 } else if (is_static) {
3056 mono_field_static_get_value (vtable, field, v);
3058 mono_field_get_value (obj, field, v);
3065 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3068 const char *p = blob;
3069 mono_metadata_decode_blob_size (p, &p);
3072 case MONO_TYPE_BOOLEAN:
3075 *(guint8 *) value = *p;
3077 case MONO_TYPE_CHAR:
3080 *(guint16*) value = read16 (p);
3084 *(guint32*) value = read32 (p);
3088 *(guint64*) value = read64 (p);
3091 readr4 (p, (float*) value);
3094 readr8 (p, (double*) value);
3096 case MONO_TYPE_STRING:
3097 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3099 case MONO_TYPE_CLASS:
3100 *(gpointer*) value = NULL;
3104 g_warning ("type 0x%02x should not be in constant table", type);
3110 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3112 MonoTypeEnum def_type;
3115 data = mono_class_get_field_default_value (field, &def_type);
3116 mono_get_constant_value_from_blob (domain, def_type, data, value);
3120 * mono_field_static_get_value:
3121 * @vt: vtable to the object
3122 * @field: MonoClassField describing the field to fetch information from
3123 * @value: where the value is returned
3125 * Use this routine to get the value of the static field @field value.
3127 * The pointer provided by value must be of the field type, for reference
3128 * types this is a MonoObject*, for value types its the actual pointer to
3133 * mono_field_static_get_value (vt, int_field, &i);
3136 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3140 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3142 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3143 get_default_field_value (vt->domain, field, value);
3147 if (field->offset == -1) {
3148 /* Special static */
3149 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3150 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3152 src = (char*)vt->data + field->offset;
3154 set_value (field->type, value, src, TRUE);
3158 * mono_property_set_value:
3159 * @prop: MonoProperty to set
3160 * @obj: instance object on which to act
3161 * @params: parameters to pass to the propery
3162 * @exc: optional exception
3164 * Invokes the property's set method with the given arguments on the
3165 * object instance obj (or NULL for static properties).
3167 * You can pass NULL as the exc argument if you don't want to
3168 * catch exceptions, otherwise, *exc will be set to the exception
3169 * thrown, if any. if an exception is thrown, you can't use the
3170 * MonoObject* result from the function.
3173 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3175 default_mono_runtime_invoke (prop->set, obj, params, exc);
3179 * mono_property_get_value:
3180 * @prop: MonoProperty to fetch
3181 * @obj: instance object on which to act
3182 * @params: parameters to pass to the propery
3183 * @exc: optional exception
3185 * Invokes the property's get method with the given arguments on the
3186 * object instance obj (or NULL for static properties).
3188 * You can pass NULL as the exc argument if you don't want to
3189 * catch exceptions, otherwise, *exc will be set to the exception
3190 * thrown, if any. if an exception is thrown, you can't use the
3191 * MonoObject* result from the function.
3193 * Returns: the value from invoking the get method on the property.
3196 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3198 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3202 * mono_nullable_init:
3203 * @buf: The nullable structure to initialize.
3204 * @value: the value to initialize from
3205 * @klass: the type for the object
3207 * Initialize the nullable structure pointed to by @buf from @value which
3208 * should be a boxed value type. The size of @buf should be able to hold
3209 * as much data as the @klass->instance_size (which is the number of bytes
3210 * that will be copies).
3212 * Since Nullables have variable structure, we can not define a C
3213 * structure for them.
3216 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3218 MonoClass *param_class = klass->cast_class;
3220 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3221 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3223 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3225 if (param_class->has_references)
3226 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3228 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3230 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3235 * mono_nullable_box:
3236 * @buf: The buffer representing the data to be boxed
3237 * @klass: the type to box it as.
3239 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3243 mono_nullable_box (guint8 *buf, MonoClass *klass)
3245 MonoClass *param_class = klass->cast_class;
3247 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3248 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3250 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3251 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3252 if (param_class->has_references)
3253 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3255 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3263 * mono_get_delegate_invoke:
3264 * @klass: The delegate class
3266 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3269 mono_get_delegate_invoke (MonoClass *klass)
3273 /* This is called at runtime, so avoid the slower search in metadata */
3274 mono_class_setup_methods (klass);
3275 if (klass->exception_type)
3277 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3284 * mono_runtime_delegate_invoke:
3285 * @delegate: pointer to a delegate object.
3286 * @params: parameters for the delegate.
3287 * @exc: Pointer to the exception result.
3289 * Invokes the delegate method @delegate with the parameters provided.
3291 * You can pass NULL as the exc argument if you don't want to
3292 * catch exceptions, otherwise, *exc will be set to the exception
3293 * thrown, if any. if an exception is thrown, you can't use the
3294 * MonoObject* result from the function.
3297 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3301 im = mono_get_delegate_invoke (delegate->vtable->klass);
3304 return mono_runtime_invoke (im, delegate, params, exc);
3307 static char **main_args = NULL;
3308 static int num_main_args;
3311 * mono_runtime_get_main_args:
3313 * Returns: a MonoArray with the arguments passed to the main program
3316 mono_runtime_get_main_args (void)
3320 MonoDomain *domain = mono_domain_get ();
3325 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3327 for (i = 0; i < num_main_args; ++i)
3328 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3334 fire_process_exit_event (void)
3336 MonoClassField *field;
3337 MonoDomain *domain = mono_domain_get ();
3339 MonoObject *delegate, *exc;
3341 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3344 if (domain != mono_get_root_domain ())
3347 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3348 if (delegate == NULL)
3353 mono_runtime_delegate_invoke (delegate, pa, &exc);
3357 * mono_runtime_run_main:
3358 * @method: the method to start the application with (usually Main)
3359 * @argc: number of arguments from the command line
3360 * @argv: array of strings from the command line
3361 * @exc: excetption results
3363 * Execute a standard Main() method (argc/argv contains the
3364 * executable name). This method also sets the command line argument value
3365 * needed by System.Environment.
3370 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3374 MonoArray *args = NULL;
3375 MonoDomain *domain = mono_domain_get ();
3376 gchar *utf8_fullpath;
3379 g_assert (method != NULL);
3381 mono_thread_set_main (mono_thread_current ());
3383 main_args = g_new0 (char*, argc);
3384 num_main_args = argc;
3386 if (!g_path_is_absolute (argv [0])) {
3387 gchar *basename = g_path_get_basename (argv [0]);
3388 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3392 utf8_fullpath = mono_utf8_from_external (fullpath);
3393 if(utf8_fullpath == NULL) {
3394 /* Printing the arg text will cause glib to
3395 * whinge about "Invalid UTF-8", but at least
3396 * its relevant, and shows the problem text
3399 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3400 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3407 utf8_fullpath = mono_utf8_from_external (argv[0]);
3408 if(utf8_fullpath == NULL) {
3409 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3410 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3415 main_args [0] = utf8_fullpath;
3417 for (i = 1; i < argc; ++i) {
3420 utf8_arg=mono_utf8_from_external (argv[i]);
3421 if(utf8_arg==NULL) {
3422 /* Ditto the comment about Invalid UTF-8 here */
3423 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3424 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3428 main_args [i] = utf8_arg;
3432 if (mono_method_signature (method)->param_count) {
3433 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3434 for (i = 0; i < argc; ++i) {
3435 /* The encodings should all work, given that
3436 * we've checked all these args for the
3439 gchar *str = mono_utf8_from_external (argv [i]);
3440 MonoString *arg = mono_string_new (domain, str);
3441 mono_array_setref (args, i, arg);
3445 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3448 mono_assembly_set_main (method->klass->image->assembly);
3450 result = mono_runtime_exec_main (method, args, exc);
3451 fire_process_exit_event ();
3456 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3458 static MonoMethod *serialize_method;
3463 if (!serialize_method) {
3464 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3465 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3468 if (!serialize_method) {
3473 g_assert (!mono_object_class (obj)->marshalbyref);
3477 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3485 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3487 static MonoMethod *deserialize_method;
3492 if (!deserialize_method) {
3493 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3494 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3496 if (!deserialize_method) {
3503 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3511 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3513 static MonoMethod *get_proxy_method;
3515 MonoDomain *domain = mono_domain_get ();
3516 MonoRealProxy *real_proxy;
3517 MonoReflectionType *reflection_type;
3518 MonoTransparentProxy *transparent_proxy;
3520 if (!get_proxy_method)
3521 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3523 g_assert (obj->vtable->klass->marshalbyref);
3525 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3526 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3528 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3529 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3532 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3536 return (MonoObject*) transparent_proxy;
3540 * mono_object_xdomain_representation
3542 * @target_domain: a domain
3543 * @exc: pointer to a MonoObject*
3545 * Creates a representation of obj in the domain target_domain. This
3546 * is either a copy of obj arrived through via serialization and
3547 * deserialization or a proxy, depending on whether the object is
3548 * serializable or marshal by ref. obj must not be in target_domain.
3550 * If the object cannot be represented in target_domain, NULL is
3551 * returned and *exc is set to an appropriate exception.
3554 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3556 MonoObject *deserialized = NULL;
3557 gboolean failure = FALSE;
3561 if (mono_object_class (obj)->marshalbyref) {
3562 deserialized = make_transparent_proxy (obj, &failure, exc);
3564 MonoDomain *domain = mono_domain_get ();
3565 MonoObject *serialized;
3567 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3568 serialized = serialize_object (obj, &failure, exc);
3569 mono_domain_set_internal_with_options (target_domain, FALSE);
3571 deserialized = deserialize_object (serialized, &failure, exc);
3572 if (domain != target_domain)
3573 mono_domain_set_internal_with_options (domain, FALSE);
3576 return deserialized;
3579 /* Used in call_unhandled_exception_delegate */
3581 create_unhandled_exception_eventargs (MonoObject *exc)
3585 MonoMethod *method = NULL;
3586 MonoBoolean is_terminating = TRUE;
3589 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3592 mono_class_init (klass);
3594 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3595 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3599 args [1] = &is_terminating;
3601 obj = mono_object_new (mono_domain_get (), klass);
3602 mono_runtime_invoke (method, obj, args, NULL);
3607 /* Used in mono_unhandled_exception */
3609 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3610 MonoObject *e = NULL;
3612 MonoDomain *current_domain = mono_domain_get ();
3614 if (domain != current_domain)
3615 mono_domain_set_internal_with_options (domain, FALSE);
3617 g_assert (domain == mono_object_domain (domain->domain));
3619 if (mono_object_domain (exc) != domain) {
3620 MonoObject *serialization_exc;
3622 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3624 if (serialization_exc) {
3626 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3629 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3630 "System.Runtime.Serialization", "SerializationException",
3631 "Could not serialize unhandled exception.");
3635 g_assert (mono_object_domain (exc) == domain);
3637 pa [0] = domain->domain;
3638 pa [1] = create_unhandled_exception_eventargs (exc);
3639 mono_runtime_delegate_invoke (delegate, pa, &e);
3641 if (domain != current_domain)
3642 mono_domain_set_internal_with_options (current_domain, FALSE);
3646 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3647 if (!mono_error_ok (&error)) {
3648 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3649 mono_error_cleanup (&error);
3651 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3657 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3660 * mono_runtime_unhandled_exception_policy_set:
3661 * @policy: the new policy
3663 * This is a VM internal routine.
3665 * Sets the runtime policy for handling unhandled exceptions.
3668 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3669 runtime_unhandled_exception_policy = policy;
3673 * mono_runtime_unhandled_exception_policy_get:
3675 * This is a VM internal routine.
3677 * Gets the runtime policy for handling unhandled exceptions.
3679 MonoRuntimeUnhandledExceptionPolicy
3680 mono_runtime_unhandled_exception_policy_get (void) {
3681 return runtime_unhandled_exception_policy;
3685 * mono_unhandled_exception:
3686 * @exc: exception thrown
3688 * This is a VM internal routine.
3690 * We call this function when we detect an unhandled exception
3691 * in the default domain.
3693 * It invokes the * UnhandledException event in AppDomain or prints
3694 * a warning to the console
3697 mono_unhandled_exception (MonoObject *exc)
3699 MonoDomain *current_domain = mono_domain_get ();
3700 MonoDomain *root_domain = mono_get_root_domain ();
3701 MonoClassField *field;
3702 MonoObject *current_appdomain_delegate;
3703 MonoObject *root_appdomain_delegate;
3705 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3706 "UnhandledException");
3709 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3710 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3711 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3712 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3713 if (current_domain != root_domain) {
3714 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3716 current_appdomain_delegate = NULL;
3719 /* set exitcode only if we will abort the process */
3721 mono_environment_exitcode_set (1);
3722 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3723 mono_print_unhandled_exception (exc);
3725 if (root_appdomain_delegate) {
3726 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3728 if (current_appdomain_delegate) {
3729 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3736 * Launch a new thread to execute a function
3738 * main_func is called back from the thread with main_args as the
3739 * parameter. The callback function is expected to start Main()
3740 * eventually. This function then waits for all managed threads to
3742 * It is not necesseray anymore to execute managed code in a subthread,
3743 * so this function should not be used anymore by default: just
3744 * execute the code and then call mono_thread_manage ().
3747 mono_runtime_exec_managed_code (MonoDomain *domain,
3748 MonoMainThreadFunc main_func,
3751 mono_thread_create (domain, main_func, main_args);
3753 mono_thread_manage ();
3757 * Execute a standard Main() method (args doesn't contain the
3761 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3766 MonoCustomAttrInfo* cinfo;
3767 gboolean has_stathread_attribute;
3768 MonoInternalThread* thread = mono_thread_internal_current ();
3774 domain = mono_object_domain (args);
3775 if (!domain->entry_assembly) {
3777 MonoAssembly *assembly;
3779 assembly = method->klass->image->assembly;
3780 domain->entry_assembly = assembly;
3781 /* Domains created from another domain already have application_base and configuration_file set */
3782 if (domain->setup->application_base == NULL) {
3783 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3786 if (domain->setup->configuration_file == NULL) {
3787 str = g_strconcat (assembly->image->name, ".config", NULL);
3788 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3790 mono_set_private_bin_path_from_config (domain);
3794 cinfo = mono_custom_attrs_from_method (method);
3796 static MonoClass *stathread_attribute = NULL;
3797 if (!stathread_attribute)
3798 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3799 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3801 mono_custom_attrs_free (cinfo);
3803 has_stathread_attribute = FALSE;
3805 if (has_stathread_attribute) {
3806 thread->apartment_state = ThreadApartmentState_STA;
3808 thread->apartment_state = ThreadApartmentState_MTA;
3810 mono_thread_init_apartment_state ();
3812 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3814 /* FIXME: check signature of method */
3815 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3817 res = mono_runtime_invoke (method, NULL, pa, exc);
3819 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3823 mono_environment_exitcode_set (rval);
3825 mono_runtime_invoke (method, NULL, pa, exc);
3829 /* If the return type of Main is void, only
3830 * set the exitcode if an exception was thrown
3831 * (we don't want to blow away an
3832 * explicitly-set exit code)
3835 mono_environment_exitcode_set (rval);
3839 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3845 * mono_install_runtime_invoke:
3846 * @func: Function to install
3848 * This is a VM internal routine
3851 mono_install_runtime_invoke (MonoInvokeFunc func)
3853 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3858 * mono_runtime_invoke_array:
3859 * @method: method to invoke
3860 * @obJ: object instance
3861 * @params: arguments to the method
3862 * @exc: exception information.
3864 * Invokes the method represented by @method on the object @obj.
3866 * obj is the 'this' pointer, it should be NULL for static
3867 * methods, a MonoObject* for object instances and a pointer to
3868 * the value type for value types.
3870 * The params array contains the arguments to the method with the
3871 * same convention: MonoObject* pointers for object instances and
3872 * pointers to the value type otherwise. The _invoke_array
3873 * variant takes a C# object[] as the params argument (MonoArray
3874 * *params): in this case the value types are boxed inside the
3875 * respective reference representation.
3877 * From unmanaged code you'll usually use the
3878 * mono_runtime_invoke() variant.
3880 * Note that this function doesn't handle virtual methods for
3881 * you, it will exec the exact method you pass: we still need to
3882 * expose a function to lookup the derived class implementation
3883 * of a virtual method (there are examples of this in the code,
3886 * You can pass NULL as the exc argument if you don't want to
3887 * catch exceptions, otherwise, *exc will be set to the exception
3888 * thrown, if any. if an exception is thrown, you can't use the
3889 * MonoObject* result from the function.
3891 * If the method returns a value type, it is boxed in an object
3895 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3898 MonoMethodSignature *sig = mono_method_signature (method);
3899 gpointer *pa = NULL;
3902 gboolean has_byref_nullables = FALSE;
3904 if (NULL != params) {
3905 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3906 for (i = 0; i < mono_array_length (params); i++) {
3907 MonoType *t = sig->params [i];
3913 case MONO_TYPE_BOOLEAN:
3916 case MONO_TYPE_CHAR:
3925 case MONO_TYPE_VALUETYPE:
3926 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3927 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3928 pa [i] = mono_array_get (params, MonoObject*, i);
3930 has_byref_nullables = TRUE;
3932 /* MS seems to create the objects if a null is passed in */
3933 if (!mono_array_get (params, MonoObject*, i))
3934 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3938 * We can't pass the unboxed vtype byref to the callee, since
3939 * that would mean the callee would be able to modify boxed
3940 * primitive types. So we (and MS) make a copy of the boxed
3941 * object, pass that to the callee, and replace the original
3942 * boxed object in the arg array with the copy.
3944 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3945 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3946 mono_array_setref (params, i, copy);
3949 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3952 case MONO_TYPE_STRING:
3953 case MONO_TYPE_OBJECT:
3954 case MONO_TYPE_CLASS:
3955 case MONO_TYPE_ARRAY:
3956 case MONO_TYPE_SZARRAY:
3958 pa [i] = mono_array_addr (params, MonoObject*, i);
3959 // FIXME: I need to check this code path
3961 pa [i] = mono_array_get (params, MonoObject*, i);
3963 case MONO_TYPE_GENERICINST:
3965 t = &t->data.generic_class->container_class->this_arg;
3967 t = &t->data.generic_class->container_class->byval_arg;
3969 case MONO_TYPE_PTR: {
3972 /* The argument should be an IntPtr */
3973 arg = mono_array_get (params, MonoObject*, i);
3977 g_assert (arg->vtable->klass == mono_defaults.int_class);
3978 pa [i] = ((MonoIntPtr*)arg)->m_value;
3983 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3988 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3991 if (mono_class_is_nullable (method->klass)) {
3992 /* Need to create a boxed vtype instead */
3998 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4002 obj = mono_object_new (mono_domain_get (), method->klass);
4003 g_assert (obj); /*maybe we should raise a TLE instead?*/
4004 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4005 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4007 if (method->klass->valuetype)
4008 o = mono_object_unbox (obj);
4011 } else if (method->klass->valuetype) {
4012 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4015 mono_runtime_invoke (method, o, pa, exc);
4018 if (mono_class_is_nullable (method->klass)) {
4019 MonoObject *nullable;
4021 /* Convert the unboxed vtype into a Nullable structure */
4022 nullable = mono_object_new (mono_domain_get (), method->klass);
4024 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4025 obj = mono_object_unbox (nullable);
4028 /* obj must be already unboxed if needed */
4029 res = mono_runtime_invoke (method, obj, pa, exc);
4031 if (sig->ret->type == MONO_TYPE_PTR) {
4032 MonoClass *pointer_class;
4033 static MonoMethod *box_method;
4035 MonoObject *box_exc;
4038 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4039 * convert it to a Pointer object.
4041 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4043 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4045 g_assert (res->vtable->klass == mono_defaults.int_class);
4046 box_args [0] = ((MonoIntPtr*)res)->m_value;
4047 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4048 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4049 g_assert (!box_exc);
4052 if (has_byref_nullables) {
4054 * The runtime invoke wrapper already converted byref nullables back,
4055 * and stored them in pa, we just need to copy them back to the
4058 for (i = 0; i < mono_array_length (params); i++) {
4059 MonoType *t = sig->params [i];
4061 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4062 mono_array_setref (params, i, pa [i]);
4071 arith_overflow (void)
4073 mono_raise_exception (mono_get_exception_overflow ());
4077 * mono_object_allocate:
4078 * @size: number of bytes to allocate
4080 * This is a very simplistic routine until we have our GC-aware
4083 * Returns: an allocated object of size @size, or NULL on failure.
4085 static inline void *
4086 mono_object_allocate (size_t size, MonoVTable *vtable)
4089 mono_stats.new_object_count++;
4090 ALLOC_OBJECT (o, vtable, size);
4096 * mono_object_allocate_ptrfree:
4097 * @size: number of bytes to allocate
4099 * Note that the memory allocated is not zeroed.
4100 * Returns: an allocated object of size @size, or NULL on failure.
4102 static inline void *
4103 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4106 mono_stats.new_object_count++;
4107 ALLOC_PTRFREE (o, vtable, size);
4111 static inline void *
4112 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4115 ALLOC_TYPED (o, size, vtable);
4116 mono_stats.new_object_count++;
4123 * @klass: the class of the object that we want to create
4125 * Returns: a newly created object whose definition is
4126 * looked up using @klass. This will not invoke any constructors,
4127 * so the consumer of this routine has to invoke any constructors on
4128 * its own to initialize the object.
4130 * It returns NULL on failure.
4133 mono_object_new (MonoDomain *domain, MonoClass *klass)
4137 MONO_ARCH_SAVE_REGS;
4138 vtable = mono_class_vtable (domain, klass);
4141 return mono_object_new_specific (vtable);
4145 * mono_object_new_specific:
4146 * @vtable: the vtable of the object that we want to create
4148 * Returns: A newly created object with class and domain specified
4152 mono_object_new_specific (MonoVTable *vtable)
4156 MONO_ARCH_SAVE_REGS;
4158 /* check for is_com_object for COM Interop */
4159 if (vtable->remote || vtable->klass->is_com_object)
4162 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4165 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4168 mono_class_init (klass);
4170 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4172 vtable->domain->create_proxy_for_type_method = im;
4175 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4177 o = mono_runtime_invoke (im, NULL, pa, NULL);
4178 if (o != NULL) return o;
4181 return mono_object_new_alloc_specific (vtable);
4185 mono_object_new_alloc_specific (MonoVTable *vtable)
4189 if (!vtable->klass->has_references) {
4190 o = mono_object_new_ptrfree (vtable);
4191 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4192 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4194 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4195 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4197 if (G_UNLIKELY (vtable->klass->has_finalize))
4198 mono_object_register_finalizer (o);
4200 if (G_UNLIKELY (profile_allocs))
4201 mono_profiler_allocation (o, vtable->klass);
4206 mono_object_new_fast (MonoVTable *vtable)
4209 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4214 mono_object_new_ptrfree (MonoVTable *vtable)
4217 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4218 #if NEED_TO_ZERO_PTRFREE
4219 /* an inline memset is much faster for the common vcase of small objects
4220 * note we assume the allocated size is a multiple of sizeof (void*).
4222 if (vtable->klass->instance_size < 128) {
4224 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4225 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4231 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4238 mono_object_new_ptrfree_box (MonoVTable *vtable)
4241 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4242 /* the object will be boxed right away, no need to memzero it */
4247 * mono_class_get_allocation_ftn:
4249 * @for_box: the object will be used for boxing
4250 * @pass_size_in_words:
4252 * Return the allocation function appropriate for the given class.
4256 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4258 *pass_size_in_words = FALSE;
4260 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4261 profile_allocs = FALSE;
4263 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4264 return mono_object_new_specific;
4266 if (!vtable->klass->has_references) {
4267 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4269 return mono_object_new_ptrfree_box;
4270 return mono_object_new_ptrfree;
4273 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4275 return mono_object_new_fast;
4278 * FIXME: This is actually slower than mono_object_new_fast, because
4279 * of the overhead of parameter passing.
4282 *pass_size_in_words = TRUE;
4283 #ifdef GC_REDIRECT_TO_LOCAL
4284 return GC_local_gcj_fast_malloc;
4286 return GC_gcj_fast_malloc;
4291 return mono_object_new_specific;
4295 * mono_object_new_from_token:
4296 * @image: Context where the type_token is hosted
4297 * @token: a token of the type that we want to create
4299 * Returns: A newly created object whose definition is
4300 * looked up using @token in the @image image
4303 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4307 class = mono_class_get (image, token);
4309 return mono_object_new (domain, class);
4314 * mono_object_clone:
4315 * @obj: the object to clone
4317 * Returns: A newly created object who is a shallow copy of @obj
4320 mono_object_clone (MonoObject *obj)
4323 int size = obj->vtable->klass->instance_size;
4325 o = mono_object_allocate (size, obj->vtable);
4327 if (obj->vtable->klass->has_references) {
4328 mono_gc_wbarrier_object_copy (o, obj);
4330 int size = obj->vtable->klass->instance_size;
4331 /* do not copy the sync state */
4332 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4334 if (G_UNLIKELY (profile_allocs))
4335 mono_profiler_allocation (o, obj->vtable->klass);
4337 if (obj->vtable->klass->has_finalize)
4338 mono_object_register_finalizer (o);
4343 * mono_array_full_copy:
4344 * @src: source array to copy
4345 * @dest: destination array
4347 * Copies the content of one array to another with exactly the same type and size.
4350 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4353 MonoClass *klass = src->obj.vtable->klass;
4355 MONO_ARCH_SAVE_REGS;
4357 g_assert (klass == dest->obj.vtable->klass);
4359 size = mono_array_length (src);
4360 g_assert (size == mono_array_length (dest));
4361 size *= mono_array_element_size (klass);
4363 if (klass->element_class->valuetype) {
4364 if (klass->element_class->has_references)
4365 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4367 memcpy (&dest->vector, &src->vector, size);
4369 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4372 memcpy (&dest->vector, &src->vector, size);
4377 * mono_array_clone_in_domain:
4378 * @domain: the domain in which the array will be cloned into
4379 * @array: the array to clone
4381 * This routine returns a copy of the array that is hosted on the
4382 * specified MonoDomain.
4385 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4390 MonoClass *klass = array->obj.vtable->klass;
4392 MONO_ARCH_SAVE_REGS;
4394 if (array->bounds == NULL) {
4395 size = mono_array_length (array);
4396 o = mono_array_new_full (domain, klass, &size, NULL);
4398 size *= mono_array_element_size (klass);
4400 if (klass->element_class->valuetype) {
4401 if (klass->element_class->has_references)
4402 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4404 memcpy (&o->vector, &array->vector, size);
4406 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4409 memcpy (&o->vector, &array->vector, size);
4414 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4415 size = mono_array_element_size (klass);
4416 for (i = 0; i < klass->rank; ++i) {
4417 sizes [i] = array->bounds [i].length;
4418 size *= array->bounds [i].length;
4419 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4421 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4423 if (klass->element_class->valuetype) {
4424 if (klass->element_class->has_references)
4425 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4427 memcpy (&o->vector, &array->vector, size);
4429 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4432 memcpy (&o->vector, &array->vector, size);
4440 * @array: the array to clone
4442 * Returns: A newly created array who is a shallow copy of @array
4445 mono_array_clone (MonoArray *array)
4447 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4450 /* helper macros to check for overflow when calculating the size of arrays */
4451 #ifdef MONO_BIG_ARRAYS
4452 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4453 #define MYGUINT_MAX MYGUINT64_MAX
4454 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4455 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4456 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4457 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4458 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4460 #define MYGUINT32_MAX 4294967295U
4461 #define MYGUINT_MAX MYGUINT32_MAX
4462 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4463 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4464 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4465 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4466 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4470 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4474 byte_len = mono_array_element_size (class);
4475 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4478 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4480 byte_len += sizeof (MonoArray);
4488 * mono_array_new_full:
4489 * @domain: domain where the object is created
4490 * @array_class: array class
4491 * @lengths: lengths for each dimension in the array
4492 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4494 * This routine creates a new array objects with the given dimensions,
4495 * lower bounds and type.
4498 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4500 uintptr_t byte_len, len, bounds_size;
4503 MonoArrayBounds *bounds;
4507 if (!array_class->inited)
4508 mono_class_init (array_class);
4512 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4513 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4515 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4519 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4521 for (i = 0; i < array_class->rank; ++i) {
4522 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4524 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4525 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4530 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4531 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4535 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4536 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4537 byte_len = (byte_len + 3) & ~3;
4538 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4539 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4540 byte_len += bounds_size;
4543 * Following three lines almost taken from mono_object_new ():
4544 * they need to be kept in sync.
4546 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4547 #ifndef HAVE_SGEN_GC
4548 if (!array_class->has_references) {
4549 o = mono_object_allocate_ptrfree (byte_len, vtable);
4550 #if NEED_TO_ZERO_PTRFREE
4551 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4553 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4554 o = mono_object_allocate_spec (byte_len, vtable);
4556 o = mono_object_allocate (byte_len, vtable);
4559 array = (MonoArray*)o;
4560 array->max_length = len;
4563 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4564 array->bounds = bounds;
4568 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4570 o = mono_gc_alloc_vector (vtable, byte_len, len);
4571 array = (MonoArray*)o;
4572 mono_stats.new_object_count++;
4574 bounds = array->bounds;
4578 for (i = 0; i < array_class->rank; ++i) {
4579 bounds [i].length = lengths [i];
4581 bounds [i].lower_bound = lower_bounds [i];
4585 if (G_UNLIKELY (profile_allocs))
4586 mono_profiler_allocation (o, array_class);
4593 * @domain: domain where the object is created
4594 * @eclass: element class
4595 * @n: number of array elements
4597 * This routine creates a new szarray with @n elements of type @eclass.
4600 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4604 MONO_ARCH_SAVE_REGS;
4606 ac = mono_array_class_get (eclass, 1);
4609 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4613 * mono_array_new_specific:
4614 * @vtable: a vtable in the appropriate domain for an initialized class
4615 * @n: number of array elements
4617 * This routine is a fast alternative to mono_array_new() for code which
4618 * can be sure about the domain it operates in.
4621 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4627 MONO_ARCH_SAVE_REGS;
4629 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4634 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4635 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4638 #ifndef HAVE_SGEN_GC
4639 if (!vtable->klass->has_references) {
4640 o = mono_object_allocate_ptrfree (byte_len, vtable);
4641 #if NEED_TO_ZERO_PTRFREE
4642 ((MonoArray*)o)->bounds = NULL;
4643 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4645 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4646 o = mono_object_allocate_spec (byte_len, vtable);
4648 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4649 o = mono_object_allocate (byte_len, vtable);
4652 ao = (MonoArray *)o;
4655 o = mono_gc_alloc_vector (vtable, byte_len, n);
4657 mono_stats.new_object_count++;
4660 if (G_UNLIKELY (profile_allocs))
4661 mono_profiler_allocation (o, vtable->klass);
4667 * mono_string_new_utf16:
4668 * @text: a pointer to an utf16 string
4669 * @len: the length of the string
4671 * Returns: A newly created string object which contains @text.
4674 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4678 s = mono_string_new_size (domain, len);
4679 g_assert (s != NULL);
4681 memcpy (mono_string_chars (s), text, len * 2);
4687 * mono_string_new_size:
4688 * @text: a pointer to an utf16 string
4689 * @len: the length of the string
4691 * Returns: A newly created string object of @len
4694 mono_string_new_size (MonoDomain *domain, gint32 len)
4698 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4700 /* overflow ? can't fit it, can't allocate it! */
4702 mono_gc_out_of_memory (-1);
4704 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4707 #ifndef HAVE_SGEN_GC
4708 s = mono_object_allocate_ptrfree (size, vtable);
4712 s = mono_gc_alloc_string (vtable, size, len);
4714 #if NEED_TO_ZERO_PTRFREE
4717 if (G_UNLIKELY (profile_allocs))
4718 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4724 * mono_string_new_len:
4725 * @text: a pointer to an utf8 string
4726 * @length: number of bytes in @text to consider
4728 * Returns: A newly created string object which contains @text.
4731 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4733 GError *error = NULL;
4734 MonoString *o = NULL;
4736 glong items_written;
4738 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4741 o = mono_string_new_utf16 (domain, ut, items_written);
4743 g_error_free (error);
4752 * @text: a pointer to an utf8 string
4754 * Returns: A newly created string object which contains @text.
4757 mono_string_new (MonoDomain *domain, const char *text)
4759 GError *error = NULL;
4760 MonoString *o = NULL;
4762 glong items_written;
4767 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4770 o = mono_string_new_utf16 (domain, ut, items_written);
4772 g_error_free (error);
4775 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4780 MonoString *o = NULL;
4782 if (!g_utf8_validate (text, -1, &end))
4785 len = g_utf8_strlen (text, -1);
4786 o = mono_string_new_size (domain, len);
4787 str = mono_string_chars (o);
4789 while (text < end) {
4790 *str++ = g_utf8_get_char (text);
4791 text = g_utf8_next_char (text);
4798 * mono_string_new_wrapper:
4799 * @text: pointer to utf8 characters.
4801 * Helper function to create a string object from @text in the current domain.
4804 mono_string_new_wrapper (const char *text)
4806 MonoDomain *domain = mono_domain_get ();
4808 MONO_ARCH_SAVE_REGS;
4811 return mono_string_new (domain, text);
4818 * @class: the class of the value
4819 * @value: a pointer to the unboxed data
4821 * Returns: A newly created object which contains @value.
4824 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4830 g_assert (class->valuetype);
4831 if (mono_class_is_nullable (class))
4832 return mono_nullable_box (value, class);
4834 vtable = mono_class_vtable (domain, class);
4837 size = mono_class_instance_size (class);
4838 res = mono_object_new_alloc_specific (vtable);
4839 if (G_UNLIKELY (profile_allocs))
4840 mono_profiler_allocation (res, class);
4842 size = size - sizeof (MonoObject);
4845 g_assert (size == mono_class_value_size (class, NULL));
4846 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4848 #if NO_UNALIGNED_ACCESS
4849 memcpy ((char *)res + sizeof (MonoObject), value, size);
4853 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4856 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4859 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4862 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4865 memcpy ((char *)res + sizeof (MonoObject), value, size);
4869 if (class->has_finalize)
4870 mono_object_register_finalizer (res);
4876 * @dest: destination pointer
4877 * @src: source pointer
4878 * @klass: a valuetype class
4880 * Copy a valuetype from @src to @dest. This function must be used
4881 * when @klass contains references fields.
4884 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4886 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4890 * mono_value_copy_array:
4891 * @dest: destination array
4892 * @dest_idx: index in the @dest array
4893 * @src: source pointer
4894 * @count: number of items
4896 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4897 * This function must be used when @klass contains references fields.
4898 * Overlap is handled.
4901 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4903 int size = mono_array_element_size (dest->obj.vtable->klass);
4904 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4905 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4906 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4910 * mono_object_get_domain:
4911 * @obj: object to query
4913 * Returns: the MonoDomain where the object is hosted
4916 mono_object_get_domain (MonoObject *obj)
4918 return mono_object_domain (obj);
4922 * mono_object_get_class:
4923 * @obj: object to query
4925 * Returns: the MonOClass of the object.
4928 mono_object_get_class (MonoObject *obj)
4930 return mono_object_class (obj);
4933 * mono_object_get_size:
4934 * @o: object to query
4936 * Returns: the size, in bytes, of @o
4939 mono_object_get_size (MonoObject* o)
4941 MonoClass* klass = mono_object_class (o);
4942 if (klass == mono_defaults.string_class) {
4943 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4944 } else if (o->vtable->rank) {
4945 MonoArray *array = (MonoArray*)o;
4946 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4947 if (array->bounds) {
4950 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4954 return mono_class_instance_size (klass);
4959 * mono_object_unbox:
4960 * @obj: object to unbox
4962 * Returns: a pointer to the start of the valuetype boxed in this
4965 * This method will assert if the object passed is not a valuetype.
4968 mono_object_unbox (MonoObject *obj)
4970 /* add assert for valuetypes? */
4971 g_assert (obj->vtable->klass->valuetype);
4972 return ((char*)obj) + sizeof (MonoObject);
4976 * mono_object_isinst:
4978 * @klass: a pointer to a class
4980 * Returns: @obj if @obj is derived from @klass
4983 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4986 mono_class_init (klass);
4988 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
4989 return mono_object_isinst_mbyref (obj, klass);
4994 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4998 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5007 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5008 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5012 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5013 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5016 MonoClass *oklass = vt->klass;
5017 if ((oklass == mono_defaults.transparent_proxy_class))
5018 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5020 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5024 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5026 MonoDomain *domain = mono_domain_get ();
5028 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5029 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5030 MonoMethod *im = NULL;
5033 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5034 im = mono_object_get_virtual_method (rp, im);
5037 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5040 res = mono_runtime_invoke (im, rp, pa, NULL);
5042 if (*(MonoBoolean *) mono_object_unbox(res)) {
5043 /* Update the vtable of the remote type, so it can safely cast to this new type */
5044 mono_upgrade_remote_class (domain, obj, klass);
5053 * mono_object_castclass_mbyref:
5055 * @klass: a pointer to a class
5057 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5060 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5062 if (!obj) return NULL;
5063 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5065 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5067 "InvalidCastException"));
5072 MonoDomain *orig_domain;
5078 str_lookup (MonoDomain *domain, gpointer user_data)
5080 LDStrInfo *info = user_data;
5081 if (info->res || domain == info->orig_domain)
5083 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5089 mono_string_get_pinned (MonoString *str)
5093 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5094 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5095 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5096 news->length = mono_string_length (str);
5101 #define mono_string_get_pinned(str) (str)
5105 mono_string_is_interned_lookup (MonoString *str, int insert)
5107 MonoGHashTable *ldstr_table;
5111 domain = ((MonoObject *)str)->vtable->domain;
5112 ldstr_table = domain->ldstr_table;
5114 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5119 str = mono_string_get_pinned (str);
5120 mono_g_hash_table_insert (ldstr_table, str, str);
5124 LDStrInfo ldstr_info;
5125 ldstr_info.orig_domain = domain;
5126 ldstr_info.ins = str;
5127 ldstr_info.res = NULL;
5129 mono_domain_foreach (str_lookup, &ldstr_info);
5130 if (ldstr_info.res) {
5132 * the string was already interned in some other domain:
5133 * intern it in the current one as well.
5135 mono_g_hash_table_insert (ldstr_table, str, str);
5145 * mono_string_is_interned:
5146 * @o: String to probe
5148 * Returns whether the string has been interned.
5151 mono_string_is_interned (MonoString *o)
5153 return mono_string_is_interned_lookup (o, FALSE);
5157 * mono_string_intern:
5158 * @o: String to intern
5160 * Interns the string passed.
5161 * Returns: The interned string.
5164 mono_string_intern (MonoString *str)
5166 return mono_string_is_interned_lookup (str, TRUE);
5171 * @domain: the domain where the string will be used.
5172 * @image: a metadata context
5173 * @idx: index into the user string table.
5175 * Implementation for the ldstr opcode.
5176 * Returns: a loaded string from the @image/@idx combination.
5179 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5181 MONO_ARCH_SAVE_REGS;
5183 if (image->dynamic) {
5184 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5187 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5188 return NULL; /*FIXME we should probably be raising an exception here*/
5189 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5194 * mono_ldstr_metadata_sig
5195 * @domain: the domain for the string
5196 * @sig: the signature of a metadata string
5198 * Returns: a MonoString for a string stored in the metadata
5201 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5203 const char *str = sig;
5204 MonoString *o, *interned;
5207 len2 = mono_metadata_decode_blob_size (str, &str);
5210 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5211 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5214 guint16 *p2 = (guint16*)mono_string_chars (o);
5215 for (i = 0; i < len2; ++i) {
5216 *p2 = GUINT16_FROM_LE (*p2);
5222 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5224 /* o will get garbage collected */
5228 o = mono_string_get_pinned (o);
5229 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5236 * mono_string_to_utf8:
5237 * @s: a System.String
5239 * Return the UTF8 representation for @s.
5240 * the resulting buffer nedds to be freed with g_free().
5242 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5245 mono_string_to_utf8 (MonoString *s)
5248 char *result = mono_string_to_utf8_checked (s, &error);
5250 if (!mono_error_ok (&error))
5251 mono_error_raise_exception (&error);
5256 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5260 GError *gerror = NULL;
5262 mono_error_init (error);
5268 return g_strdup ("");
5270 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5272 mono_error_set_argument (error, "string", "%s", gerror->message);
5273 g_error_free (gerror);
5276 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5277 if (s->length > written) {
5278 /* allocate the total length and copy the part of the string that has been converted */
5279 char *as2 = g_malloc0 (s->length);
5280 memcpy (as2, as, written);
5289 * mono_string_to_utf16:
5292 * Return an null-terminated array of the utf-16 chars
5293 * contained in @s. The result must be freed with g_free().
5294 * This is a temporary helper until our string implementation
5295 * is reworked to always include the null terminating char.
5298 mono_string_to_utf16 (MonoString *s)
5305 as = g_malloc ((s->length * 2) + 2);
5306 as [(s->length * 2)] = '\0';
5307 as [(s->length * 2) + 1] = '\0';
5310 return (gunichar2 *)(as);
5313 memcpy (as, mono_string_chars(s), s->length * 2);
5314 return (gunichar2 *)(as);
5318 * mono_string_from_utf16:
5319 * @data: the UTF16 string (LPWSTR) to convert
5321 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5323 * Returns: a MonoString.
5326 mono_string_from_utf16 (gunichar2 *data)
5328 MonoDomain *domain = mono_domain_get ();
5334 while (data [len]) len++;
5336 return mono_string_new_utf16 (domain, data, len);
5341 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5347 r = mono_string_to_utf8_checked (s, error);
5348 if (!mono_error_ok (error))
5354 len = strlen (r) + 1;
5356 mp_s = mono_mempool_alloc (mp, len);
5358 mp_s = mono_image_alloc (image, len);
5360 memcpy (mp_s, r, len);
5368 * mono_string_to_utf8_image:
5369 * @s: a System.String
5371 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5374 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5376 return mono_string_to_utf8_internal (NULL, image, s, error);
5380 * mono_string_to_utf8_mp:
5381 * @s: a System.String
5383 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5386 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5388 return mono_string_to_utf8_internal (mp, NULL, s, error);
5392 default_ex_handler (MonoException *ex)
5394 MonoObject *o = (MonoObject*)ex;
5395 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5399 static MonoExceptionFunc ex_handler = default_ex_handler;
5402 * mono_install_handler:
5403 * @func: exception handler
5405 * This is an internal JIT routine used to install the handler for exceptions
5409 mono_install_handler (MonoExceptionFunc func)
5411 ex_handler = func? func: default_ex_handler;
5415 * mono_raise_exception:
5416 * @ex: exception object
5418 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5421 mono_raise_exception (MonoException *ex)
5424 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5425 * that will cause gcc to omit the function epilog, causing problems when
5426 * the JIT tries to walk the stack, since the return address on the stack
5427 * will point into the next function in the executable, not this one.
5430 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5431 MonoInternalThread *thread = mono_thread_internal_current ();
5432 g_assert (ex->object.vtable->domain == mono_domain_get ());
5433 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5440 * mono_wait_handle_new:
5441 * @domain: Domain where the object will be created
5442 * @handle: Handle for the wait handle
5444 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5447 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5449 MonoWaitHandle *res;
5450 gpointer params [1];
5451 static MonoMethod *handle_set;
5453 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5455 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5457 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5459 params [0] = &handle;
5460 mono_runtime_invoke (handle_set, res, params, NULL);
5466 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5468 static MonoClassField *f_os_handle;
5469 static MonoClassField *f_safe_handle;
5471 if (!f_os_handle && !f_safe_handle) {
5472 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5473 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5478 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5482 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5489 mono_runtime_capture_context (MonoDomain *domain)
5491 RuntimeInvokeFunction runtime_invoke;
5493 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5494 MonoMethod *method = mono_get_context_capture_method ();
5495 MonoMethod *wrapper;
5498 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5499 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5500 domain->capture_context_method = mono_compile_method (method);
5503 runtime_invoke = domain->capture_context_runtime_invoke;
5505 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5508 * mono_async_result_new:
5509 * @domain:domain where the object will be created.
5510 * @handle: wait handle.
5511 * @state: state to pass to AsyncResult
5512 * @data: C closure data.
5514 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5515 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5519 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5521 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5522 MonoObject *context = mono_runtime_capture_context (domain);
5523 /* we must capture the execution context from the original thread */
5525 MONO_OBJECT_SETREF (res, execution_context, context);
5526 /* note: result may be null if the flow is suppressed */
5530 MONO_OBJECT_SETREF (res, object_data, object_data);
5531 MONO_OBJECT_SETREF (res, async_state, state);
5533 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5535 res->sync_completed = FALSE;
5536 res->completed = FALSE;
5542 mono_message_init (MonoDomain *domain,
5543 MonoMethodMessage *this,
5544 MonoReflectionMethod *method,
5545 MonoArray *out_args)
5547 static MonoClass *object_array_klass;
5548 static MonoClass *byte_array_klass;
5549 static MonoClass *string_array_klass;
5550 MonoMethodSignature *sig = mono_method_signature (method->method);
5556 if (!object_array_klass) {
5559 klass = mono_array_class_get (mono_defaults.object_class, 1);
5562 mono_memory_barrier ();
5563 object_array_klass = klass;
5565 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5568 mono_memory_barrier ();
5569 byte_array_klass = klass;
5571 klass = mono_array_class_get (mono_defaults.string_class, 1);
5574 mono_memory_barrier ();
5575 string_array_klass = klass;
5578 MONO_OBJECT_SETREF (this, method, method);
5580 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5581 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5582 this->async_result = NULL;
5583 this->call_type = CallType_Sync;
5585 names = g_new (char *, sig->param_count);
5586 mono_method_get_param_names (method->method, (const char **) names);
5587 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5589 for (i = 0; i < sig->param_count; i++) {
5590 name = mono_string_new (domain, names [i]);
5591 mono_array_setref (this->names, i, name);
5595 for (i = 0, j = 0; i < sig->param_count; i++) {
5596 if (sig->params [i]->byref) {
5598 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5599 mono_array_setref (this->args, i, arg);
5603 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5607 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5610 mono_array_set (this->arg_types, guint8, i, arg_type);
5615 * mono_remoting_invoke:
5616 * @real_proxy: pointer to a RealProxy object
5617 * @msg: The MonoMethodMessage to execute
5618 * @exc: used to store exceptions
5619 * @out_args: used to store output arguments
5621 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5622 * IMessage interface and it is not trivial to extract results from there. So
5623 * we call an helper method PrivateInvoke instead of calling
5624 * RealProxy::Invoke() directly.
5626 * Returns: the result object.
5629 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5630 MonoObject **exc, MonoArray **out_args)
5632 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5635 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5638 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5640 real_proxy->vtable->domain->private_invoke_method = im;
5643 pa [0] = real_proxy;
5648 return mono_runtime_invoke (im, NULL, pa, exc);
5652 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5653 MonoObject **exc, MonoArray **out_args)
5655 static MonoClass *object_array_klass;
5658 MonoMethodSignature *sig;
5660 int i, j, outarg_count = 0;
5662 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5664 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5665 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5666 target = tp->rp->unwrapped_server;
5668 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5672 domain = mono_domain_get ();
5673 method = msg->method->method;
5674 sig = mono_method_signature (method);
5676 for (i = 0; i < sig->param_count; i++) {
5677 if (sig->params [i]->byref)
5681 if (!object_array_klass) {
5684 klass = mono_array_class_get (mono_defaults.object_class, 1);
5687 mono_memory_barrier ();
5688 object_array_klass = klass;
5691 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5692 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5695 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5697 for (i = 0, j = 0; i < sig->param_count; i++) {
5698 if (sig->params [i]->byref) {
5700 arg = mono_array_get (msg->args, gpointer, i);
5701 mono_array_setref (*out_args, j, arg);
5710 * mono_print_unhandled_exception:
5711 * @exc: The exception
5713 * Prints the unhandled exception.
5716 mono_print_unhandled_exception (MonoObject *exc)
5719 char *message = (char *) "";
5723 gboolean free_message = FALSE;
5725 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5726 klass = exc->vtable->klass;
5728 while (klass && method == NULL) {
5729 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5731 klass = klass->parent;
5736 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5738 message = mono_string_to_utf8_checked (str, &error);
5739 if (!mono_error_ok (&error)) {
5740 mono_error_cleanup (&error);
5741 message = (char *)"";
5743 free_message = TRUE;
5749 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5750 * exc->vtable->klass->name, message);
5752 g_printerr ("\nUnhandled Exception: %s\n", message);
5759 * mono_delegate_ctor:
5760 * @this: pointer to an uninitialized delegate object
5761 * @target: target object
5762 * @addr: pointer to native code
5765 * Initialize a delegate and sets a specific method, not the one
5766 * associated with addr. This is useful when sharing generic code.
5767 * In that case addr will most probably not be associated with the
5768 * correct instantiation of the method.
5771 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5773 MonoDelegate *delegate = (MonoDelegate *)this;
5780 delegate->method = method;
5782 class = this->vtable->klass;
5783 mono_stats.delegate_creations++;
5785 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5787 method = mono_marshal_get_remoting_invoke (method);
5788 delegate->method_ptr = mono_compile_method (method);
5789 MONO_OBJECT_SETREF (delegate, target, target);
5790 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5791 method = mono_marshal_get_unbox_wrapper (method);
5792 delegate->method_ptr = mono_compile_method (method);
5793 MONO_OBJECT_SETREF (delegate, target, target);
5795 delegate->method_ptr = addr;
5796 MONO_OBJECT_SETREF (delegate, target, target);
5799 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5803 * mono_delegate_ctor:
5804 * @this: pointer to an uninitialized delegate object
5805 * @target: target object
5806 * @addr: pointer to native code
5808 * This is used to initialize a delegate.
5811 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5813 MonoDomain *domain = mono_domain_get ();
5815 MonoMethod *method = NULL;
5819 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5820 method = ji->method;
5821 g_assert (!method->klass->generic_container);
5824 mono_delegate_ctor_with_method (this, target, addr, method);
5828 * mono_method_call_message_new:
5829 * @method: method to encapsulate
5830 * @params: parameters to the method
5831 * @invoke: optional, delegate invoke.
5832 * @cb: async callback delegate.
5833 * @state: state passed to the async callback.
5835 * Translates arguments pointers into a MonoMethodMessage.
5838 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5839 MonoDelegate **cb, MonoObject **state)
5841 MonoDomain *domain = mono_domain_get ();
5842 MonoMethodSignature *sig = mono_method_signature (method);
5843 MonoMethodMessage *msg;
5846 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5849 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5850 count = sig->param_count - 2;
5852 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5853 count = sig->param_count;
5856 for (i = 0; i < count; i++) {
5861 if (sig->params [i]->byref)
5862 vpos = *((gpointer *)params [i]);
5866 type = sig->params [i]->type;
5867 class = mono_class_from_mono_type (sig->params [i]);
5869 if (class->valuetype)
5870 arg = mono_value_box (domain, class, vpos);
5872 arg = *((MonoObject **)vpos);
5874 mono_array_setref (msg->args, i, arg);
5877 if (cb != NULL && state != NULL) {
5878 *cb = *((MonoDelegate **)params [i]);
5880 *state = *((MonoObject **)params [i]);
5887 * mono_method_return_message_restore:
5889 * Restore results from message based processing back to arguments pointers
5892 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5894 MonoMethodSignature *sig = mono_method_signature (method);
5895 int i, j, type, size, out_len;
5897 if (out_args == NULL)
5899 out_len = mono_array_length (out_args);
5903 for (i = 0, j = 0; i < sig->param_count; i++) {
5904 MonoType *pt = sig->params [i];
5909 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5911 arg = mono_array_get (out_args, gpointer, j);
5914 g_assert (type != MONO_TYPE_VOID);
5916 if (MONO_TYPE_IS_REFERENCE (pt)) {
5917 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5920 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5921 size = mono_class_value_size (class, NULL);
5922 if (class->has_references)
5923 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5925 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5927 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5928 memset (*((gpointer *)params [i]), 0, size);
5938 * mono_load_remote_field:
5939 * @this: pointer to an object
5940 * @klass: klass of the object containing @field
5941 * @field: the field to load
5942 * @res: a storage to store the result
5944 * This method is called by the runtime on attempts to load fields of
5945 * transparent proxy objects. @this points to such TP, @klass is the class of
5946 * the object containing @field. @res is a storage location which can be
5947 * used to store the result.
5949 * Returns: an address pointing to the value of field.
5952 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5954 static MonoMethod *getter = NULL;
5955 MonoDomain *domain = mono_domain_get ();
5956 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5957 MonoClass *field_class;
5958 MonoMethodMessage *msg;
5959 MonoArray *out_args;
5963 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5964 g_assert (res != NULL);
5966 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5967 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5972 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5976 field_class = mono_class_from_mono_type (field->type);
5978 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5979 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5980 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5982 full_name = mono_type_get_full_name (klass);
5983 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5984 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5987 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5989 if (exc) mono_raise_exception ((MonoException *)exc);
5991 if (mono_array_length (out_args) == 0)
5994 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5996 if (field_class->valuetype) {
5997 return ((char *)*res) + sizeof (MonoObject);
6003 * mono_load_remote_field_new:
6008 * Missing documentation.
6011 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6013 static MonoMethod *getter = NULL;
6014 MonoDomain *domain = mono_domain_get ();
6015 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6016 MonoClass *field_class;
6017 MonoMethodMessage *msg;
6018 MonoArray *out_args;
6019 MonoObject *exc, *res;
6022 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6024 field_class = mono_class_from_mono_type (field->type);
6026 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6028 if (field_class->valuetype) {
6029 res = mono_object_new (domain, field_class);
6030 val = ((gchar *) res) + sizeof (MonoObject);
6034 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6039 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6043 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6044 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6046 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6048 full_name = mono_type_get_full_name (klass);
6049 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6050 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6053 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6055 if (exc) mono_raise_exception ((MonoException *)exc);
6057 if (mono_array_length (out_args) == 0)
6060 res = mono_array_get (out_args, MonoObject *, 0);
6066 * mono_store_remote_field:
6067 * @this: pointer to an object
6068 * @klass: klass of the object containing @field
6069 * @field: the field to load
6070 * @val: the value/object to store
6072 * This method is called by the runtime on attempts to store fields of
6073 * transparent proxy objects. @this points to such TP, @klass is the class of
6074 * the object containing @field. @val is the new value to store in @field.
6077 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6079 static MonoMethod *setter = NULL;
6080 MonoDomain *domain = mono_domain_get ();
6081 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6082 MonoClass *field_class;
6083 MonoMethodMessage *msg;
6084 MonoArray *out_args;
6089 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6091 field_class = mono_class_from_mono_type (field->type);
6093 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6094 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6095 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6100 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6104 if (field_class->valuetype)
6105 arg = mono_value_box (domain, field_class, val);
6107 arg = *((MonoObject **)val);
6110 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6111 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6113 full_name = mono_type_get_full_name (klass);
6114 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6115 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6116 mono_array_setref (msg->args, 2, arg);
6119 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6121 if (exc) mono_raise_exception ((MonoException *)exc);
6125 * mono_store_remote_field_new:
6131 * Missing documentation
6134 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6136 static MonoMethod *setter = NULL;
6137 MonoDomain *domain = mono_domain_get ();
6138 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6139 MonoClass *field_class;
6140 MonoMethodMessage *msg;
6141 MonoArray *out_args;
6145 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6147 field_class = mono_class_from_mono_type (field->type);
6149 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6150 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6151 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6156 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6160 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6161 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6163 full_name = mono_type_get_full_name (klass);
6164 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6165 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6166 mono_array_setref (msg->args, 2, arg);
6169 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6171 if (exc) mono_raise_exception ((MonoException *)exc);
6175 * mono_create_ftnptr:
6177 * Given a function address, create a function descriptor for it.
6178 * This is only needed on some platforms.
6181 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6183 return callbacks.create_ftnptr (domain, addr);
6187 * mono_get_addr_from_ftnptr:
6189 * Given a pointer to a function descriptor, return the function address.
6190 * This is only needed on some platforms.
6193 mono_get_addr_from_ftnptr (gpointer descr)
6195 return callbacks.get_addr_from_ftnptr (descr);
6199 * mono_string_chars:
6202 * Returns a pointer to the UCS16 characters stored in the MonoString
6205 mono_string_chars (MonoString *s)
6211 * mono_string_length:
6214 * Returns the lenght in characters of the string
6217 mono_string_length (MonoString *s)
6223 * mono_array_length:
6224 * @array: a MonoArray*
6226 * Returns the total number of elements in the array. This works for
6227 * both vectors and multidimensional arrays.
6230 mono_array_length (MonoArray *array)
6232 return array->max_length;
6236 * mono_array_addr_with_size:
6237 * @array: a MonoArray*
6238 * @size: size of the array elements
6239 * @idx: index into the array
6241 * Returns the address of the @idx element in the array.
6244 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6246 return ((char*)(array)->vector) + size * idx;