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 static gpointer vtable_trampoline = NULL;
999 mono_install_vtable_trampoline (gpointer tramp_code)
1001 vtable_trampoline = tramp_code;
1004 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1005 #define mix(a,b,c) { \
1006 a -= c; a ^= rot(c, 4); c += b; \
1007 b -= a; b ^= rot(a, 6); a += c; \
1008 c -= b; c ^= rot(b, 8); b += a; \
1009 a -= c; a ^= rot(c,16); c += b; \
1010 b -= a; b ^= rot(a,19); a += c; \
1011 c -= b; c ^= rot(b, 4); b += a; \
1013 #define final(a,b,c) { \
1014 c ^= b; c -= rot(b,14); \
1015 a ^= c; a -= rot(c,11); \
1016 b ^= a; b -= rot(a,25); \
1017 c ^= b; c -= rot(b,16); \
1018 a ^= c; a -= rot(c,4); \
1019 b ^= a; b -= rot(a,14); \
1020 c ^= b; c -= rot(b,24); \
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] = g_str_hash (method->klass->name);
1057 hashes [1] = g_str_hash (method->klass->name_space);
1058 hashes [2] = g_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;
1267 if (mono_class_has_variant_generic_params (iface))
1268 has_variant_iface = TRUE;
1270 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1273 if (slot_num >= 0 && iface->is_inflated) {
1275 * The imt slot of the method is the same as for its declaring method,
1276 * see the comment in mono_method_get_imt_slot (), so we can
1277 * avoid inflating methods which will be discarded by
1278 * add_imt_builder_entry anyway.
1280 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1281 if (mono_method_get_imt_slot (method) != slot_num)
1284 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1285 if (method->is_generic) {
1286 has_generic_virtual = TRUE;
1290 /*FIXME (interface_offset + method_slot_in_interface) is wrong for interfaces with static methods.*/
1291 if (method->flags & METHOD_ATTRIBUTE_STATIC)
1294 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1297 if (extra_interfaces) {
1298 int interface_offset = klass->vtable_size;
1300 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1301 MonoClass* iface = list_item->data;
1302 int method_slot_in_interface;
1303 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1304 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1305 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1307 interface_offset += iface->method.count;
1310 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1311 /* overwrite the imt slot only if we're building all the entries or if
1312 * we're building this specific one
1314 if (slot_num < 0 || i == slot_num) {
1315 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1318 if (imt_builder [i]) {
1319 MonoImtBuilderEntry *entry;
1321 /* Link entries with imt_builder [i] */
1322 for (entry = entries; entry->next; entry = entry->next) {
1324 MonoMethod *method = (MonoMethod*)entry->key;
1325 char *method_name = mono_method_full_name (method, TRUE);
1326 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1327 g_free (method_name);
1330 entry->next = imt_builder [i];
1331 entries->children += imt_builder [i]->children + 1;
1333 imt_builder [i] = entries;
1336 if (has_generic_virtual || has_variant_iface) {
1338 * There might be collisions later when the the thunk is expanded.
1340 imt_collisions_bitmap |= (1 << i);
1343 * The IMT thunk might be called with an instance of one of the
1344 * generic virtual methods, so has to fallback to the IMT trampoline.
1346 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1348 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1351 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1355 if (imt_builder [i] != NULL) {
1356 int methods_in_slot = imt_builder [i]->children + 1;
1357 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1358 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1359 record_method_count_for_max_collisions = TRUE;
1361 method_count += methods_in_slot;
1365 mono_stats.imt_number_of_methods += method_count;
1366 if (record_method_count_for_max_collisions) {
1367 mono_stats.imt_method_count_when_max_collisions = method_count;
1370 for (i = 0; i < MONO_IMT_SIZE; i++) {
1371 MonoImtBuilderEntry* entry = imt_builder [i];
1372 while (entry != NULL) {
1373 MonoImtBuilderEntry* next = entry->next;
1379 /* we OR the bitmap since we may build just a single imt slot at a time */
1380 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1384 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1385 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1389 * mono_vtable_build_imt_slot:
1390 * @vtable: virtual object table struct
1391 * @imt_slot: slot in the IMT table
1393 * Fill the given @imt_slot in the IMT table of @vtable with
1394 * a trampoline or a thunk for the case of collisions.
1395 * This is part of the internal mono API.
1397 * LOCKING: Take the domain lock.
1400 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1402 gpointer *imt = (gpointer*)vtable;
1403 imt -= MONO_IMT_SIZE;
1404 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1406 /* no support for extra interfaces: the proxy objects will need
1407 * to build the complete IMT
1408 * Update and heck needs to ahppen inside the proper domain lock, as all
1409 * the changes made to a MonoVTable.
1411 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1412 mono_domain_lock (vtable->domain);
1413 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1414 if (imt [imt_slot] == imt_trampoline)
1415 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1416 mono_domain_unlock (vtable->domain);
1417 mono_loader_unlock ();
1422 * The first two free list entries both belong to the wait list: The
1423 * first entry is the pointer to the head of the list and the second
1424 * entry points to the last element. That way appending and removing
1425 * the first element are both O(1) operations.
1427 #define NUM_FREE_LISTS 12
1428 #define FIRST_FREE_LIST_SIZE 64
1429 #define MAX_WAIT_LENGTH 50
1430 #define THUNK_THRESHOLD 10
1433 * LOCKING: The domain lock must be held.
1436 init_thunk_free_lists (MonoDomain *domain)
1438 if (domain->thunk_free_lists)
1440 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1444 list_index_for_size (int item_size)
1447 int size = FIRST_FREE_LIST_SIZE;
1449 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1458 * mono_method_alloc_generic_virtual_thunk:
1460 * @size: size in bytes
1462 * Allocs size bytes to be used for the code of a generic virtual
1463 * thunk. It's either allocated from the domain's code manager or
1464 * reused from a previously invalidated piece.
1466 * LOCKING: The domain lock must be held.
1469 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1471 static gboolean inited = FALSE;
1472 static int generic_virtual_thunks_size = 0;
1476 MonoThunkFreeList **l;
1478 init_thunk_free_lists (domain);
1480 size += sizeof (guint32);
1481 if (size < sizeof (MonoThunkFreeList))
1482 size = sizeof (MonoThunkFreeList);
1484 i = list_index_for_size (size);
1485 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1486 if ((*l)->size >= size) {
1487 MonoThunkFreeList *item = *l;
1489 return ((guint32*)item) + 1;
1493 /* no suitable item found - search lists of larger sizes */
1494 while (++i < NUM_FREE_LISTS) {
1495 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1498 g_assert (item->size > size);
1499 domain->thunk_free_lists [i] = item->next;
1500 return ((guint32*)item) + 1;
1503 /* still nothing found - allocate it */
1505 mono_counters_register ("Generic virtual thunk bytes",
1506 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1509 generic_virtual_thunks_size += size;
1511 p = mono_domain_code_reserve (domain, size);
1518 * LOCKING: The domain lock must be held.
1521 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1524 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1526 init_thunk_free_lists (domain);
1528 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1529 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1530 int length = item->length;
1533 /* unlink the first item from the wait list */
1534 domain->thunk_free_lists [0] = item->next;
1535 domain->thunk_free_lists [0]->length = length - 1;
1537 i = list_index_for_size (item->size);
1539 /* put it in the free list */
1540 item->next = domain->thunk_free_lists [i];
1541 domain->thunk_free_lists [i] = item;
1545 if (domain->thunk_free_lists [1]) {
1546 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1547 domain->thunk_free_lists [0]->length++;
1549 g_assert (!domain->thunk_free_lists [0]);
1551 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1552 domain->thunk_free_lists [0]->length = 1;
1556 typedef struct _GenericVirtualCase {
1560 struct _GenericVirtualCase *next;
1561 } GenericVirtualCase;
1564 * get_generic_virtual_entries:
1566 * Return IMT entries for the generic virtual method instances and
1567 * variant interface methods for vtable slot
1570 static MonoImtBuilderEntry*
1571 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1573 GenericVirtualCase *list;
1574 MonoImtBuilderEntry *entries;
1576 mono_domain_lock (domain);
1577 if (!domain->generic_virtual_cases)
1578 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1580 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1583 for (; list; list = list->next) {
1584 MonoImtBuilderEntry *entry;
1586 if (list->count < THUNK_THRESHOLD)
1589 entry = g_new0 (MonoImtBuilderEntry, 1);
1590 entry->key = list->method;
1591 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1592 entry->has_target_code = 1;
1594 entry->children = entries->children + 1;
1595 entry->next = entries;
1599 mono_domain_unlock (domain);
1601 /* FIXME: Leaking memory ? */
1606 * mono_method_add_generic_virtual_invocation:
1608 * @vtable_slot: pointer to the vtable slot
1609 * @method: the inflated generic virtual method
1610 * @code: the method's code
1612 * Registers a call via unmanaged code to a generic virtual method
1613 * instantiation or variant interface method. If the number of calls reaches a threshold
1614 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1615 * virtual method thunk.
1618 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1619 gpointer *vtable_slot,
1620 MonoMethod *method, gpointer code)
1622 static gboolean inited = FALSE;
1623 static int num_added = 0;
1625 GenericVirtualCase *gvc, *list;
1626 MonoImtBuilderEntry *entries;
1630 mono_domain_lock (domain);
1631 if (!domain->generic_virtual_cases)
1632 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1634 /* Check whether the case was already added */
1635 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1638 if (gvc->method == method)
1643 /* If not found, make a new one */
1645 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1646 gvc->method = method;
1649 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1651 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1654 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1660 if (++gvc->count == THUNK_THRESHOLD) {
1661 gpointer *old_thunk = *vtable_slot;
1663 if ((gpointer)vtable_slot < (gpointer)vtable)
1664 /* Force the rebuild of the thunk at the next call */
1665 *vtable_slot = imt_trampoline;
1667 entries = get_generic_virtual_entries (domain, vtable_slot);
1669 sorted = imt_sort_slot_entries (entries);
1671 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1675 MonoImtBuilderEntry *next = entries->next;
1680 for (i = 0; i < sorted->len; ++i)
1681 g_free (g_ptr_array_index (sorted, i));
1682 g_ptr_array_free (sorted, TRUE);
1685 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1686 invalidate_generic_virtual_thunk (domain, old_thunk);
1689 mono_domain_unlock (domain);
1692 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1695 * mono_class_vtable:
1696 * @domain: the application domain
1697 * @class: the class to initialize
1699 * VTables are domain specific because we create domain specific code, and
1700 * they contain the domain specific static class data.
1701 * On failure, NULL is returned, and class->exception_type is set.
1704 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1706 return mono_class_vtable_full (domain, class, FALSE);
1710 * mono_class_vtable_full:
1711 * @domain: the application domain
1712 * @class: the class to initialize
1713 * @raise_on_error if an exception should be raised on failure or not
1715 * VTables are domain specific because we create domain specific code, and
1716 * they contain the domain specific static class data.
1719 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1721 MonoClassRuntimeInfo *runtime_info;
1725 if (class->exception_type) {
1727 mono_raise_exception (mono_class_get_exception_for_failure (class));
1731 /* this check can be inlined in jitted code, too */
1732 runtime_info = class->runtime_info;
1733 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1734 return runtime_info->domain_vtables [domain->domain_id];
1735 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1739 * mono_class_try_get_vtable:
1740 * @domain: the application domain
1741 * @class: the class to initialize
1743 * This function tries to get the associated vtable from @class if
1744 * it was already created.
1747 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1749 MonoClassRuntimeInfo *runtime_info;
1753 runtime_info = class->runtime_info;
1754 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1755 return runtime_info->domain_vtables [domain->domain_id];
1760 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1763 MonoClassRuntimeInfo *runtime_info, *old_info;
1764 MonoClassField *field;
1767 int imt_table_bytes = 0;
1768 guint32 vtable_size, class_size;
1771 gpointer *interface_offsets;
1773 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1774 mono_domain_lock (domain);
1775 runtime_info = class->runtime_info;
1776 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1777 mono_domain_unlock (domain);
1778 mono_loader_unlock ();
1779 return runtime_info->domain_vtables [domain->domain_id];
1781 if (!class->inited || class->exception_type) {
1782 if (!mono_class_init (class) || class->exception_type) {
1783 mono_domain_unlock (domain);
1784 mono_loader_unlock ();
1786 mono_raise_exception (mono_class_get_exception_for_failure (class));
1791 /* Array types require that their element type be valid*/
1792 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1793 MonoClass *element_class = class->element_class;
1794 if (!element_class->inited)
1795 mono_class_init (element_class);
1797 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1798 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1799 mono_class_setup_vtable (element_class);
1801 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1802 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1803 if (class->exception_type == MONO_EXCEPTION_NONE)
1804 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1805 mono_domain_unlock (domain);
1806 mono_loader_unlock ();
1808 mono_raise_exception (mono_class_get_exception_for_failure (class));
1814 * For some classes, mono_class_init () already computed class->vtable_size, and
1815 * that is all that is needed because of the vtable trampolines.
1817 if (!class->vtable_size)
1818 mono_class_setup_vtable (class);
1820 if (class->exception_type) {
1821 mono_domain_unlock (domain);
1822 mono_loader_unlock ();
1824 mono_raise_exception (mono_class_get_exception_for_failure (class));
1829 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1830 if (class->interface_offsets_count) {
1831 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1832 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1833 mono_stats.imt_number_of_tables++;
1834 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1837 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1838 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1841 mono_stats.used_class_count++;
1842 mono_stats.class_vtable_size += vtable_size;
1843 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1846 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1848 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1850 vt->rank = class->rank;
1851 vt->domain = domain;
1853 mono_class_compute_gc_descriptor (class);
1855 * We can't use typed allocation in the non-root domains, since the
1856 * collector needs the GC descriptor stored in the vtable even after
1857 * the mempool containing the vtable is destroyed when the domain is
1858 * unloaded. An alternative might be to allocate vtables in the GC
1859 * heap, but this does not seem to work (it leads to crashes inside
1860 * libgc). If that approach is tried, two gc descriptors need to be
1861 * allocated for each class: one for the root domain, and one for all
1862 * other domains. The second descriptor should contain a bit for the
1863 * vtable field in MonoObject, since we can no longer assume the
1864 * vtable is reachable by other roots after the appdomain is unloaded.
1866 #ifdef HAVE_BOEHM_GC
1867 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1868 vt->gc_descr = GC_NO_DESCRIPTOR;
1871 vt->gc_descr = class->gc_descr;
1873 if ((class_size = mono_class_data_size (class))) {
1874 if (class->has_static_refs) {
1875 gpointer statics_gc_descr;
1877 gsize default_bitmap [4] = {0};
1880 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1881 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1882 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1883 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1884 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1885 if (bitmap != default_bitmap)
1888 vt->data = mono_domain_alloc0 (domain, class_size);
1890 mono_stats.class_static_data_size += class_size;
1895 while ((field = mono_class_get_fields (class, &iter))) {
1896 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1898 if (mono_field_is_deleted (field))
1900 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1901 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1902 if (special_static != SPECIAL_STATIC_NONE) {
1903 guint32 size, offset;
1905 size = mono_type_size (field->type, &align);
1906 offset = mono_alloc_special_static_data (special_static, size, align);
1907 if (!domain->special_static_fields)
1908 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1909 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1911 * This marks the field as special static to speed up the
1912 * checks in mono_field_static_get/set_value ().
1918 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1919 MonoClass *fklass = mono_class_from_mono_type (field->type);
1920 const char *data = mono_field_get_data (field);
1922 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1923 t = (char*)vt->data + field->offset;
1924 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1927 if (fklass->valuetype) {
1928 memcpy (t, data, mono_class_value_size (fklass, NULL));
1930 /* it's a pointer type: add check */
1931 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1938 vt->max_interface_id = class->max_interface_id;
1939 vt->interface_bitmap = class->interface_bitmap;
1941 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1942 // class->name, class->interface_offsets_count);
1944 if (! ARCH_USE_IMT) {
1945 /* initialize interface offsets */
1946 for (i = 0; i < class->interface_offsets_count; ++i) {
1947 int interface_id = class->interfaces_packed [i]->interface_id;
1948 int slot = class->interface_offsets_packed [i];
1949 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1953 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1954 * as we change the code in appdomain.c to invalidate vtables by
1955 * looking at the possible MonoClasses created for the domain.
1957 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1958 /* class->runtime_info is protected by the loader lock, both when
1959 * it it enlarged and when it is stored info.
1962 old_info = class->runtime_info;
1963 if (old_info && old_info->max_domain >= domain->domain_id) {
1964 /* someone already created a large enough runtime info */
1965 mono_memory_barrier ();
1966 old_info->domain_vtables [domain->domain_id] = vt;
1968 int new_size = domain->domain_id;
1970 new_size = MAX (new_size, old_info->max_domain);
1972 /* make the new size a power of two */
1974 while (new_size > i)
1977 /* this is a bounded memory retention issue: may want to
1978 * handle it differently when we'll have a rcu-like system.
1980 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1981 runtime_info->max_domain = new_size - 1;
1982 /* copy the stuff from the older info */
1984 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1986 runtime_info->domain_vtables [domain->domain_id] = vt;
1988 mono_memory_barrier ();
1989 class->runtime_info = runtime_info;
1992 /* Initialize vtable */
1993 if (vtable_trampoline) {
1994 // This also covers the AOT case
1995 for (i = 0; i < class->vtable_size; ++i) {
1996 vt->vtable [i] = vtable_trampoline;
1999 mono_class_setup_vtable (class);
2001 for (i = 0; i < class->vtable_size; ++i) {
2004 if ((cm = class->vtable [i]))
2005 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
2009 if (ARCH_USE_IMT && imt_table_bytes) {
2010 /* Now that the vtable is full, we can actually fill up the IMT */
2011 if (imt_trampoline) {
2012 /* lazy construction of the IMT entries enabled */
2013 for (i = 0; i < MONO_IMT_SIZE; ++i)
2014 interface_offsets [i] = imt_trampoline;
2016 build_imt (class, vt, domain, interface_offsets, NULL);
2020 mono_domain_unlock (domain);
2021 mono_loader_unlock ();
2023 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2024 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2025 mono_raise_exception (mono_class_get_exception_for_failure (class));
2027 /* make sure the parent is initialized */
2028 /*FIXME shouldn't this fail the current type?*/
2030 mono_class_vtable_full (domain, class->parent, raise_on_error);
2032 /*FIXME check for OOM*/
2033 vt->type = mono_type_get_object (domain, &class->byval_arg);
2034 if (class->contextbound)
2043 * mono_class_proxy_vtable:
2044 * @domain: the application domain
2045 * @remove_class: the remote class
2047 * Creates a vtable for transparent proxies. It is basically
2048 * a copy of the real vtable of the class wrapped in @remote_class,
2049 * but all function pointers invoke the remoting functions, and
2050 * vtable->klass points to the transparent proxy class, and not to @class.
2053 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2056 MonoVTable *vt, *pvt;
2057 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2059 GSList *extra_interfaces = NULL;
2060 MonoClass *class = remote_class->proxy_class;
2061 gpointer *interface_offsets;
2063 vt = mono_class_vtable (domain, class);
2064 g_assert (vt); /*FIXME property handle failure*/
2065 max_interface_id = vt->max_interface_id;
2067 /* Calculate vtable space for extra interfaces */
2068 for (j = 0; j < remote_class->interface_count; j++) {
2069 MonoClass* iclass = remote_class->interfaces[j];
2073 /*FIXME test for interfaces with variant generic arguments*/
2074 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2075 continue; /* interface implemented by the class */
2076 if (g_slist_find (extra_interfaces, iclass))
2079 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2081 method_count = mono_class_num_methods (iclass);
2083 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2084 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2086 for (i = 0; i < ifaces->len; ++i) {
2087 MonoClass *ic = g_ptr_array_index (ifaces, i);
2088 /*FIXME test for interfaces with variant generic arguments*/
2089 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2090 continue; /* interface implemented by the class */
2091 if (g_slist_find (extra_interfaces, ic))
2093 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2094 method_count += mono_class_num_methods (ic);
2096 g_ptr_array_free (ifaces, TRUE);
2099 extra_interface_vtsize += method_count * sizeof (gpointer);
2100 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2104 mono_stats.imt_number_of_tables++;
2105 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2106 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2107 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2109 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2110 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2113 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2115 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2117 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2119 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2120 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2122 pvt->klass = mono_defaults.transparent_proxy_class;
2123 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2124 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2126 /* initialize vtable */
2127 mono_class_setup_vtable (class);
2128 for (i = 0; i < class->vtable_size; ++i) {
2131 if ((cm = class->vtable [i]))
2132 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2134 pvt->vtable [i] = NULL;
2137 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2138 /* create trampolines for abstract methods */
2139 for (k = class; k; k = k->parent) {
2141 gpointer iter = NULL;
2142 while ((m = mono_class_get_methods (k, &iter)))
2143 if (!pvt->vtable [m->slot])
2144 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2148 pvt->max_interface_id = max_interface_id;
2149 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2151 if (! ARCH_USE_IMT) {
2152 /* initialize interface offsets */
2153 for (i = 0; i < class->interface_offsets_count; ++i) {
2154 int interface_id = class->interfaces_packed [i]->interface_id;
2155 int slot = class->interface_offsets_packed [i];
2156 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2159 for (i = 0; i < class->interface_offsets_count; ++i) {
2160 int interface_id = class->interfaces_packed [i]->interface_id;
2161 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2164 if (extra_interfaces) {
2165 int slot = class->vtable_size;
2171 /* Create trampolines for the methods of the interfaces */
2172 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2173 interf = list_item->data;
2175 if (! ARCH_USE_IMT) {
2176 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2178 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2182 while ((cm = mono_class_get_methods (interf, &iter)))
2183 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2185 slot += mono_class_num_methods (interf);
2187 if (! ARCH_USE_IMT) {
2188 g_slist_free (extra_interfaces);
2193 /* Now that the vtable is full, we can actually fill up the IMT */
2194 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2195 if (extra_interfaces) {
2196 g_slist_free (extra_interfaces);
2204 * mono_class_field_is_special_static:
2206 * Returns whether @field is a thread/context static field.
2209 mono_class_field_is_special_static (MonoClassField *field)
2211 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2213 if (mono_field_is_deleted (field))
2215 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2216 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2223 * mono_class_has_special_static_fields:
2225 * Returns whenever @klass has any thread/context static fields.
2228 mono_class_has_special_static_fields (MonoClass *klass)
2230 MonoClassField *field;
2234 while ((field = mono_class_get_fields (klass, &iter))) {
2235 g_assert (field->parent == klass);
2236 if (mono_class_field_is_special_static (field))
2244 * create_remote_class_key:
2245 * Creates an array of pointers that can be used as a hash key for a remote class.
2246 * The first element of the array is the number of pointers.
2249 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2254 if (remote_class == NULL) {
2255 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2256 key = g_malloc (sizeof(gpointer) * 3);
2257 key [0] = GINT_TO_POINTER (2);
2258 key [1] = mono_defaults.marshalbyrefobject_class;
2259 key [2] = extra_class;
2261 key = g_malloc (sizeof(gpointer) * 2);
2262 key [0] = GINT_TO_POINTER (1);
2263 key [1] = extra_class;
2266 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2267 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2268 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2269 key [1] = remote_class->proxy_class;
2271 // Keep the list of interfaces sorted
2272 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2273 if (extra_class && remote_class->interfaces [i] > extra_class) {
2274 key [j++] = extra_class;
2277 key [j] = remote_class->interfaces [i];
2280 key [j] = extra_class;
2282 // Replace the old class. The interface list is the same
2283 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2284 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2285 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2286 for (i = 0; i < remote_class->interface_count; i++)
2287 key [2 + i] = remote_class->interfaces [i];
2295 * copy_remote_class_key:
2297 * Make a copy of KEY in the domain and return the copy.
2300 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2302 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2303 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2305 memcpy (mp_key, key, key_size);
2311 * mono_remote_class:
2312 * @domain: the application domain
2313 * @class_name: name of the remote class
2315 * Creates and initializes a MonoRemoteClass object for a remote type.
2317 * Can raise an exception on failure.
2320 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2323 MonoRemoteClass *rc;
2324 gpointer* key, *mp_key;
2327 key = create_remote_class_key (NULL, proxy_class);
2329 mono_domain_lock (domain);
2330 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2334 mono_domain_unlock (domain);
2338 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2339 if (!mono_error_ok (&error)) {
2341 mono_domain_unlock (domain);
2342 mono_error_raise_exception (&error);
2345 mp_key = copy_remote_class_key (domain, key);
2349 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2350 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2351 rc->interface_count = 1;
2352 rc->interfaces [0] = proxy_class;
2353 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2355 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2356 rc->interface_count = 0;
2357 rc->proxy_class = proxy_class;
2360 rc->default_vtable = NULL;
2361 rc->xdomain_vtable = NULL;
2362 rc->proxy_class_name = name;
2363 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2365 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2367 mono_domain_unlock (domain);
2372 * clone_remote_class:
2373 * Creates a copy of the remote_class, adding the provided class or interface
2375 static MonoRemoteClass*
2376 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2378 MonoRemoteClass *rc;
2379 gpointer* key, *mp_key;
2381 key = create_remote_class_key (remote_class, extra_class);
2382 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2388 mp_key = copy_remote_class_key (domain, key);
2392 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2394 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2395 rc->proxy_class = remote_class->proxy_class;
2396 rc->interface_count = remote_class->interface_count + 1;
2398 // Keep the list of interfaces sorted, since the hash key of
2399 // the remote class depends on this
2400 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2401 if (remote_class->interfaces [i] > extra_class && i == j)
2402 rc->interfaces [j++] = extra_class;
2403 rc->interfaces [j] = remote_class->interfaces [i];
2406 rc->interfaces [j] = extra_class;
2408 // Replace the old class. The interface array is the same
2409 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2410 rc->proxy_class = extra_class;
2411 rc->interface_count = remote_class->interface_count;
2412 if (rc->interface_count > 0)
2413 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2416 rc->default_vtable = NULL;
2417 rc->xdomain_vtable = NULL;
2418 rc->proxy_class_name = remote_class->proxy_class_name;
2420 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2426 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2428 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2429 mono_domain_lock (domain);
2430 if (rp->target_domain_id != -1) {
2431 if (remote_class->xdomain_vtable == NULL)
2432 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2433 mono_domain_unlock (domain);
2434 mono_loader_unlock ();
2435 return remote_class->xdomain_vtable;
2437 if (remote_class->default_vtable == NULL) {
2440 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2441 klass = mono_class_from_mono_type (type);
2442 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2443 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2445 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2448 mono_domain_unlock (domain);
2449 mono_loader_unlock ();
2450 return remote_class->default_vtable;
2454 * mono_upgrade_remote_class:
2455 * @domain: the application domain
2456 * @tproxy: the proxy whose remote class has to be upgraded.
2457 * @klass: class to which the remote class can be casted.
2459 * Updates the vtable of the remote class by adding the necessary method slots
2460 * and interface offsets so it can be safely casted to klass. klass can be a
2461 * class or an interface.
2464 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2466 MonoTransparentProxy *tproxy;
2467 MonoRemoteClass *remote_class;
2468 gboolean redo_vtable;
2470 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2471 mono_domain_lock (domain);
2473 tproxy = (MonoTransparentProxy*) proxy_object;
2474 remote_class = tproxy->remote_class;
2476 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2479 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2480 if (remote_class->interfaces [i] == klass)
2481 redo_vtable = FALSE;
2484 redo_vtable = (remote_class->proxy_class != klass);
2488 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2489 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2492 mono_domain_unlock (domain);
2493 mono_loader_unlock ();
2498 * mono_object_get_virtual_method:
2499 * @obj: object to operate on.
2502 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2503 * the instance of a callvirt of method.
2506 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2509 MonoMethod **vtable;
2511 MonoMethod *res = NULL;
2513 klass = mono_object_class (obj);
2514 if (klass == mono_defaults.transparent_proxy_class) {
2515 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2521 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2524 mono_class_setup_vtable (klass);
2525 vtable = klass->vtable;
2527 if (method->slot == -1) {
2528 /* method->slot might not be set for instances of generic methods */
2529 if (method->is_inflated) {
2530 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2531 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2534 g_assert_not_reached ();
2538 /* check method->slot is a valid index: perform isinstance? */
2539 if (method->slot != -1) {
2540 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2542 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2544 res = vtable [method->slot];
2549 /* It may be an interface, abstract class method or generic method */
2550 if (!res || mono_method_signature (res)->generic_param_count)
2553 /* generic methods demand invoke_with_check */
2554 if (mono_method_signature (res)->generic_param_count)
2555 res = mono_marshal_get_remoting_invoke_with_check (res);
2558 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2559 res = mono_cominterop_get_invoke (res);
2562 res = mono_marshal_get_remoting_invoke (res);
2565 if (method->is_inflated) {
2566 /* Have to inflate the result */
2567 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2577 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2579 g_error ("runtime invoke called on uninitialized runtime");
2583 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2586 * mono_runtime_invoke:
2587 * @method: method to invoke
2588 * @obJ: object instance
2589 * @params: arguments to the method
2590 * @exc: exception information.
2592 * Invokes the method represented by @method on the object @obj.
2594 * obj is the 'this' pointer, it should be NULL for static
2595 * methods, a MonoObject* for object instances and a pointer to
2596 * the value type for value types.
2598 * The params array contains the arguments to the method with the
2599 * same convention: MonoObject* pointers for object instances and
2600 * pointers to the value type otherwise.
2602 * From unmanaged code you'll usually use the
2603 * mono_runtime_invoke() variant.
2605 * Note that this function doesn't handle virtual methods for
2606 * you, it will exec the exact method you pass: we still need to
2607 * expose a function to lookup the derived class implementation
2608 * of a virtual method (there are examples of this in the code,
2611 * You can pass NULL as the exc argument if you don't want to
2612 * catch exceptions, otherwise, *exc will be set to the exception
2613 * thrown, if any. if an exception is thrown, you can't use the
2614 * MonoObject* result from the function.
2616 * If the method returns a value type, it is boxed in an object
2620 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2624 if (mono_runtime_get_no_exec ())
2625 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2627 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2628 mono_profiler_method_start_invoke (method);
2630 result = default_mono_runtime_invoke (method, obj, params, exc);
2632 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2633 mono_profiler_method_end_invoke (method);
2639 * mono_method_get_unmanaged_thunk:
2640 * @method: method to generate a thunk for.
2642 * Returns an unmanaged->managed thunk that can be used to call
2643 * a managed method directly from C.
2645 * The thunk's C signature closely matches the managed signature:
2647 * C#: public bool Equals (object obj);
2648 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2649 * MonoObject*, MonoException**);
2651 * The 1st ("this") parameter must not be used with static methods:
2653 * C#: public static bool ReferenceEquals (object a, object b);
2654 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2657 * The last argument must be a non-null pointer of a MonoException* pointer.
2658 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2659 * exception has been thrown in managed code. Otherwise it will point
2660 * to the MonoException* caught by the thunk. In this case, the result of
2661 * the thunk is undefined:
2663 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2664 * MonoException *ex = NULL;
2665 * Equals func = mono_method_get_unmanaged_thunk (method);
2666 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2668 * // handle exception
2671 * The calling convention of the thunk matches the platform's default
2672 * convention. This means that under Windows, C declarations must
2673 * contain the __stdcall attribute:
2675 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2676 * MonoObject*, MonoException**);
2680 * Value type arguments and return values are treated as they were objects:
2682 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2683 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2685 * Arguments must be properly boxed upon trunk's invocation, while return
2686 * values must be unboxed.
2689 mono_method_get_unmanaged_thunk (MonoMethod *method)
2691 method = mono_marshal_get_thunk_invoke_wrapper (method);
2692 return mono_compile_method (method);
2696 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2700 /* object fields cannot be byref, so we don't need a
2702 gpointer *p = (gpointer*)dest;
2709 case MONO_TYPE_BOOLEAN:
2711 case MONO_TYPE_U1: {
2712 guint8 *p = (guint8*)dest;
2713 *p = value ? *(guint8*)value : 0;
2718 case MONO_TYPE_CHAR: {
2719 guint16 *p = (guint16*)dest;
2720 *p = value ? *(guint16*)value : 0;
2723 #if SIZEOF_VOID_P == 4
2728 case MONO_TYPE_U4: {
2729 gint32 *p = (gint32*)dest;
2730 *p = value ? *(gint32*)value : 0;
2733 #if SIZEOF_VOID_P == 8
2738 case MONO_TYPE_U8: {
2739 gint64 *p = (gint64*)dest;
2740 *p = value ? *(gint64*)value : 0;
2743 case MONO_TYPE_R4: {
2744 float *p = (float*)dest;
2745 *p = value ? *(float*)value : 0;
2748 case MONO_TYPE_R8: {
2749 double *p = (double*)dest;
2750 *p = value ? *(double*)value : 0;
2753 case MONO_TYPE_STRING:
2754 case MONO_TYPE_SZARRAY:
2755 case MONO_TYPE_CLASS:
2756 case MONO_TYPE_OBJECT:
2757 case MONO_TYPE_ARRAY:
2758 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2760 case MONO_TYPE_FNPTR:
2761 case MONO_TYPE_PTR: {
2762 gpointer *p = (gpointer*)dest;
2763 *p = deref_pointer? *(gpointer*)value: value;
2766 case MONO_TYPE_VALUETYPE:
2767 /* note that 't' and 'type->type' can be different */
2768 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2769 t = mono_class_enum_basetype (type->data.klass)->type;
2772 MonoClass *class = mono_class_from_mono_type (type);
2773 int size = mono_class_value_size (class, NULL);
2775 memset (dest, 0, size);
2777 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2780 case MONO_TYPE_GENERICINST:
2781 t = type->data.generic_class->container_class->byval_arg.type;
2784 g_warning ("got type %x", type->type);
2785 g_assert_not_reached ();
2790 * mono_field_set_value:
2791 * @obj: Instance object
2792 * @field: MonoClassField describing the field to set
2793 * @value: The value to be set
2795 * Sets the value of the field described by @field in the object instance @obj
2796 * to the value passed in @value. This method should only be used for instance
2797 * fields. For static fields, use mono_field_static_set_value.
2799 * The value must be on the native format of the field type.
2802 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2806 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2808 dest = (char*)obj + field->offset;
2809 set_value (field->type, dest, value, FALSE);
2813 * mono_field_static_set_value:
2814 * @field: MonoClassField describing the field to set
2815 * @value: The value to be set
2817 * Sets the value of the static field described by @field
2818 * to the value passed in @value.
2820 * The value must be on the native format of the field type.
2823 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2827 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2828 /* you cant set a constant! */
2829 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2831 if (field->offset == -1) {
2832 /* Special static */
2833 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2834 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2836 dest = (char*)vt->data + field->offset;
2838 set_value (field->type, dest, value, FALSE);
2841 /* Used by the debugger */
2843 mono_vtable_get_static_field_data (MonoVTable *vt)
2849 * mono_field_get_value:
2850 * @obj: Object instance
2851 * @field: MonoClassField describing the field to fetch information from
2852 * @value: pointer to the location where the value will be stored
2854 * Use this routine to get the value of the field @field in the object
2857 * The pointer provided by value must be of the field type, for reference
2858 * types this is a MonoObject*, for value types its the actual pointer to
2863 * mono_field_get_value (obj, int_field, &i);
2866 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2870 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2872 src = (char*)obj + field->offset;
2873 set_value (field->type, value, src, TRUE);
2877 * mono_field_get_value_object:
2878 * @domain: domain where the object will be created (if boxing)
2879 * @field: MonoClassField describing the field to fetch information from
2880 * @obj: The object instance for the field.
2882 * Returns: a new MonoObject with the value from the given field. If the
2883 * field represents a value type, the value is boxed.
2887 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2891 MonoVTable *vtable = NULL;
2893 gboolean is_static = FALSE;
2894 gboolean is_ref = FALSE;
2896 switch (field->type->type) {
2897 case MONO_TYPE_STRING:
2898 case MONO_TYPE_OBJECT:
2899 case MONO_TYPE_CLASS:
2900 case MONO_TYPE_ARRAY:
2901 case MONO_TYPE_SZARRAY:
2906 case MONO_TYPE_BOOLEAN:
2909 case MONO_TYPE_CHAR:
2918 case MONO_TYPE_VALUETYPE:
2919 is_ref = field->type->byref;
2921 case MONO_TYPE_GENERICINST:
2922 is_ref = !field->type->data.generic_class->container_class->valuetype;
2925 g_error ("type 0x%x not handled in "
2926 "mono_field_get_value_object", field->type->type);
2930 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2932 vtable = mono_class_vtable (domain, field->parent);
2934 char *name = mono_type_get_full_name (field->parent);
2935 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2939 if (!vtable->initialized)
2940 mono_runtime_class_init (vtable);
2945 mono_field_static_get_value (vtable, field, &o);
2947 mono_field_get_value (obj, field, &o);
2952 /* boxed value type */
2953 klass = mono_class_from_mono_type (field->type);
2954 o = mono_object_new (domain, klass);
2955 v = ((gchar *) o) + sizeof (MonoObject);
2957 mono_field_static_get_value (vtable, field, v);
2959 mono_field_get_value (obj, field, v);
2966 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2969 const char *p = blob;
2970 mono_metadata_decode_blob_size (p, &p);
2973 case MONO_TYPE_BOOLEAN:
2976 *(guint8 *) value = *p;
2978 case MONO_TYPE_CHAR:
2981 *(guint16*) value = read16 (p);
2985 *(guint32*) value = read32 (p);
2989 *(guint64*) value = read64 (p);
2992 readr4 (p, (float*) value);
2995 readr8 (p, (double*) value);
2997 case MONO_TYPE_STRING:
2998 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3000 case MONO_TYPE_CLASS:
3001 *(gpointer*) value = NULL;
3005 g_warning ("type 0x%02x should not be in constant table", type);
3011 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3013 MonoTypeEnum def_type;
3016 data = mono_class_get_field_default_value (field, &def_type);
3017 mono_get_constant_value_from_blob (domain, def_type, data, value);
3021 * mono_field_static_get_value:
3022 * @vt: vtable to the object
3023 * @field: MonoClassField describing the field to fetch information from
3024 * @value: where the value is returned
3026 * Use this routine to get the value of the static field @field value.
3028 * The pointer provided by value must be of the field type, for reference
3029 * types this is a MonoObject*, for value types its the actual pointer to
3034 * mono_field_static_get_value (vt, int_field, &i);
3037 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3041 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3043 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3044 get_default_field_value (vt->domain, field, value);
3048 if (field->offset == -1) {
3049 /* Special static */
3050 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3051 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3053 src = (char*)vt->data + field->offset;
3055 set_value (field->type, value, src, TRUE);
3059 * mono_property_set_value:
3060 * @prop: MonoProperty to set
3061 * @obj: instance object on which to act
3062 * @params: parameters to pass to the propery
3063 * @exc: optional exception
3065 * Invokes the property's set method with the given arguments on the
3066 * object instance obj (or NULL for static properties).
3068 * You can pass NULL as the exc argument if you don't want to
3069 * catch exceptions, otherwise, *exc will be set to the exception
3070 * thrown, if any. if an exception is thrown, you can't use the
3071 * MonoObject* result from the function.
3074 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3076 default_mono_runtime_invoke (prop->set, obj, params, exc);
3080 * mono_property_get_value:
3081 * @prop: MonoProperty to fetch
3082 * @obj: instance object on which to act
3083 * @params: parameters to pass to the propery
3084 * @exc: optional exception
3086 * Invokes the property's get method with the given arguments on the
3087 * object instance obj (or NULL for static properties).
3089 * You can pass NULL as the exc argument if you don't want to
3090 * catch exceptions, otherwise, *exc will be set to the exception
3091 * thrown, if any. if an exception is thrown, you can't use the
3092 * MonoObject* result from the function.
3094 * Returns: the value from invoking the get method on the property.
3097 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3099 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3103 * mono_nullable_init:
3104 * @buf: The nullable structure to initialize.
3105 * @value: the value to initialize from
3106 * @klass: the type for the object
3108 * Initialize the nullable structure pointed to by @buf from @value which
3109 * should be a boxed value type. The size of @buf should be able to hold
3110 * as much data as the @klass->instance_size (which is the number of bytes
3111 * that will be copies).
3113 * Since Nullables have variable structure, we can not define a C
3114 * structure for them.
3117 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3119 MonoClass *param_class = klass->cast_class;
3121 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3122 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3124 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3126 if (param_class->has_references)
3127 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3129 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3131 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3136 * mono_nullable_box:
3137 * @buf: The buffer representing the data to be boxed
3138 * @klass: the type to box it as.
3140 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3144 mono_nullable_box (guint8 *buf, MonoClass *klass)
3146 MonoClass *param_class = klass->cast_class;
3148 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3149 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3151 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3152 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3153 if (param_class->has_references)
3154 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3156 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3164 * mono_get_delegate_invoke:
3165 * @klass: The delegate class
3167 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3170 mono_get_delegate_invoke (MonoClass *klass)
3174 /* This is called at runtime, so avoid the slower search in metadata */
3175 mono_class_setup_methods (klass);
3176 if (klass->exception_type)
3178 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3185 * mono_runtime_delegate_invoke:
3186 * @delegate: pointer to a delegate object.
3187 * @params: parameters for the delegate.
3188 * @exc: Pointer to the exception result.
3190 * Invokes the delegate method @delegate with the parameters provided.
3192 * You can pass NULL as the exc argument if you don't want to
3193 * catch exceptions, otherwise, *exc will be set to the exception
3194 * thrown, if any. if an exception is thrown, you can't use the
3195 * MonoObject* result from the function.
3198 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3202 im = mono_get_delegate_invoke (delegate->vtable->klass);
3205 return mono_runtime_invoke (im, delegate, params, exc);
3208 static char **main_args = NULL;
3209 static int num_main_args;
3212 * mono_runtime_get_main_args:
3214 * Returns: a MonoArray with the arguments passed to the main program
3217 mono_runtime_get_main_args (void)
3221 MonoDomain *domain = mono_domain_get ();
3226 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3228 for (i = 0; i < num_main_args; ++i)
3229 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3235 fire_process_exit_event (void)
3237 MonoClassField *field;
3238 MonoDomain *domain = mono_domain_get ();
3240 MonoObject *delegate, *exc;
3242 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3245 if (domain != mono_get_root_domain ())
3248 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3249 if (delegate == NULL)
3254 mono_runtime_delegate_invoke (delegate, pa, &exc);
3258 * mono_runtime_run_main:
3259 * @method: the method to start the application with (usually Main)
3260 * @argc: number of arguments from the command line
3261 * @argv: array of strings from the command line
3262 * @exc: excetption results
3264 * Execute a standard Main() method (argc/argv contains the
3265 * executable name). This method also sets the command line argument value
3266 * needed by System.Environment.
3271 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3275 MonoArray *args = NULL;
3276 MonoDomain *domain = mono_domain_get ();
3277 gchar *utf8_fullpath;
3280 g_assert (method != NULL);
3282 mono_thread_set_main (mono_thread_current ());
3284 main_args = g_new0 (char*, argc);
3285 num_main_args = argc;
3287 if (!g_path_is_absolute (argv [0])) {
3288 gchar *basename = g_path_get_basename (argv [0]);
3289 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3293 utf8_fullpath = mono_utf8_from_external (fullpath);
3294 if(utf8_fullpath == NULL) {
3295 /* Printing the arg text will cause glib to
3296 * whinge about "Invalid UTF-8", but at least
3297 * its relevant, and shows the problem text
3300 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3301 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3308 utf8_fullpath = mono_utf8_from_external (argv[0]);
3309 if(utf8_fullpath == NULL) {
3310 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3311 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3316 main_args [0] = utf8_fullpath;
3318 for (i = 1; i < argc; ++i) {
3321 utf8_arg=mono_utf8_from_external (argv[i]);
3322 if(utf8_arg==NULL) {
3323 /* Ditto the comment about Invalid UTF-8 here */
3324 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3325 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3329 main_args [i] = utf8_arg;
3333 if (mono_method_signature (method)->param_count) {
3334 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3335 for (i = 0; i < argc; ++i) {
3336 /* The encodings should all work, given that
3337 * we've checked all these args for the
3340 gchar *str = mono_utf8_from_external (argv [i]);
3341 MonoString *arg = mono_string_new (domain, str);
3342 mono_array_setref (args, i, arg);
3346 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3349 mono_assembly_set_main (method->klass->image->assembly);
3351 result = mono_runtime_exec_main (method, args, exc);
3352 fire_process_exit_event ();
3357 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3359 static MonoMethod *serialize_method;
3364 if (!serialize_method) {
3365 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3366 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3369 if (!serialize_method) {
3374 g_assert (!mono_object_class (obj)->marshalbyref);
3378 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3386 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3388 static MonoMethod *deserialize_method;
3393 if (!deserialize_method) {
3394 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3395 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3397 if (!deserialize_method) {
3404 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3412 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3414 static MonoMethod *get_proxy_method;
3416 MonoDomain *domain = mono_domain_get ();
3417 MonoRealProxy *real_proxy;
3418 MonoReflectionType *reflection_type;
3419 MonoTransparentProxy *transparent_proxy;
3421 if (!get_proxy_method)
3422 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3424 g_assert (obj->vtable->klass->marshalbyref);
3426 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3427 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3429 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3430 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3433 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3437 return (MonoObject*) transparent_proxy;
3441 * mono_object_xdomain_representation
3443 * @target_domain: a domain
3444 * @exc: pointer to a MonoObject*
3446 * Creates a representation of obj in the domain target_domain. This
3447 * is either a copy of obj arrived through via serialization and
3448 * deserialization or a proxy, depending on whether the object is
3449 * serializable or marshal by ref. obj must not be in target_domain.
3451 * If the object cannot be represented in target_domain, NULL is
3452 * returned and *exc is set to an appropriate exception.
3455 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3457 MonoObject *deserialized = NULL;
3458 gboolean failure = FALSE;
3462 if (mono_object_class (obj)->marshalbyref) {
3463 deserialized = make_transparent_proxy (obj, &failure, exc);
3465 MonoDomain *domain = mono_domain_get ();
3466 MonoObject *serialized;
3468 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3469 serialized = serialize_object (obj, &failure, exc);
3470 mono_domain_set_internal_with_options (target_domain, FALSE);
3472 deserialized = deserialize_object (serialized, &failure, exc);
3473 if (domain != target_domain)
3474 mono_domain_set_internal_with_options (domain, FALSE);
3477 return deserialized;
3480 /* Used in call_unhandled_exception_delegate */
3482 create_unhandled_exception_eventargs (MonoObject *exc)
3486 MonoMethod *method = NULL;
3487 MonoBoolean is_terminating = TRUE;
3490 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3493 mono_class_init (klass);
3495 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3496 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3500 args [1] = &is_terminating;
3502 obj = mono_object_new (mono_domain_get (), klass);
3503 mono_runtime_invoke (method, obj, args, NULL);
3508 /* Used in mono_unhandled_exception */
3510 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3511 MonoObject *e = NULL;
3513 MonoDomain *current_domain = mono_domain_get ();
3515 if (domain != current_domain)
3516 mono_domain_set_internal_with_options (domain, FALSE);
3518 g_assert (domain == mono_object_domain (domain->domain));
3520 if (mono_object_domain (exc) != domain) {
3521 MonoObject *serialization_exc;
3523 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3525 if (serialization_exc) {
3527 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3530 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3531 "System.Runtime.Serialization", "SerializationException",
3532 "Could not serialize unhandled exception.");
3536 g_assert (mono_object_domain (exc) == domain);
3538 pa [0] = domain->domain;
3539 pa [1] = create_unhandled_exception_eventargs (exc);
3540 mono_runtime_delegate_invoke (delegate, pa, &e);
3542 if (domain != current_domain)
3543 mono_domain_set_internal_with_options (current_domain, FALSE);
3547 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3548 if (!mono_error_ok (&error)) {
3549 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3550 mono_error_cleanup (&error);
3552 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3558 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3561 * mono_runtime_unhandled_exception_policy_set:
3562 * @policy: the new policy
3564 * This is a VM internal routine.
3566 * Sets the runtime policy for handling unhandled exceptions.
3569 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3570 runtime_unhandled_exception_policy = policy;
3574 * mono_runtime_unhandled_exception_policy_get:
3576 * This is a VM internal routine.
3578 * Gets the runtime policy for handling unhandled exceptions.
3580 MonoRuntimeUnhandledExceptionPolicy
3581 mono_runtime_unhandled_exception_policy_get (void) {
3582 return runtime_unhandled_exception_policy;
3586 * mono_unhandled_exception:
3587 * @exc: exception thrown
3589 * This is a VM internal routine.
3591 * We call this function when we detect an unhandled exception
3592 * in the default domain.
3594 * It invokes the * UnhandledException event in AppDomain or prints
3595 * a warning to the console
3598 mono_unhandled_exception (MonoObject *exc)
3600 MonoDomain *current_domain = mono_domain_get ();
3601 MonoDomain *root_domain = mono_get_root_domain ();
3602 MonoClassField *field;
3603 MonoObject *current_appdomain_delegate;
3604 MonoObject *root_appdomain_delegate;
3606 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3607 "UnhandledException");
3610 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3611 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3612 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3613 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3614 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3615 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3617 current_appdomain_delegate = NULL;
3620 /* set exitcode only if we will abort the process */
3622 mono_environment_exitcode_set (1);
3623 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3624 mono_print_unhandled_exception (exc);
3626 if (root_appdomain_delegate) {
3627 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3629 if (current_appdomain_delegate) {
3630 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3637 * Launch a new thread to execute a function
3639 * main_func is called back from the thread with main_args as the
3640 * parameter. The callback function is expected to start Main()
3641 * eventually. This function then waits for all managed threads to
3643 * It is not necesseray anymore to execute managed code in a subthread,
3644 * so this function should not be used anymore by default: just
3645 * execute the code and then call mono_thread_manage ().
3648 mono_runtime_exec_managed_code (MonoDomain *domain,
3649 MonoMainThreadFunc main_func,
3652 mono_thread_create (domain, main_func, main_args);
3654 mono_thread_manage ();
3658 * Execute a standard Main() method (args doesn't contain the
3662 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3667 MonoCustomAttrInfo* cinfo;
3668 gboolean has_stathread_attribute;
3669 MonoInternalThread* thread = mono_thread_internal_current ();
3675 domain = mono_object_domain (args);
3676 if (!domain->entry_assembly) {
3678 MonoAssembly *assembly;
3680 assembly = method->klass->image->assembly;
3681 domain->entry_assembly = assembly;
3682 /* Domains created from another domain already have application_base and configuration_file set */
3683 if (domain->setup->application_base == NULL) {
3684 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3687 if (domain->setup->configuration_file == NULL) {
3688 str = g_strconcat (assembly->image->name, ".config", NULL);
3689 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3691 mono_set_private_bin_path_from_config (domain);
3695 cinfo = mono_custom_attrs_from_method (method);
3697 static MonoClass *stathread_attribute = NULL;
3698 if (!stathread_attribute)
3699 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3700 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3702 mono_custom_attrs_free (cinfo);
3704 has_stathread_attribute = FALSE;
3706 if (has_stathread_attribute) {
3707 thread->apartment_state = ThreadApartmentState_STA;
3708 } else if (mono_framework_version () == 1) {
3709 thread->apartment_state = ThreadApartmentState_Unknown;
3711 thread->apartment_state = ThreadApartmentState_MTA;
3713 mono_thread_init_apartment_state ();
3715 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3717 /* FIXME: check signature of method */
3718 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3720 res = mono_runtime_invoke (method, NULL, pa, exc);
3722 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3726 mono_environment_exitcode_set (rval);
3728 mono_runtime_invoke (method, NULL, pa, exc);
3732 /* If the return type of Main is void, only
3733 * set the exitcode if an exception was thrown
3734 * (we don't want to blow away an
3735 * explicitly-set exit code)
3738 mono_environment_exitcode_set (rval);
3742 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3748 * mono_install_runtime_invoke:
3749 * @func: Function to install
3751 * This is a VM internal routine
3754 mono_install_runtime_invoke (MonoInvokeFunc func)
3756 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3761 * mono_runtime_invoke_array:
3762 * @method: method to invoke
3763 * @obJ: object instance
3764 * @params: arguments to the method
3765 * @exc: exception information.
3767 * Invokes the method represented by @method on the object @obj.
3769 * obj is the 'this' pointer, it should be NULL for static
3770 * methods, a MonoObject* for object instances and a pointer to
3771 * the value type for value types.
3773 * The params array contains the arguments to the method with the
3774 * same convention: MonoObject* pointers for object instances and
3775 * pointers to the value type otherwise. The _invoke_array
3776 * variant takes a C# object[] as the params argument (MonoArray
3777 * *params): in this case the value types are boxed inside the
3778 * respective reference representation.
3780 * From unmanaged code you'll usually use the
3781 * mono_runtime_invoke() variant.
3783 * Note that this function doesn't handle virtual methods for
3784 * you, it will exec the exact method you pass: we still need to
3785 * expose a function to lookup the derived class implementation
3786 * of a virtual method (there are examples of this in the code,
3789 * You can pass NULL as the exc argument if you don't want to
3790 * catch exceptions, otherwise, *exc will be set to the exception
3791 * thrown, if any. if an exception is thrown, you can't use the
3792 * MonoObject* result from the function.
3794 * If the method returns a value type, it is boxed in an object
3798 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3801 MonoMethodSignature *sig = mono_method_signature (method);
3802 gpointer *pa = NULL;
3805 gboolean has_byref_nullables = FALSE;
3807 if (NULL != params) {
3808 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3809 for (i = 0; i < mono_array_length (params); i++) {
3810 MonoType *t = sig->params [i];
3816 case MONO_TYPE_BOOLEAN:
3819 case MONO_TYPE_CHAR:
3828 case MONO_TYPE_VALUETYPE:
3829 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3830 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3831 pa [i] = mono_array_get (params, MonoObject*, i);
3833 has_byref_nullables = TRUE;
3835 /* MS seems to create the objects if a null is passed in */
3836 if (!mono_array_get (params, MonoObject*, i))
3837 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3841 * We can't pass the unboxed vtype byref to the callee, since
3842 * that would mean the callee would be able to modify boxed
3843 * primitive types. So we (and MS) make a copy of the boxed
3844 * object, pass that to the callee, and replace the original
3845 * boxed object in the arg array with the copy.
3847 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3848 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3849 mono_array_setref (params, i, copy);
3852 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3855 case MONO_TYPE_STRING:
3856 case MONO_TYPE_OBJECT:
3857 case MONO_TYPE_CLASS:
3858 case MONO_TYPE_ARRAY:
3859 case MONO_TYPE_SZARRAY:
3861 pa [i] = mono_array_addr (params, MonoObject*, i);
3862 // FIXME: I need to check this code path
3864 pa [i] = mono_array_get (params, MonoObject*, i);
3866 case MONO_TYPE_GENERICINST:
3868 t = &t->data.generic_class->container_class->this_arg;
3870 t = &t->data.generic_class->container_class->byval_arg;
3872 case MONO_TYPE_PTR: {
3875 /* The argument should be an IntPtr */
3876 arg = mono_array_get (params, MonoObject*, i);
3880 g_assert (arg->vtable->klass == mono_defaults.int_class);
3881 pa [i] = ((MonoIntPtr*)arg)->m_value;
3886 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3891 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3894 if (mono_class_is_nullable (method->klass)) {
3895 /* Need to create a boxed vtype instead */
3901 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3905 obj = mono_object_new (mono_domain_get (), method->klass);
3906 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3907 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3909 if (method->klass->valuetype)
3910 o = mono_object_unbox (obj);
3913 } else if (method->klass->valuetype) {
3914 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3917 mono_runtime_invoke (method, o, pa, exc);
3920 if (mono_class_is_nullable (method->klass)) {
3921 MonoObject *nullable;
3923 /* Convert the unboxed vtype into a Nullable structure */
3924 nullable = mono_object_new (mono_domain_get (), method->klass);
3926 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3927 obj = mono_object_unbox (nullable);
3930 /* obj must be already unboxed if needed */
3931 res = mono_runtime_invoke (method, obj, pa, exc);
3933 if (sig->ret->type == MONO_TYPE_PTR) {
3934 MonoClass *pointer_class;
3935 static MonoMethod *box_method;
3937 MonoObject *box_exc;
3940 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3941 * convert it to a Pointer object.
3943 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3945 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3947 g_assert (res->vtable->klass == mono_defaults.int_class);
3948 box_args [0] = ((MonoIntPtr*)res)->m_value;
3949 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3950 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3951 g_assert (!box_exc);
3954 if (has_byref_nullables) {
3956 * The runtime invoke wrapper already converted byref nullables back,
3957 * and stored them in pa, we just need to copy them back to the
3960 for (i = 0; i < mono_array_length (params); i++) {
3961 MonoType *t = sig->params [i];
3963 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3964 mono_array_setref (params, i, pa [i]);
3973 arith_overflow (void)
3975 mono_raise_exception (mono_get_exception_overflow ());
3979 * mono_object_allocate:
3980 * @size: number of bytes to allocate
3982 * This is a very simplistic routine until we have our GC-aware
3985 * Returns: an allocated object of size @size, or NULL on failure.
3987 static inline void *
3988 mono_object_allocate (size_t size, MonoVTable *vtable)
3991 mono_stats.new_object_count++;
3992 ALLOC_OBJECT (o, vtable, size);
3998 * mono_object_allocate_ptrfree:
3999 * @size: number of bytes to allocate
4001 * Note that the memory allocated is not zeroed.
4002 * Returns: an allocated object of size @size, or NULL on failure.
4004 static inline void *
4005 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4008 mono_stats.new_object_count++;
4009 ALLOC_PTRFREE (o, vtable, size);
4013 static inline void *
4014 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4017 ALLOC_TYPED (o, size, vtable);
4018 mono_stats.new_object_count++;
4025 * @klass: the class of the object that we want to create
4027 * Returns: a newly created object whose definition is
4028 * looked up using @klass. This will not invoke any constructors,
4029 * so the consumer of this routine has to invoke any constructors on
4030 * its own to initialize the object.
4032 * It returns NULL on failure.
4035 mono_object_new (MonoDomain *domain, MonoClass *klass)
4039 MONO_ARCH_SAVE_REGS;
4040 vtable = mono_class_vtable (domain, klass);
4043 return mono_object_new_specific (vtable);
4047 * mono_object_new_specific:
4048 * @vtable: the vtable of the object that we want to create
4050 * Returns: A newly created object with class and domain specified
4054 mono_object_new_specific (MonoVTable *vtable)
4058 MONO_ARCH_SAVE_REGS;
4060 /* check for is_com_object for COM Interop */
4061 if (vtable->remote || vtable->klass->is_com_object)
4064 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4067 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4070 mono_class_init (klass);
4072 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4074 vtable->domain->create_proxy_for_type_method = im;
4077 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4079 o = mono_runtime_invoke (im, NULL, pa, NULL);
4080 if (o != NULL) return o;
4083 return mono_object_new_alloc_specific (vtable);
4087 mono_object_new_alloc_specific (MonoVTable *vtable)
4091 if (!vtable->klass->has_references) {
4092 o = mono_object_new_ptrfree (vtable);
4093 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4094 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4096 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4097 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4099 if (G_UNLIKELY (vtable->klass->has_finalize))
4100 mono_object_register_finalizer (o);
4102 if (G_UNLIKELY (profile_allocs))
4103 mono_profiler_allocation (o, vtable->klass);
4108 mono_object_new_fast (MonoVTable *vtable)
4111 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4116 mono_object_new_ptrfree (MonoVTable *vtable)
4119 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4120 #if NEED_TO_ZERO_PTRFREE
4121 /* an inline memset is much faster for the common vcase of small objects
4122 * note we assume the allocated size is a multiple of sizeof (void*).
4124 if (vtable->klass->instance_size < 128) {
4126 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4127 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4133 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4140 mono_object_new_ptrfree_box (MonoVTable *vtable)
4143 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4144 /* the object will be boxed right away, no need to memzero it */
4149 * mono_class_get_allocation_ftn:
4151 * @for_box: the object will be used for boxing
4152 * @pass_size_in_words:
4154 * Return the allocation function appropriate for the given class.
4158 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4160 *pass_size_in_words = FALSE;
4162 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4163 profile_allocs = FALSE;
4165 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4166 return mono_object_new_specific;
4168 if (!vtable->klass->has_references) {
4169 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4171 return mono_object_new_ptrfree_box;
4172 return mono_object_new_ptrfree;
4175 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4177 return mono_object_new_fast;
4180 * FIXME: This is actually slower than mono_object_new_fast, because
4181 * of the overhead of parameter passing.
4184 *pass_size_in_words = TRUE;
4185 #ifdef GC_REDIRECT_TO_LOCAL
4186 return GC_local_gcj_fast_malloc;
4188 return GC_gcj_fast_malloc;
4193 return mono_object_new_specific;
4197 * mono_object_new_from_token:
4198 * @image: Context where the type_token is hosted
4199 * @token: a token of the type that we want to create
4201 * Returns: A newly created object whose definition is
4202 * looked up using @token in the @image image
4205 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4209 class = mono_class_get (image, token);
4211 return mono_object_new (domain, class);
4216 * mono_object_clone:
4217 * @obj: the object to clone
4219 * Returns: A newly created object who is a shallow copy of @obj
4222 mono_object_clone (MonoObject *obj)
4225 int size = obj->vtable->klass->instance_size;
4227 o = mono_object_allocate (size, obj->vtable);
4229 if (obj->vtable->klass->has_references) {
4230 mono_gc_wbarrier_object_copy (o, obj);
4232 int size = obj->vtable->klass->instance_size;
4233 /* do not copy the sync state */
4234 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4236 if (G_UNLIKELY (profile_allocs))
4237 mono_profiler_allocation (o, obj->vtable->klass);
4239 if (obj->vtable->klass->has_finalize)
4240 mono_object_register_finalizer (o);
4245 * mono_array_full_copy:
4246 * @src: source array to copy
4247 * @dest: destination array
4249 * Copies the content of one array to another with exactly the same type and size.
4252 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4254 mono_array_size_t size;
4255 MonoClass *klass = src->obj.vtable->klass;
4257 MONO_ARCH_SAVE_REGS;
4259 g_assert (klass == dest->obj.vtable->klass);
4261 size = mono_array_length (src);
4262 g_assert (size == mono_array_length (dest));
4263 size *= mono_array_element_size (klass);
4265 if (klass->element_class->valuetype) {
4266 if (klass->element_class->has_references)
4267 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4269 memcpy (&dest->vector, &src->vector, size);
4271 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4274 memcpy (&dest->vector, &src->vector, size);
4279 * mono_array_clone_in_domain:
4280 * @domain: the domain in which the array will be cloned into
4281 * @array: the array to clone
4283 * This routine returns a copy of the array that is hosted on the
4284 * specified MonoDomain.
4287 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4290 mono_array_size_t size, i;
4291 mono_array_size_t *sizes;
4292 MonoClass *klass = array->obj.vtable->klass;
4294 MONO_ARCH_SAVE_REGS;
4296 if (array->bounds == NULL) {
4297 size = mono_array_length (array);
4298 o = mono_array_new_full (domain, klass, &size, NULL);
4300 size *= mono_array_element_size (klass);
4302 if (klass->element_class->valuetype) {
4303 if (klass->element_class->has_references)
4304 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4306 memcpy (&o->vector, &array->vector, size);
4308 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4311 memcpy (&o->vector, &array->vector, size);
4316 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4317 size = mono_array_element_size (klass);
4318 for (i = 0; i < klass->rank; ++i) {
4319 sizes [i] = array->bounds [i].length;
4320 size *= array->bounds [i].length;
4321 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4323 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4325 if (klass->element_class->valuetype) {
4326 if (klass->element_class->has_references)
4327 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4329 memcpy (&o->vector, &array->vector, size);
4331 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4334 memcpy (&o->vector, &array->vector, size);
4342 * @array: the array to clone
4344 * Returns: A newly created array who is a shallow copy of @array
4347 mono_array_clone (MonoArray *array)
4349 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4352 /* helper macros to check for overflow when calculating the size of arrays */
4353 #ifdef MONO_BIG_ARRAYS
4354 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4355 #define MYGUINT_MAX MYGUINT64_MAX
4356 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4357 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4358 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4359 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4360 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4362 #define MYGUINT32_MAX 4294967295U
4363 #define MYGUINT_MAX MYGUINT32_MAX
4364 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4365 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4366 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4367 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4368 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4372 mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
4374 mono_array_size_t byte_len;
4376 byte_len = mono_array_element_size (class);
4377 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4380 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4382 byte_len += sizeof (MonoArray);
4390 * mono_array_new_full:
4391 * @domain: domain where the object is created
4392 * @array_class: array class
4393 * @lengths: lengths for each dimension in the array
4394 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4396 * This routine creates a new array objects with the given dimensions,
4397 * lower bounds and type.
4400 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4402 mono_array_size_t byte_len, len, bounds_size;
4405 MonoArrayBounds *bounds;
4409 if (!array_class->inited)
4410 mono_class_init (array_class);
4414 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4415 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4417 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4421 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4423 for (i = 0; i < array_class->rank; ++i) {
4424 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4426 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4427 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4432 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4433 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4437 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4438 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4439 byte_len = (byte_len + 3) & ~3;
4440 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4441 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4442 byte_len += bounds_size;
4445 * Following three lines almost taken from mono_object_new ():
4446 * they need to be kept in sync.
4448 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4449 #ifndef HAVE_SGEN_GC
4450 if (!array_class->has_references) {
4451 o = mono_object_allocate_ptrfree (byte_len, vtable);
4452 #if NEED_TO_ZERO_PTRFREE
4453 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4455 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4456 o = mono_object_allocate_spec (byte_len, vtable);
4458 o = mono_object_allocate (byte_len, vtable);
4461 array = (MonoArray*)o;
4462 array->max_length = len;
4465 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4466 array->bounds = bounds;
4470 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4472 o = mono_gc_alloc_vector (vtable, byte_len, len);
4473 array = (MonoArray*)o;
4474 mono_stats.new_object_count++;
4476 bounds = array->bounds;
4480 for (i = 0; i < array_class->rank; ++i) {
4481 bounds [i].length = lengths [i];
4483 bounds [i].lower_bound = lower_bounds [i];
4487 if (G_UNLIKELY (profile_allocs))
4488 mono_profiler_allocation (o, array_class);
4495 * @domain: domain where the object is created
4496 * @eclass: element class
4497 * @n: number of array elements
4499 * This routine creates a new szarray with @n elements of type @eclass.
4502 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4506 MONO_ARCH_SAVE_REGS;
4508 ac = mono_array_class_get (eclass, 1);
4511 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4515 * mono_array_new_specific:
4516 * @vtable: a vtable in the appropriate domain for an initialized class
4517 * @n: number of array elements
4519 * This routine is a fast alternative to mono_array_new() for code which
4520 * can be sure about the domain it operates in.
4523 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4529 MONO_ARCH_SAVE_REGS;
4531 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4536 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4537 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4540 #ifndef HAVE_SGEN_GC
4541 if (!vtable->klass->has_references) {
4542 o = mono_object_allocate_ptrfree (byte_len, vtable);
4543 #if NEED_TO_ZERO_PTRFREE
4544 ((MonoArray*)o)->bounds = NULL;
4545 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4547 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4548 o = mono_object_allocate_spec (byte_len, vtable);
4550 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4551 o = mono_object_allocate (byte_len, vtable);
4554 ao = (MonoArray *)o;
4557 o = mono_gc_alloc_vector (vtable, byte_len, n);
4559 mono_stats.new_object_count++;
4562 if (G_UNLIKELY (profile_allocs))
4563 mono_profiler_allocation (o, vtable->klass);
4569 * mono_string_new_utf16:
4570 * @text: a pointer to an utf16 string
4571 * @len: the length of the string
4573 * Returns: A newly created string object which contains @text.
4576 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4580 s = mono_string_new_size (domain, len);
4581 g_assert (s != NULL);
4583 memcpy (mono_string_chars (s), text, len * 2);
4589 * mono_string_new_size:
4590 * @text: a pointer to an utf16 string
4591 * @len: the length of the string
4593 * Returns: A newly created string object of @len
4596 mono_string_new_size (MonoDomain *domain, gint32 len)
4600 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4602 /* overflow ? can't fit it, can't allocate it! */
4604 mono_gc_out_of_memory (-1);
4606 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4609 s = mono_object_allocate_ptrfree (size, vtable);
4612 #if NEED_TO_ZERO_PTRFREE
4615 if (G_UNLIKELY (profile_allocs))
4616 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4622 * mono_string_new_len:
4623 * @text: a pointer to an utf8 string
4624 * @length: number of bytes in @text to consider
4626 * Returns: A newly created string object which contains @text.
4629 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4631 GError *error = NULL;
4632 MonoString *o = NULL;
4634 glong items_written;
4636 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4639 o = mono_string_new_utf16 (domain, ut, items_written);
4641 g_error_free (error);
4650 * @text: a pointer to an utf8 string
4652 * Returns: A newly created string object which contains @text.
4655 mono_string_new (MonoDomain *domain, const char *text)
4657 GError *error = NULL;
4658 MonoString *o = NULL;
4660 glong items_written;
4665 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4668 o = mono_string_new_utf16 (domain, ut, items_written);
4670 g_error_free (error);
4673 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4678 MonoString *o = NULL;
4680 if (!g_utf8_validate (text, -1, &end))
4683 len = g_utf8_strlen (text, -1);
4684 o = mono_string_new_size (domain, len);
4685 str = mono_string_chars (o);
4687 while (text < end) {
4688 *str++ = g_utf8_get_char (text);
4689 text = g_utf8_next_char (text);
4696 * mono_string_new_wrapper:
4697 * @text: pointer to utf8 characters.
4699 * Helper function to create a string object from @text in the current domain.
4702 mono_string_new_wrapper (const char *text)
4704 MonoDomain *domain = mono_domain_get ();
4706 MONO_ARCH_SAVE_REGS;
4709 return mono_string_new (domain, text);
4716 * @class: the class of the value
4717 * @value: a pointer to the unboxed data
4719 * Returns: A newly created object which contains @value.
4722 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4728 g_assert (class->valuetype);
4729 if (mono_class_is_nullable (class))
4730 return mono_nullable_box (value, class);
4732 vtable = mono_class_vtable (domain, class);
4735 size = mono_class_instance_size (class);
4736 res = mono_object_new_alloc_specific (vtable);
4737 if (G_UNLIKELY (profile_allocs))
4738 mono_profiler_allocation (res, class);
4740 size = size - sizeof (MonoObject);
4743 g_assert (size == mono_class_value_size (class, NULL));
4744 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4746 #if NO_UNALIGNED_ACCESS
4747 memcpy ((char *)res + sizeof (MonoObject), value, size);
4751 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4754 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4757 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4760 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4763 memcpy ((char *)res + sizeof (MonoObject), value, size);
4767 if (class->has_finalize)
4768 mono_object_register_finalizer (res);
4774 * @dest: destination pointer
4775 * @src: source pointer
4776 * @klass: a valuetype class
4778 * Copy a valuetype from @src to @dest. This function must be used
4779 * when @klass contains references fields.
4782 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4784 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4788 * mono_value_copy_array:
4789 * @dest: destination array
4790 * @dest_idx: index in the @dest array
4791 * @src: source pointer
4792 * @count: number of items
4794 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4795 * This function must be used when @klass contains references fields.
4796 * Overlap is handled.
4799 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4801 int size = mono_array_element_size (dest->obj.vtable->klass);
4802 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4803 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4804 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4808 * mono_object_get_domain:
4809 * @obj: object to query
4811 * Returns: the MonoDomain where the object is hosted
4814 mono_object_get_domain (MonoObject *obj)
4816 return mono_object_domain (obj);
4820 * mono_object_get_class:
4821 * @obj: object to query
4823 * Returns: the MonOClass of the object.
4826 mono_object_get_class (MonoObject *obj)
4828 return mono_object_class (obj);
4831 * mono_object_get_size:
4832 * @o: object to query
4834 * Returns: the size, in bytes, of @o
4837 mono_object_get_size (MonoObject* o)
4839 MonoClass* klass = mono_object_class (o);
4840 if (klass == mono_defaults.string_class) {
4841 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4842 } else if (o->vtable->rank) {
4843 MonoArray *array = (MonoArray*)o;
4844 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4845 if (array->bounds) {
4848 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4852 return mono_class_instance_size (klass);
4857 * mono_object_unbox:
4858 * @obj: object to unbox
4860 * Returns: a pointer to the start of the valuetype boxed in this
4863 * This method will assert if the object passed is not a valuetype.
4866 mono_object_unbox (MonoObject *obj)
4868 /* add assert for valuetypes? */
4869 g_assert (obj->vtable->klass->valuetype);
4870 return ((char*)obj) + sizeof (MonoObject);
4874 * mono_object_isinst:
4876 * @klass: a pointer to a class
4878 * Returns: @obj if @obj is derived from @klass
4881 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4884 mono_class_init (klass);
4886 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
4887 return mono_object_isinst_mbyref (obj, klass);
4892 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4896 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4905 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4906 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4910 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
4911 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
4914 MonoClass *oklass = vt->klass;
4915 if ((oklass == mono_defaults.transparent_proxy_class))
4916 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4918 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4922 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4924 MonoDomain *domain = mono_domain_get ();
4926 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4927 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4928 MonoMethod *im = NULL;
4931 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4932 im = mono_object_get_virtual_method (rp, im);
4935 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4938 res = mono_runtime_invoke (im, rp, pa, NULL);
4940 if (*(MonoBoolean *) mono_object_unbox(res)) {
4941 /* Update the vtable of the remote type, so it can safely cast to this new type */
4942 mono_upgrade_remote_class (domain, obj, klass);
4951 * mono_object_castclass_mbyref:
4953 * @klass: a pointer to a class
4955 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4958 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4960 if (!obj) return NULL;
4961 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4963 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4965 "InvalidCastException"));
4970 MonoDomain *orig_domain;
4976 str_lookup (MonoDomain *domain, gpointer user_data)
4978 LDStrInfo *info = user_data;
4979 if (info->res || domain == info->orig_domain)
4981 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4987 mono_string_get_pinned (MonoString *str)
4991 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4992 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4993 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4994 news->length = mono_string_length (str);
4999 #define mono_string_get_pinned(str) (str)
5003 mono_string_is_interned_lookup (MonoString *str, int insert)
5005 MonoGHashTable *ldstr_table;
5009 domain = ((MonoObject *)str)->vtable->domain;
5010 ldstr_table = domain->ldstr_table;
5012 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5017 str = mono_string_get_pinned (str);
5018 mono_g_hash_table_insert (ldstr_table, str, str);
5022 LDStrInfo ldstr_info;
5023 ldstr_info.orig_domain = domain;
5024 ldstr_info.ins = str;
5025 ldstr_info.res = NULL;
5027 mono_domain_foreach (str_lookup, &ldstr_info);
5028 if (ldstr_info.res) {
5030 * the string was already interned in some other domain:
5031 * intern it in the current one as well.
5033 mono_g_hash_table_insert (ldstr_table, str, str);
5043 * mono_string_is_interned:
5044 * @o: String to probe
5046 * Returns whether the string has been interned.
5049 mono_string_is_interned (MonoString *o)
5051 return mono_string_is_interned_lookup (o, FALSE);
5055 * mono_string_intern:
5056 * @o: String to intern
5058 * Interns the string passed.
5059 * Returns: The interned string.
5062 mono_string_intern (MonoString *str)
5064 return mono_string_is_interned_lookup (str, TRUE);
5069 * @domain: the domain where the string will be used.
5070 * @image: a metadata context
5071 * @idx: index into the user string table.
5073 * Implementation for the ldstr opcode.
5074 * Returns: a loaded string from the @image/@idx combination.
5077 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5079 MONO_ARCH_SAVE_REGS;
5081 if (image->dynamic) {
5082 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5083 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5084 mono_profiler_string_allocation (domain, str);
5087 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5088 return NULL; /*FIXME we should probably be raising an exception here*/
5089 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5094 * mono_ldstr_metadata_sig
5095 * @domain: the domain for the string
5096 * @sig: the signature of a metadata string
5098 * Returns: a MonoString for a string stored in the metadata
5101 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5103 const char *str = sig;
5104 MonoString *o, *interned;
5107 len2 = mono_metadata_decode_blob_size (str, &str);
5110 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5111 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5114 guint16 *p2 = (guint16*)mono_string_chars (o);
5115 for (i = 0; i < len2; ++i) {
5116 *p2 = GUINT16_FROM_LE (*p2);
5122 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5124 /* o will get garbage collected */
5128 o = mono_string_get_pinned (o);
5129 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5132 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5133 mono_profiler_string_allocation (domain, o);
5139 * mono_string_to_utf8:
5140 * @s: a System.String
5142 * Return the UTF8 representation for @s.
5143 * the resulting buffer nedds to be freed with g_free().
5145 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5148 mono_string_to_utf8 (MonoString *s)
5151 char *result = mono_string_to_utf8_checked (s, &error);
5153 if (!mono_error_ok (&error))
5154 mono_error_raise_exception (&error);
5159 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5163 GError *gerror = NULL;
5165 mono_error_init (error);
5171 return g_strdup ("");
5173 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5175 mono_error_set_argument (error, "string", "%s", gerror->message);
5176 g_error_free (gerror);
5179 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5180 if (s->length > written) {
5181 /* allocate the total length and copy the part of the string that has been converted */
5182 char *as2 = g_malloc0 (s->length);
5183 memcpy (as2, as, written);
5192 * mono_string_to_utf16:
5195 * Return an null-terminated array of the utf-16 chars
5196 * contained in @s. The result must be freed with g_free().
5197 * This is a temporary helper until our string implementation
5198 * is reworked to always include the null terminating char.
5201 mono_string_to_utf16 (MonoString *s)
5208 as = g_malloc ((s->length * 2) + 2);
5209 as [(s->length * 2)] = '\0';
5210 as [(s->length * 2) + 1] = '\0';
5213 return (gunichar2 *)(as);
5216 memcpy (as, mono_string_chars(s), s->length * 2);
5217 return (gunichar2 *)(as);
5221 * mono_string_from_utf16:
5222 * @data: the UTF16 string (LPWSTR) to convert
5224 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5226 * Returns: a MonoString.
5229 mono_string_from_utf16 (gunichar2 *data)
5231 MonoDomain *domain = mono_domain_get ();
5237 while (data [len]) len++;
5239 return mono_string_new_utf16 (domain, data, len);
5244 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5250 r = mono_string_to_utf8_checked (s, error);
5251 if (!mono_error_ok (error))
5257 len = strlen (r) + 1;
5259 mp_s = mono_mempool_alloc (mp, len);
5261 mp_s = mono_image_alloc (image, len);
5263 memcpy (mp_s, r, len);
5271 * mono_string_to_utf8_image:
5272 * @s: a System.String
5274 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5277 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5279 return mono_string_to_utf8_internal (NULL, image, s, error);
5283 * mono_string_to_utf8_mp:
5284 * @s: a System.String
5286 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5289 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5291 return mono_string_to_utf8_internal (mp, NULL, s, error);
5295 default_ex_handler (MonoException *ex)
5297 MonoObject *o = (MonoObject*)ex;
5298 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5302 static MonoExceptionFunc ex_handler = default_ex_handler;
5305 * mono_install_handler:
5306 * @func: exception handler
5308 * This is an internal JIT routine used to install the handler for exceptions
5312 mono_install_handler (MonoExceptionFunc func)
5314 ex_handler = func? func: default_ex_handler;
5318 * mono_raise_exception:
5319 * @ex: exception object
5321 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5324 mono_raise_exception (MonoException *ex)
5327 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5328 * that will cause gcc to omit the function epilog, causing problems when
5329 * the JIT tries to walk the stack, since the return address on the stack
5330 * will point into the next function in the executable, not this one.
5333 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5334 MonoInternalThread *thread = mono_thread_internal_current ();
5335 g_assert (ex->object.vtable->domain == mono_domain_get ());
5336 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5343 * mono_wait_handle_new:
5344 * @domain: Domain where the object will be created
5345 * @handle: Handle for the wait handle
5347 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5350 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5352 MonoWaitHandle *res;
5353 gpointer params [1];
5354 static MonoMethod *handle_set;
5356 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5358 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5360 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5362 params [0] = &handle;
5363 mono_runtime_invoke (handle_set, res, params, NULL);
5369 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5371 static MonoClassField *f_os_handle;
5372 static MonoClassField *f_safe_handle;
5374 if (!f_os_handle && !f_safe_handle) {
5375 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5376 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5381 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5385 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5392 mono_runtime_capture_context (MonoDomain *domain)
5394 RuntimeInvokeFunction runtime_invoke;
5396 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5397 MonoMethod *method = mono_get_context_capture_method ();
5398 MonoMethod *wrapper;
5401 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5402 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5403 domain->capture_context_method = mono_compile_method (method);
5406 runtime_invoke = domain->capture_context_runtime_invoke;
5408 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5411 * mono_async_result_new:
5412 * @domain:domain where the object will be created.
5413 * @handle: wait handle.
5414 * @state: state to pass to AsyncResult
5415 * @data: C closure data.
5417 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5418 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5422 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5424 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5425 MonoObject *context = mono_runtime_capture_context (domain);
5426 /* we must capture the execution context from the original thread */
5428 MONO_OBJECT_SETREF (res, execution_context, context);
5429 /* note: result may be null if the flow is suppressed */
5433 MONO_OBJECT_SETREF (res, object_data, object_data);
5434 MONO_OBJECT_SETREF (res, async_state, state);
5436 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5438 res->sync_completed = FALSE;
5439 res->completed = FALSE;
5445 mono_message_init (MonoDomain *domain,
5446 MonoMethodMessage *this,
5447 MonoReflectionMethod *method,
5448 MonoArray *out_args)
5450 static MonoClass *object_array_klass;
5451 static MonoClass *byte_array_klass;
5452 static MonoClass *string_array_klass;
5453 MonoMethodSignature *sig = mono_method_signature (method->method);
5459 if (!object_array_klass) {
5462 klass = mono_array_class_get (mono_defaults.object_class, 1);
5465 mono_memory_barrier ();
5466 object_array_klass = klass;
5468 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5471 mono_memory_barrier ();
5472 byte_array_klass = klass;
5474 klass = mono_array_class_get (mono_defaults.string_class, 1);
5477 mono_memory_barrier ();
5478 string_array_klass = klass;
5481 MONO_OBJECT_SETREF (this, method, method);
5483 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5484 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5485 this->async_result = NULL;
5486 this->call_type = CallType_Sync;
5488 names = g_new (char *, sig->param_count);
5489 mono_method_get_param_names (method->method, (const char **) names);
5490 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5492 for (i = 0; i < sig->param_count; i++) {
5493 name = mono_string_new (domain, names [i]);
5494 mono_array_setref (this->names, i, name);
5498 for (i = 0, j = 0; i < sig->param_count; i++) {
5499 if (sig->params [i]->byref) {
5501 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5502 mono_array_setref (this->args, i, arg);
5506 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5510 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5513 mono_array_set (this->arg_types, guint8, i, arg_type);
5518 * mono_remoting_invoke:
5519 * @real_proxy: pointer to a RealProxy object
5520 * @msg: The MonoMethodMessage to execute
5521 * @exc: used to store exceptions
5522 * @out_args: used to store output arguments
5524 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5525 * IMessage interface and it is not trivial to extract results from there. So
5526 * we call an helper method PrivateInvoke instead of calling
5527 * RealProxy::Invoke() directly.
5529 * Returns: the result object.
5532 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5533 MonoObject **exc, MonoArray **out_args)
5535 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5538 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5541 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5543 real_proxy->vtable->domain->private_invoke_method = im;
5546 pa [0] = real_proxy;
5551 return mono_runtime_invoke (im, NULL, pa, exc);
5555 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5556 MonoObject **exc, MonoArray **out_args)
5558 static MonoClass *object_array_klass;
5561 MonoMethodSignature *sig;
5563 int i, j, outarg_count = 0;
5565 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5567 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5568 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5569 target = tp->rp->unwrapped_server;
5571 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5575 domain = mono_domain_get ();
5576 method = msg->method->method;
5577 sig = mono_method_signature (method);
5579 for (i = 0; i < sig->param_count; i++) {
5580 if (sig->params [i]->byref)
5584 if (!object_array_klass) {
5587 klass = mono_array_class_get (mono_defaults.object_class, 1);
5590 mono_memory_barrier ();
5591 object_array_klass = klass;
5594 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5595 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5598 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5600 for (i = 0, j = 0; i < sig->param_count; i++) {
5601 if (sig->params [i]->byref) {
5603 arg = mono_array_get (msg->args, gpointer, i);
5604 mono_array_setref (*out_args, j, arg);
5613 * mono_print_unhandled_exception:
5614 * @exc: The exception
5616 * Prints the unhandled exception.
5619 mono_print_unhandled_exception (MonoObject *exc)
5622 char *message = (char *) "";
5626 gboolean free_message = FALSE;
5628 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5629 klass = exc->vtable->klass;
5631 while (klass && method == NULL) {
5632 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5634 klass = klass->parent;
5639 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5641 message = mono_string_to_utf8_checked (str, &error);
5642 if (!mono_error_ok (&error)) {
5643 mono_error_cleanup (&error);
5644 message = (char *)"";
5646 free_message = TRUE;
5652 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5653 * exc->vtable->klass->name, message);
5655 g_printerr ("\nUnhandled Exception: %s\n", message);
5662 * mono_delegate_ctor:
5663 * @this: pointer to an uninitialized delegate object
5664 * @target: target object
5665 * @addr: pointer to native code
5668 * Initialize a delegate and sets a specific method, not the one
5669 * associated with addr. This is useful when sharing generic code.
5670 * In that case addr will most probably not be associated with the
5671 * correct instantiation of the method.
5674 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5676 MonoDelegate *delegate = (MonoDelegate *)this;
5683 delegate->method = method;
5685 class = this->vtable->klass;
5686 mono_stats.delegate_creations++;
5688 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5690 method = mono_marshal_get_remoting_invoke (method);
5691 delegate->method_ptr = mono_compile_method (method);
5692 MONO_OBJECT_SETREF (delegate, target, target);
5693 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5694 method = mono_marshal_get_unbox_wrapper (method);
5695 delegate->method_ptr = mono_compile_method (method);
5696 MONO_OBJECT_SETREF (delegate, target, target);
5698 delegate->method_ptr = addr;
5699 MONO_OBJECT_SETREF (delegate, target, target);
5702 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5706 * mono_delegate_ctor:
5707 * @this: pointer to an uninitialized delegate object
5708 * @target: target object
5709 * @addr: pointer to native code
5711 * This is used to initialize a delegate.
5714 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5716 MonoDomain *domain = mono_domain_get ();
5718 MonoMethod *method = NULL;
5722 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5723 method = ji->method;
5724 g_assert (!method->klass->generic_container);
5727 mono_delegate_ctor_with_method (this, target, addr, method);
5731 * mono_method_call_message_new:
5732 * @method: method to encapsulate
5733 * @params: parameters to the method
5734 * @invoke: optional, delegate invoke.
5735 * @cb: async callback delegate.
5736 * @state: state passed to the async callback.
5738 * Translates arguments pointers into a MonoMethodMessage.
5741 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5742 MonoDelegate **cb, MonoObject **state)
5744 MonoDomain *domain = mono_domain_get ();
5745 MonoMethodSignature *sig = mono_method_signature (method);
5746 MonoMethodMessage *msg;
5749 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5752 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5753 count = sig->param_count - 2;
5755 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5756 count = sig->param_count;
5759 for (i = 0; i < count; i++) {
5764 if (sig->params [i]->byref)
5765 vpos = *((gpointer *)params [i]);
5769 type = sig->params [i]->type;
5770 class = mono_class_from_mono_type (sig->params [i]);
5772 if (class->valuetype)
5773 arg = mono_value_box (domain, class, vpos);
5775 arg = *((MonoObject **)vpos);
5777 mono_array_setref (msg->args, i, arg);
5780 if (cb != NULL && state != NULL) {
5781 *cb = *((MonoDelegate **)params [i]);
5783 *state = *((MonoObject **)params [i]);
5790 * mono_method_return_message_restore:
5792 * Restore results from message based processing back to arguments pointers
5795 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5797 MonoMethodSignature *sig = mono_method_signature (method);
5798 int i, j, type, size, out_len;
5800 if (out_args == NULL)
5802 out_len = mono_array_length (out_args);
5806 for (i = 0, j = 0; i < sig->param_count; i++) {
5807 MonoType *pt = sig->params [i];
5812 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5814 arg = mono_array_get (out_args, gpointer, j);
5817 g_assert (type != MONO_TYPE_VOID);
5819 if (MONO_TYPE_IS_REFERENCE (pt)) {
5820 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5823 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5824 size = mono_class_value_size (class, NULL);
5825 if (class->has_references)
5826 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5828 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5830 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5831 memset (*((gpointer *)params [i]), 0, size);
5841 * mono_load_remote_field:
5842 * @this: pointer to an object
5843 * @klass: klass of the object containing @field
5844 * @field: the field to load
5845 * @res: a storage to store the result
5847 * This method is called by the runtime on attempts to load fields of
5848 * transparent proxy objects. @this points to such TP, @klass is the class of
5849 * the object containing @field. @res is a storage location which can be
5850 * used to store the result.
5852 * Returns: an address pointing to the value of field.
5855 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5857 static MonoMethod *getter = NULL;
5858 MonoDomain *domain = mono_domain_get ();
5859 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5860 MonoClass *field_class;
5861 MonoMethodMessage *msg;
5862 MonoArray *out_args;
5866 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5867 g_assert (res != NULL);
5869 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5870 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5875 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5879 field_class = mono_class_from_mono_type (field->type);
5881 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5882 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5883 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5885 full_name = mono_type_get_full_name (klass);
5886 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5887 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5890 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5892 if (exc) mono_raise_exception ((MonoException *)exc);
5894 if (mono_array_length (out_args) == 0)
5897 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5899 if (field_class->valuetype) {
5900 return ((char *)*res) + sizeof (MonoObject);
5906 * mono_load_remote_field_new:
5911 * Missing documentation.
5914 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5916 static MonoMethod *getter = NULL;
5917 MonoDomain *domain = mono_domain_get ();
5918 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5919 MonoClass *field_class;
5920 MonoMethodMessage *msg;
5921 MonoArray *out_args;
5922 MonoObject *exc, *res;
5925 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5927 field_class = mono_class_from_mono_type (field->type);
5929 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5931 if (field_class->valuetype) {
5932 res = mono_object_new (domain, field_class);
5933 val = ((gchar *) res) + sizeof (MonoObject);
5937 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5942 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5946 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5947 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5949 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5951 full_name = mono_type_get_full_name (klass);
5952 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5953 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5956 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5958 if (exc) mono_raise_exception ((MonoException *)exc);
5960 if (mono_array_length (out_args) == 0)
5963 res = mono_array_get (out_args, MonoObject *, 0);
5969 * mono_store_remote_field:
5970 * @this: pointer to an object
5971 * @klass: klass of the object containing @field
5972 * @field: the field to load
5973 * @val: the value/object to store
5975 * This method is called by the runtime on attempts to store fields of
5976 * transparent proxy objects. @this points to such TP, @klass is the class of
5977 * the object containing @field. @val is the new value to store in @field.
5980 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5982 static MonoMethod *setter = NULL;
5983 MonoDomain *domain = mono_domain_get ();
5984 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5985 MonoClass *field_class;
5986 MonoMethodMessage *msg;
5987 MonoArray *out_args;
5992 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5994 field_class = mono_class_from_mono_type (field->type);
5996 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5997 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5998 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6003 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6007 if (field_class->valuetype)
6008 arg = mono_value_box (domain, field_class, val);
6010 arg = *((MonoObject **)val);
6013 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6014 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6016 full_name = mono_type_get_full_name (klass);
6017 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6018 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6019 mono_array_setref (msg->args, 2, arg);
6022 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6024 if (exc) mono_raise_exception ((MonoException *)exc);
6028 * mono_store_remote_field_new:
6034 * Missing documentation
6037 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6039 static MonoMethod *setter = NULL;
6040 MonoDomain *domain = mono_domain_get ();
6041 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6042 MonoClass *field_class;
6043 MonoMethodMessage *msg;
6044 MonoArray *out_args;
6048 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6050 field_class = mono_class_from_mono_type (field->type);
6052 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6053 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6054 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6059 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6063 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6064 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6066 full_name = mono_type_get_full_name (klass);
6067 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6068 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6069 mono_array_setref (msg->args, 2, arg);
6072 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6074 if (exc) mono_raise_exception ((MonoException *)exc);
6078 * mono_create_ftnptr:
6080 * Given a function address, create a function descriptor for it.
6081 * This is only needed on some platforms.
6084 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6086 return callbacks.create_ftnptr (domain, addr);
6090 * mono_get_addr_from_ftnptr:
6092 * Given a pointer to a function descriptor, return the function address.
6093 * This is only needed on some platforms.
6096 mono_get_addr_from_ftnptr (gpointer descr)
6098 return callbacks.get_addr_from_ftnptr (descr);
6103 * mono_string_chars:
6106 * Returns a pointer to the UCS16 characters stored in the MonoString
6109 mono_string_chars(MonoString *s)
6111 /* This method is here only for documentation extraction, this is a macro */
6115 * mono_string_length:
6118 * Returns the lenght in characters of the string
6121 mono_string_length (MonoString *s)
6123 /* This method is here only for documentation extraction, this is a macro */