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/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include "cominterop.h"
46 #define NEED_TO_ZERO_PTRFREE 1
47 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
48 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
49 #ifdef HAVE_GC_GCJ_MALLOC
50 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
51 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
53 #define GC_NO_DESCRIPTOR (NULL)
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
58 #define GC_NO_DESCRIPTOR (NULL)
59 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
61 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
63 #define NEED_TO_ZERO_PTRFREE 1
64 #define GC_NO_DESCRIPTOR (NULL)
65 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
66 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
67 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
71 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
72 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
75 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
78 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
80 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
81 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
82 static CRITICAL_SECTION ldstr_section;
84 static gboolean profile_allocs = TRUE;
87 mono_runtime_object_init (MonoObject *this)
89 MonoMethod *method = NULL;
90 MonoClass *klass = this->vtable->klass;
92 method = mono_class_get_method_from_name (klass, ".ctor", 0);
95 if (method->klass->valuetype)
96 this = mono_object_unbox (this);
97 mono_runtime_invoke (method, this, NULL, NULL);
100 /* The pseudo algorithm for type initialization from the spec
101 Note it doesn't say anything about domains - only threads.
103 2. If the type is initialized you are done.
104 2.1. If the type is not yet initialized, try to take an
106 2.2. If successful, record this thread as responsible for
107 initializing the type and proceed to step 2.3.
108 2.2.1. If not, see whether this thread or any thread
109 waiting for this thread to complete already holds the lock.
110 2.2.2. If so, return since blocking would create a deadlock. This thread
111 will now see an incompletely initialized state for the type,
112 but no deadlock will arise.
113 2.2.3 If not, block until the type is initialized then return.
114 2.3 Initialize the parent type and then all interfaces implemented
116 2.4 Execute the type initialization code for this type.
117 2.5 Mark the type as initialized, release the initialization lock,
118 awaken any threads waiting for this type to be initialized,
125 guint32 initializing_tid;
126 guint32 waiting_count;
128 CRITICAL_SECTION initialization_section;
129 } TypeInitializationLock;
131 /* for locking access to type_initialization_hash and blocked_thread_hash */
132 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
133 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
134 static CRITICAL_SECTION type_initialization_section;
136 /* from vtable to lock */
137 static GHashTable *type_initialization_hash;
139 /* from thread id to thread id being waited on */
140 static GHashTable *blocked_thread_hash;
143 static MonoThread *main_thread;
145 /* Functions supplied by the runtime */
146 static MonoRuntimeCallbacks callbacks;
149 * mono_thread_set_main:
150 * @thread: thread to set as the main thread
152 * This function can be used to instruct the runtime to treat @thread
153 * as the main thread, ie, the thread that would normally execute the Main()
154 * method. This basically means that at the end of @thread, the runtime will
155 * wait for the existing foreground threads to quit and other such details.
158 mono_thread_set_main (MonoThread *thread)
160 main_thread = thread;
164 mono_thread_get_main (void)
170 mono_type_initialization_init (void)
172 InitializeCriticalSection (&type_initialization_section);
173 type_initialization_hash = g_hash_table_new (NULL, NULL);
174 blocked_thread_hash = g_hash_table_new (NULL, NULL);
175 InitializeCriticalSection (&ldstr_section);
179 mono_type_initialization_cleanup (void)
182 /* This is causing race conditions with
183 * mono_release_type_locks
185 DeleteCriticalSection (&type_initialization_section);
187 DeleteCriticalSection (&ldstr_section);
191 * get_type_init_exception_for_vtable:
193 * Return the stored type initialization exception for VTABLE.
195 static MonoException*
196 get_type_init_exception_for_vtable (MonoVTable *vtable)
198 MonoDomain *domain = vtable->domain;
199 MonoClass *klass = vtable->klass;
203 g_assert (vtable->init_failed);
206 * If the initializing thread was rudely aborted, the exception is not stored
210 mono_domain_lock (domain);
211 if (domain->type_init_exception_hash)
212 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
213 mono_domain_unlock (domain);
216 if (klass->name_space && *klass->name_space)
217 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
219 full_name = g_strdup (klass->name);
220 ex = mono_get_exception_type_initialization (full_name, NULL);
227 * mono_runtime_class_init:
228 * @vtable: vtable that needs to be initialized
230 * This routine calls the class constructor for @vtable.
233 mono_runtime_class_init (MonoVTable *vtable)
235 mono_runtime_class_init_full (vtable, TRUE);
239 * mono_runtime_class_init_full:
240 * @vtable that neeeds to be initialized
241 * @raise_exception is TRUE, exceptions are raised intead of returned
245 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
248 MonoException *exc_to_throw;
249 MonoMethod *method = NULL;
255 if (vtable->initialized)
259 klass = vtable->klass;
261 if (!klass->image->checked_module_cctor) {
262 mono_image_check_for_module_cctor (klass->image);
263 if (klass->image->has_module_cctor) {
264 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
265 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
268 mono_runtime_class_init (module_vtable);
271 method = mono_class_get_cctor (klass);
274 MonoDomain *domain = vtable->domain;
275 TypeInitializationLock *lock;
276 guint32 tid = GetCurrentThreadId();
277 int do_initialization = 0;
278 MonoDomain *last_domain = NULL;
280 mono_type_initialization_lock ();
281 /* double check... */
282 if (vtable->initialized) {
283 mono_type_initialization_unlock ();
286 if (vtable->init_failed) {
287 mono_type_initialization_unlock ();
289 /* The type initialization already failed once, rethrow the same exception */
291 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
292 return get_type_init_exception_for_vtable (vtable);
294 lock = g_hash_table_lookup (type_initialization_hash, vtable);
296 /* This thread will get to do the initialization */
297 if (mono_domain_get () != domain) {
298 /* Transfer into the target domain */
299 last_domain = mono_domain_get ();
300 if (!mono_domain_set (domain, FALSE)) {
301 vtable->initialized = 1;
302 mono_type_initialization_unlock ();
304 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
305 return mono_get_exception_appdomain_unloaded ();
308 lock = g_malloc (sizeof(TypeInitializationLock));
309 InitializeCriticalSection (&lock->initialization_section);
310 lock->initializing_tid = tid;
311 lock->waiting_count = 1;
313 /* grab the vtable lock while this thread still owns type_initialization_section */
314 EnterCriticalSection (&lock->initialization_section);
315 g_hash_table_insert (type_initialization_hash, vtable, lock);
316 do_initialization = 1;
319 TypeInitializationLock *pending_lock;
321 if (lock->initializing_tid == tid || lock->done) {
322 mono_type_initialization_unlock ();
325 /* see if the thread doing the initialization is already blocked on this thread */
326 blocked = GUINT_TO_POINTER (lock->initializing_tid);
327 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
328 if (pending_lock->initializing_tid == tid) {
329 if (!pending_lock->done) {
330 mono_type_initialization_unlock ();
333 /* the thread doing the initialization is blocked on this thread,
334 but on a lock that has already been freed. It just hasn't got
339 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
341 ++lock->waiting_count;
342 /* record the fact that we are waiting on the initializing thread */
343 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
345 mono_type_initialization_unlock ();
347 if (do_initialization) {
348 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
350 /* If the initialization failed, mark the class as unusable. */
351 /* Avoid infinite loops */
353 (klass->image == mono_defaults.corlib &&
354 !strcmp (klass->name_space, "System") &&
355 !strcmp (klass->name, "TypeInitializationException")))) {
356 vtable->init_failed = 1;
358 if (klass->name_space && *klass->name_space)
359 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
361 full_name = g_strdup (klass->name);
362 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
366 * Store the exception object so it could be thrown on subsequent
369 mono_domain_lock (domain);
370 if (!domain->type_init_exception_hash)
371 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
372 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
373 mono_domain_unlock (domain);
377 mono_domain_set (last_domain, TRUE);
379 LeaveCriticalSection (&lock->initialization_section);
381 /* this just blocks until the initializing thread is done */
382 EnterCriticalSection (&lock->initialization_section);
383 LeaveCriticalSection (&lock->initialization_section);
386 mono_type_initialization_lock ();
387 if (lock->initializing_tid != tid)
388 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
389 --lock->waiting_count;
390 if (lock->waiting_count == 0) {
391 DeleteCriticalSection (&lock->initialization_section);
392 g_hash_table_remove (type_initialization_hash, vtable);
395 if (!vtable->init_failed)
396 vtable->initialized = 1;
397 mono_type_initialization_unlock ();
399 if (vtable->init_failed) {
400 /* Either we were the initializing thread or we waited for the initialization */
402 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
403 return get_type_init_exception_for_vtable (vtable);
406 vtable->initialized = 1;
413 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
415 MonoVTable *vtable = (MonoVTable*)key;
417 TypeInitializationLock *lock = (TypeInitializationLock*) value;
418 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
421 * Have to set this since it cannot be set by the normal code in
422 * mono_runtime_class_init (). In this case, the exception object is not stored,
423 * and get_type_init_exception_for_class () needs to be aware of this.
425 vtable->init_failed = 1;
426 LeaveCriticalSection (&lock->initialization_section);
427 --lock->waiting_count;
428 if (lock->waiting_count == 0) {
429 DeleteCriticalSection (&lock->initialization_section);
438 mono_release_type_locks (MonoThread *thread)
440 mono_type_initialization_lock ();
441 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
442 mono_type_initialization_unlock ();
446 default_trampoline (MonoMethod *method)
452 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
454 g_assert_not_reached ();
460 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
462 g_error ("remoting not installed");
467 default_delegate_trampoline (MonoClass *klass)
469 g_assert_not_reached ();
473 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
474 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
475 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
476 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
477 static MonoImtThunkBuilder imt_thunk_builder = NULL;
478 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
479 #if (MONO_IMT_SIZE > 32)
480 #error "MONO_IMT_SIZE cannot be larger than 32"
484 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
486 memcpy (&callbacks, cbs, sizeof (*cbs));
489 MonoRuntimeCallbacks*
490 mono_get_runtime_callbacks (void)
496 mono_install_trampoline (MonoTrampoline func)
498 arch_create_jit_trampoline = func? func: default_trampoline;
502 mono_install_jump_trampoline (MonoJumpTrampoline func)
504 arch_create_jump_trampoline = func? func: default_jump_trampoline;
508 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
510 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
514 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
516 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
520 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
521 imt_thunk_builder = func;
524 static MonoCompileFunc default_mono_compile_method = NULL;
527 * mono_install_compile_method:
528 * @func: function to install
530 * This is a VM internal routine
533 mono_install_compile_method (MonoCompileFunc func)
535 default_mono_compile_method = func;
539 * mono_compile_method:
540 * @method: The method to compile.
542 * This JIT-compiles the method, and returns the pointer to the native code
546 mono_compile_method (MonoMethod *method)
548 if (!default_mono_compile_method) {
549 g_error ("compile method called on uninitialized runtime");
552 return default_mono_compile_method (method);
556 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
558 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
562 mono_runtime_create_delegate_trampoline (MonoClass *klass)
564 return arch_create_delegate_trampoline (klass);
567 static MonoFreeMethodFunc default_mono_free_method = NULL;
570 * mono_install_free_method:
571 * @func: pointer to the MonoFreeMethodFunc used to release a method
573 * This is an internal VM routine, it is used for the engines to
574 * register a handler to release the resources associated with a method.
576 * Methods are freed when no more references to the delegate that holds
580 mono_install_free_method (MonoFreeMethodFunc func)
582 default_mono_free_method = func;
586 * mono_runtime_free_method:
587 * @domain; domain where the method is hosted
588 * @method: method to release
590 * This routine is invoked to free the resources associated with
591 * a method that has been JIT compiled. This is used to discard
592 * methods that were used only temporarily (for example, used in marshalling)
596 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
598 if (default_mono_free_method != NULL)
599 default_mono_free_method (domain, method);
601 mono_method_clear_object (domain, method);
603 mono_free_method (method);
607 * The vtables in the root appdomain are assumed to be reachable by other
608 * roots, and we don't use typed allocation in the other domains.
611 /* The sync block is no longer a GC pointer */
612 #define GC_HEADER_BITMAP (0)
614 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
617 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
619 MonoClassField *field;
625 max_size = mono_class_data_size (class) / sizeof (gpointer);
627 max_size = class->instance_size / sizeof (gpointer);
628 if (max_size >= size) {
629 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
632 for (p = class; p != NULL; p = p->parent) {
633 gpointer iter = NULL;
634 while ((field = mono_class_get_fields (p, &iter))) {
638 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
640 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
643 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
646 /* FIXME: should not happen, flag as type load error */
647 if (field->type->byref)
650 if (static_fields && field->offset == -1)
654 pos = field->offset / sizeof (gpointer);
657 type = mono_type_get_underlying_type (field->type);
658 switch (type->type) {
661 case MONO_TYPE_FNPTR:
663 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
668 if (class->image != mono_defaults.corlib)
671 case MONO_TYPE_STRING:
672 case MONO_TYPE_SZARRAY:
673 case MONO_TYPE_CLASS:
674 case MONO_TYPE_OBJECT:
675 case MONO_TYPE_ARRAY:
676 g_assert ((field->offset % sizeof(gpointer)) == 0);
678 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
679 *max_set = MAX (*max_set, pos);
681 case MONO_TYPE_GENERICINST:
682 if (!mono_type_generic_inst_is_valuetype (type)) {
683 g_assert ((field->offset % sizeof(gpointer)) == 0);
685 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
686 *max_set = MAX (*max_set, pos);
691 case MONO_TYPE_VALUETYPE: {
692 MonoClass *fclass = mono_class_from_mono_type (field->type);
693 if (fclass->has_references) {
694 /* remove the object header */
695 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
709 case MONO_TYPE_BOOLEAN:
713 g_assert_not_reached ();
725 * similar to the above, but sets the bits in the bitmap for any non-ref field
726 * and ignores static fields
729 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
731 MonoClassField *field;
736 max_size = class->instance_size / sizeof (gpointer);
737 if (max_size >= size) {
738 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
741 for (p = class; p != NULL; p = p->parent) {
742 gpointer iter = NULL;
743 while ((field = mono_class_get_fields (p, &iter))) {
746 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
748 /* FIXME: should not happen, flag as type load error */
749 if (field->type->byref)
752 pos = field->offset / sizeof (gpointer);
755 type = mono_type_get_underlying_type (field->type);
756 switch (type->type) {
757 #if SIZEOF_VOID_P == 8
761 case MONO_TYPE_FNPTR:
766 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
767 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
768 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
771 #if SIZEOF_VOID_P == 4
775 case MONO_TYPE_FNPTR:
780 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
781 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
782 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
788 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
789 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
790 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
793 case MONO_TYPE_BOOLEAN:
796 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
798 case MONO_TYPE_STRING:
799 case MONO_TYPE_SZARRAY:
800 case MONO_TYPE_CLASS:
801 case MONO_TYPE_OBJECT:
802 case MONO_TYPE_ARRAY:
804 case MONO_TYPE_GENERICINST:
805 if (!mono_type_generic_inst_is_valuetype (type)) {
810 case MONO_TYPE_VALUETYPE: {
811 MonoClass *fclass = mono_class_from_mono_type (field->type);
812 /* remove the object header */
813 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
817 g_assert_not_reached ();
826 * mono_class_insecure_overlapping:
827 * check if a class with explicit layout has references and non-references
828 * fields overlapping.
830 * Returns: TRUE if it is insecure to load the type.
833 mono_class_insecure_overlapping (MonoClass *klass)
837 gsize default_bitmap [4] = {0};
839 gsize default_nrbitmap [4] = {0};
840 int i, insecure = FALSE;
843 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
844 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
846 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
847 int idx = i % (sizeof (bitmap [0]) * 8);
848 if (bitmap [idx] & nrbitmap [idx]) {
853 if (bitmap != default_bitmap)
855 if (nrbitmap != default_nrbitmap)
858 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
866 mono_string_alloc (int length)
868 return mono_string_new_size (mono_domain_get (), length);
872 mono_class_compute_gc_descriptor (MonoClass *class)
876 gsize default_bitmap [4] = {0};
877 static gboolean gcj_inited = FALSE;
882 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
883 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
884 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
885 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
887 #ifdef HAVE_GC_GCJ_MALLOC
889 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
893 #ifdef GC_REDIRECT_TO_LOCAL
894 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
895 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
897 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
898 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
903 mono_loader_unlock ();
907 mono_class_init (class);
909 if (class->gc_descr_inited)
912 class->gc_descr_inited = TRUE;
913 class->gc_descr = GC_NO_DESCRIPTOR;
915 bitmap = default_bitmap;
916 if (class == mono_defaults.string_class) {
917 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
918 } else if (class->rank) {
919 mono_class_compute_gc_descriptor (class->element_class);
920 if (!class->element_class->valuetype) {
922 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
923 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
924 class->name_space, class->name);*/
926 /* remove the object header */
927 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
928 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
929 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
930 class->name_space, class->name);*/
931 if (bitmap != default_bitmap)
935 /*static int count = 0;
938 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
939 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
941 if (class->gc_descr == GC_NO_DESCRIPTOR)
942 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
944 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
945 if (bitmap != default_bitmap)
951 * field_is_special_static:
952 * @fklass: The MonoClass to look up.
953 * @field: The MonoClassField describing the field.
955 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
956 * SPECIAL_STATIC_NONE otherwise.
959 field_is_special_static (MonoClass *fklass, MonoClassField *field)
961 MonoCustomAttrInfo *ainfo;
963 ainfo = mono_custom_attrs_from_field (fklass, field);
966 for (i = 0; i < ainfo->num_attrs; ++i) {
967 MonoClass *klass = ainfo->attrs [i].ctor->klass;
968 if (klass->image == mono_defaults.corlib) {
969 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
970 mono_custom_attrs_free (ainfo);
971 return SPECIAL_STATIC_THREAD;
973 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
974 mono_custom_attrs_free (ainfo);
975 return SPECIAL_STATIC_CONTEXT;
979 mono_custom_attrs_free (ainfo);
980 return SPECIAL_STATIC_NONE;
983 static gpointer imt_trampoline = NULL;
986 mono_install_imt_trampoline (gpointer tramp_code)
988 imt_trampoline = tramp_code;
991 static gpointer vtable_trampoline = NULL;
994 mono_install_vtable_trampoline (gpointer tramp_code)
996 vtable_trampoline = tramp_code;
999 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1000 #define mix(a,b,c) { \
1001 a -= c; a ^= rot(c, 4); c += b; \
1002 b -= a; b ^= rot(a, 6); a += c; \
1003 c -= b; c ^= rot(b, 8); b += a; \
1004 a -= c; a ^= rot(c,16); c += b; \
1005 b -= a; b ^= rot(a,19); a += c; \
1006 c -= b; c ^= rot(b, 4); b += a; \
1008 #define final(a,b,c) { \
1009 c ^= b; c -= rot(b,14); \
1010 a ^= c; a -= rot(c,11); \
1011 b ^= a; b -= rot(a,25); \
1012 c ^= b; c -= rot(b,16); \
1013 a ^= c; a -= rot(c,4); \
1014 b ^= a; b -= rot(a,14); \
1015 c ^= b; c -= rot(b,24); \
1019 mono_method_get_imt_slot (MonoMethod *method)
1021 MonoMethodSignature *sig;
1023 guint32 *hashes_start, *hashes;
1027 /* This can be used to stress tests the collision code */
1031 * We do this to simplify generic sharing. It will hurt
1032 * performance in cases where a class implements two different
1033 * instantiations of the same generic interface.
1034 * The code in build_imt_slots () depends on this.
1036 if (method->is_inflated)
1037 method = ((MonoMethodInflated*)method)->declaring;
1039 sig = mono_method_signature (method);
1040 hashes_count = sig->param_count + 4;
1041 hashes_start = malloc (hashes_count * sizeof (guint32));
1042 hashes = hashes_start;
1044 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1045 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1046 method->klass->name_space, method->klass->name, method->name);
1047 g_assert_not_reached ();
1050 /* Initialize hashes */
1051 hashes [0] = g_str_hash (method->klass->name);
1052 hashes [1] = g_str_hash (method->klass->name_space);
1053 hashes [2] = g_str_hash (method->name);
1054 hashes [3] = mono_metadata_type_hash (sig->ret);
1055 for (i = 0; i < sig->param_count; i++) {
1056 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1059 /* Setup internal state */
1060 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1062 /* Handle most of the hashes */
1063 while (hashes_count > 3) {
1072 /* Handle the last 3 hashes (all the case statements fall through) */
1073 switch (hashes_count) {
1074 case 3 : c += hashes [2];
1075 case 2 : b += hashes [1];
1076 case 1 : a += hashes [0];
1078 case 0: /* nothing left to add */
1082 free (hashes_start);
1083 /* Report the result */
1084 return c % MONO_IMT_SIZE;
1093 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1094 guint32 imt_slot = mono_method_get_imt_slot (method);
1095 MonoImtBuilderEntry *entry;
1097 if (slot_num >= 0 && imt_slot != slot_num) {
1098 /* we build just a single imt slot and this is not it */
1102 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1103 entry->key = method;
1104 entry->value.vtable_slot = vtable_slot;
1105 entry->next = imt_builder [imt_slot];
1106 if (imt_builder [imt_slot] != NULL) {
1107 entry->children = imt_builder [imt_slot]->children + 1;
1108 if (entry->children == 1) {
1109 mono_stats.imt_slots_with_collisions++;
1110 *imt_collisions_bitmap |= (1 << imt_slot);
1113 entry->children = 0;
1114 mono_stats.imt_used_slots++;
1116 imt_builder [imt_slot] = entry;
1118 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1119 method, method->klass->name_space, method->klass->name,
1120 method->name, imt_slot, vtable_slot, entry->children);
1126 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1128 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1132 e->method->klass->name_space,
1133 e->method->klass->name,
1136 printf (" * %s: NULL\n", message);
1142 compare_imt_builder_entries (const void *p1, const void *p2) {
1143 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1144 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1146 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1150 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1152 int count = end - start;
1153 int chunk_start = out_array->len;
1156 for (i = start; i < end; ++i) {
1157 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1158 item->key = sorted_array [i]->key;
1159 item->value = sorted_array [i]->value;
1160 item->has_target_code = sorted_array [i]->has_target_code;
1161 item->is_equals = TRUE;
1163 item->check_target_idx = out_array->len + 1;
1165 item->check_target_idx = 0;
1166 g_ptr_array_add (out_array, item);
1169 int middle = start + count / 2;
1170 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1172 item->key = sorted_array [middle]->key;
1173 item->is_equals = FALSE;
1174 g_ptr_array_add (out_array, item);
1175 imt_emit_ir (sorted_array, start, middle, out_array);
1176 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1182 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1183 int number_of_entries = entries->children + 1;
1184 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1185 GPtrArray *result = g_ptr_array_new ();
1186 MonoImtBuilderEntry *current_entry;
1189 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1190 sorted_array [i] = current_entry;
1192 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1194 /*for (i = 0; i < number_of_entries; i++) {
1195 print_imt_entry (" sorted array:", sorted_array [i], i);
1198 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1200 free (sorted_array);
1205 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1207 if (imt_builder_entry != NULL) {
1208 if (imt_builder_entry->children == 0 && !fail_tramp) {
1209 /* No collision, return the vtable slot contents */
1210 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1212 /* Collision, build the thunk */
1213 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1216 result = imt_thunk_builder (vtable, domain,
1217 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1218 for (i = 0; i < imt_ir->len; ++i)
1219 g_free (g_ptr_array_index (imt_ir, i));
1220 g_ptr_array_free (imt_ir, TRUE);
1232 static MonoImtBuilderEntry*
1233 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1236 * LOCKING: requires the loader and domain locks.
1240 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1244 guint32 imt_collisions_bitmap = 0;
1245 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1246 int method_count = 0;
1247 gboolean record_method_count_for_max_collisions = FALSE;
1248 gboolean has_generic_virtual = FALSE;
1251 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1253 for (i = 0; i < klass->interface_offsets_count; ++i) {
1254 MonoClass *iface = klass->interfaces_packed [i];
1255 int interface_offset = klass->interface_offsets_packed [i];
1256 int method_slot_in_interface;
1257 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1260 if (slot_num >= 0 && iface->is_inflated) {
1262 * The imt slot of the method is the same as for its declaring method,
1263 * see the comment in mono_method_get_imt_slot (), so we can
1264 * avoid inflating methods which will be discarded by
1265 * add_imt_builder_entry anyway.
1267 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1268 if (mono_method_get_imt_slot (method) != slot_num)
1271 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1272 if (method->is_generic) {
1273 has_generic_virtual = TRUE;
1276 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1279 if (extra_interfaces) {
1280 int interface_offset = klass->vtable_size;
1282 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1283 MonoClass* iface = list_item->data;
1284 int method_slot_in_interface;
1285 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1286 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1287 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1289 interface_offset += iface->method.count;
1292 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1293 /* overwrite the imt slot only if we're building all the entries or if
1294 * we're building this specific one
1296 if (slot_num < 0 || i == slot_num) {
1297 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1300 if (imt_builder [i]) {
1301 MonoImtBuilderEntry *entry;
1303 /* Link entries with imt_builder [i] */
1304 for (entry = entries; entry->next; entry = entry->next)
1306 entry->next = imt_builder [i];
1307 entries->children += imt_builder [i]->children + 1;
1309 imt_builder [i] = entries;
1312 if (has_generic_virtual) {
1314 * There might be collisions later when the the thunk is expanded.
1316 imt_collisions_bitmap |= (1 << i);
1319 * The IMT thunk might be called with an instance of one of the
1320 * generic virtual methods, so has to fallback to the IMT trampoline.
1322 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1324 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1328 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1330 if (imt_builder [i] != NULL) {
1331 int methods_in_slot = imt_builder [i]->children + 1;
1332 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1333 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1334 record_method_count_for_max_collisions = TRUE;
1336 method_count += methods_in_slot;
1340 mono_stats.imt_number_of_methods += method_count;
1341 if (record_method_count_for_max_collisions) {
1342 mono_stats.imt_method_count_when_max_collisions = method_count;
1345 for (i = 0; i < MONO_IMT_SIZE; i++) {
1346 MonoImtBuilderEntry* entry = imt_builder [i];
1347 while (entry != NULL) {
1348 MonoImtBuilderEntry* next = entry->next;
1354 /* we OR the bitmap since we may build just a single imt slot at a time */
1355 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1359 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1360 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1364 * mono_vtable_build_imt_slot:
1365 * @vtable: virtual object table struct
1366 * @imt_slot: slot in the IMT table
1368 * Fill the given @imt_slot in the IMT table of @vtable with
1369 * a trampoline or a thunk for the case of collisions.
1370 * This is part of the internal mono API.
1372 * LOCKING: Take the domain lock.
1375 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1377 gpointer *imt = (gpointer*)vtable;
1378 imt -= MONO_IMT_SIZE;
1379 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1381 /* no support for extra interfaces: the proxy objects will need
1382 * to build the complete IMT
1383 * Update and heck needs to ahppen inside the proper domain lock, as all
1384 * the changes made to a MonoVTable.
1386 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1387 mono_domain_lock (vtable->domain);
1388 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1389 if (imt [imt_slot] == imt_trampoline)
1390 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1391 mono_domain_unlock (vtable->domain);
1392 mono_loader_unlock ();
1397 * The first two free list entries both belong to the wait list: The
1398 * first entry is the pointer to the head of the list and the second
1399 * entry points to the last element. That way appending and removing
1400 * the first element are both O(1) operations.
1402 #define NUM_FREE_LISTS 12
1403 #define FIRST_FREE_LIST_SIZE 64
1404 #define MAX_WAIT_LENGTH 50
1405 #define THUNK_THRESHOLD 10
1408 * LOCKING: The domain lock must be held.
1411 init_thunk_free_lists (MonoDomain *domain)
1413 if (domain->thunk_free_lists)
1415 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1419 list_index_for_size (int item_size)
1422 int size = FIRST_FREE_LIST_SIZE;
1424 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1433 * mono_method_alloc_generic_virtual_thunk:
1435 * @size: size in bytes
1437 * Allocs size bytes to be used for the code of a generic virtual
1438 * thunk. It's either allocated from the domain's code manager or
1439 * reused from a previously invalidated piece.
1441 * LOCKING: The domain lock must be held.
1444 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1446 static gboolean inited = FALSE;
1447 static int generic_virtual_thunks_size = 0;
1451 MonoThunkFreeList **l;
1453 init_thunk_free_lists (domain);
1455 size += sizeof (guint32);
1456 if (size < sizeof (MonoThunkFreeList))
1457 size = sizeof (MonoThunkFreeList);
1459 i = list_index_for_size (size);
1460 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1461 if ((*l)->size >= size) {
1462 MonoThunkFreeList *item = *l;
1464 return ((guint32*)item) + 1;
1468 /* no suitable item found - search lists of larger sizes */
1469 while (++i < NUM_FREE_LISTS) {
1470 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1473 g_assert (item->size > size);
1474 domain->thunk_free_lists [i] = item->next;
1475 return ((guint32*)item) + 1;
1478 /* still nothing found - allocate it */
1480 mono_counters_register ("Generic virtual thunk bytes",
1481 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1484 generic_virtual_thunks_size += size;
1486 p = mono_domain_code_reserve (domain, size);
1493 * LOCKING: The domain lock must be held.
1496 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1499 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1501 init_thunk_free_lists (domain);
1503 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1504 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1505 int length = item->length;
1508 /* unlink the first item from the wait list */
1509 domain->thunk_free_lists [0] = item->next;
1510 domain->thunk_free_lists [0]->length = length - 1;
1512 i = list_index_for_size (item->size);
1514 /* put it in the free list */
1515 item->next = domain->thunk_free_lists [i];
1516 domain->thunk_free_lists [i] = item;
1520 if (domain->thunk_free_lists [1]) {
1521 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1522 domain->thunk_free_lists [0]->length++;
1524 g_assert (!domain->thunk_free_lists [0]);
1526 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1527 domain->thunk_free_lists [0]->length = 1;
1531 typedef struct _GenericVirtualCase {
1535 struct _GenericVirtualCase *next;
1536 } GenericVirtualCase;
1539 * get_generic_virtual_entries:
1541 * Return IMT entries for the generic virtual method instances for vtable slot
1544 static MonoImtBuilderEntry*
1545 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1547 GenericVirtualCase *list;
1548 MonoImtBuilderEntry *entries;
1550 mono_domain_lock (domain);
1551 if (!domain->generic_virtual_cases)
1552 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1554 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1557 for (; list; list = list->next) {
1558 MonoImtBuilderEntry *entry;
1560 if (list->count < THUNK_THRESHOLD)
1563 entry = g_new0 (MonoImtBuilderEntry, 1);
1564 entry->key = list->method;
1565 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1566 entry->has_target_code = 1;
1568 entry->children = entries->children + 1;
1569 entry->next = entries;
1573 mono_domain_unlock (domain);
1575 /* FIXME: Leaking memory ? */
1580 * mono_method_add_generic_virtual_invocation:
1582 * @vtable_slot: pointer to the vtable slot
1583 * @method: the inflated generic virtual method
1584 * @code: the method's code
1586 * Registers a call via unmanaged code to a generic virtual method
1587 * instantiation. If the number of calls reaches a threshold
1588 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1589 * virtual method thunk.
1592 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1593 gpointer *vtable_slot,
1594 MonoMethod *method, gpointer code)
1596 static gboolean inited = FALSE;
1597 static int num_added = 0;
1599 GenericVirtualCase *gvc, *list;
1600 MonoImtBuilderEntry *entries;
1604 mono_domain_lock (domain);
1605 if (!domain->generic_virtual_cases)
1606 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1608 /* Check whether the case was already added */
1609 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1612 if (gvc->method == method)
1617 /* If not found, make a new one */
1619 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1620 gvc->method = method;
1623 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1625 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1628 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1634 if (++gvc->count == THUNK_THRESHOLD) {
1635 gpointer *old_thunk = *vtable_slot;
1637 if ((gpointer)vtable_slot < (gpointer)vtable)
1638 /* Force the rebuild of the thunk at the next call */
1639 *vtable_slot = imt_trampoline;
1641 entries = get_generic_virtual_entries (domain, vtable_slot);
1643 sorted = imt_sort_slot_entries (entries);
1645 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1649 MonoImtBuilderEntry *next = entries->next;
1654 for (i = 0; i < sorted->len; ++i)
1655 g_free (g_ptr_array_index (sorted, i));
1656 g_ptr_array_free (sorted, TRUE);
1659 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1660 invalidate_generic_virtual_thunk (domain, old_thunk);
1663 mono_domain_unlock (domain);
1666 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1669 * mono_class_vtable:
1670 * @domain: the application domain
1671 * @class: the class to initialize
1673 * VTables are domain specific because we create domain specific code, and
1674 * they contain the domain specific static class data.
1675 * On failure, NULL is returned, and class->exception_type is set.
1678 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1680 return mono_class_vtable_full (domain, class, FALSE);
1684 * mono_class_vtable_full:
1685 * @domain: the application domain
1686 * @class: the class to initialize
1687 * @raise_on_error if an exception should be raised on failure or not
1689 * VTables are domain specific because we create domain specific code, and
1690 * they contain the domain specific static class data.
1693 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1695 MonoClassRuntimeInfo *runtime_info;
1699 if (class->exception_type) {
1701 mono_raise_exception (mono_class_get_exception_for_failure (class));
1705 /* this check can be inlined in jitted code, too */
1706 runtime_info = class->runtime_info;
1707 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1708 return runtime_info->domain_vtables [domain->domain_id];
1709 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1713 * mono_class_try_get_vtable:
1714 * @domain: the application domain
1715 * @class: the class to initialize
1717 * This function tries to get the associated vtable from @class if
1718 * it was already created.
1721 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1723 MonoClassRuntimeInfo *runtime_info;
1727 runtime_info = class->runtime_info;
1728 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1729 return runtime_info->domain_vtables [domain->domain_id];
1734 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1737 MonoClassRuntimeInfo *runtime_info, *old_info;
1738 MonoClassField *field;
1741 int imt_table_bytes = 0;
1742 guint32 vtable_size, class_size;
1745 gpointer *interface_offsets;
1747 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1748 mono_domain_lock (domain);
1749 runtime_info = class->runtime_info;
1750 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1751 mono_domain_unlock (domain);
1752 mono_loader_unlock ();
1753 return runtime_info->domain_vtables [domain->domain_id];
1755 if (!class->inited || class->exception_type) {
1756 if (!mono_class_init (class) || class->exception_type) {
1757 mono_domain_unlock (domain);
1758 mono_loader_unlock ();
1760 mono_raise_exception (mono_class_get_exception_for_failure (class));
1766 * For some classes, mono_class_init () already computed class->vtable_size, and
1767 * that is all that is needed because of the vtable trampolines.
1769 if (!class->vtable_size)
1770 mono_class_setup_vtable (class);
1772 if (class->exception_type) {
1773 mono_domain_unlock (domain);
1774 mono_loader_unlock ();
1776 mono_raise_exception (mono_class_get_exception_for_failure (class));
1781 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1782 if (class->interface_offsets_count) {
1783 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1784 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1785 mono_stats.imt_number_of_tables++;
1786 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1789 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1790 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1793 mono_stats.used_class_count++;
1794 mono_stats.class_vtable_size += vtable_size;
1795 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1798 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1800 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1802 vt->rank = class->rank;
1803 vt->domain = domain;
1805 mono_class_compute_gc_descriptor (class);
1807 * We can't use typed allocation in the non-root domains, since the
1808 * collector needs the GC descriptor stored in the vtable even after
1809 * the mempool containing the vtable is destroyed when the domain is
1810 * unloaded. An alternative might be to allocate vtables in the GC
1811 * heap, but this does not seem to work (it leads to crashes inside
1812 * libgc). If that approach is tried, two gc descriptors need to be
1813 * allocated for each class: one for the root domain, and one for all
1814 * other domains. The second descriptor should contain a bit for the
1815 * vtable field in MonoObject, since we can no longer assume the
1816 * vtable is reachable by other roots after the appdomain is unloaded.
1818 #ifdef HAVE_BOEHM_GC
1819 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1820 vt->gc_descr = GC_NO_DESCRIPTOR;
1823 vt->gc_descr = class->gc_descr;
1825 if ((class_size = mono_class_data_size (class))) {
1826 if (class->has_static_refs) {
1827 gpointer statics_gc_descr;
1829 gsize default_bitmap [4] = {0};
1832 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1833 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1834 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1835 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1836 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1837 if (bitmap != default_bitmap)
1840 vt->data = mono_domain_alloc0 (domain, class_size);
1842 mono_stats.class_static_data_size += class_size;
1847 while ((field = mono_class_get_fields (class, &iter))) {
1848 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1850 if (mono_field_is_deleted (field))
1852 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1853 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1854 if (special_static != SPECIAL_STATIC_NONE) {
1855 guint32 size, offset;
1857 size = mono_type_size (field->type, &align);
1858 offset = mono_alloc_special_static_data (special_static, size, align);
1859 if (!domain->special_static_fields)
1860 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1861 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1863 * This marks the field as special static to speed up the
1864 * checks in mono_field_static_get/set_value ().
1870 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1871 MonoClass *fklass = mono_class_from_mono_type (field->type);
1872 const char *data = mono_field_get_data (field);
1874 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1875 t = (char*)vt->data + field->offset;
1876 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1879 if (fklass->valuetype) {
1880 memcpy (t, data, mono_class_value_size (fklass, NULL));
1882 /* it's a pointer type: add check */
1883 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1890 vt->max_interface_id = class->max_interface_id;
1891 vt->interface_bitmap = class->interface_bitmap;
1893 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1894 // class->name, class->interface_offsets_count);
1896 if (! ARCH_USE_IMT) {
1897 /* initialize interface offsets */
1898 for (i = 0; i < class->interface_offsets_count; ++i) {
1899 int interface_id = class->interfaces_packed [i]->interface_id;
1900 int slot = class->interface_offsets_packed [i];
1901 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1905 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1906 * as we change the code in appdomain.c to invalidate vtables by
1907 * looking at the possible MonoClasses created for the domain.
1909 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1910 /* class->runtime_info is protected by the loader lock, both when
1911 * it it enlarged and when it is stored info.
1914 old_info = class->runtime_info;
1915 if (old_info && old_info->max_domain >= domain->domain_id) {
1916 /* someone already created a large enough runtime info */
1917 mono_memory_barrier ();
1918 old_info->domain_vtables [domain->domain_id] = vt;
1920 int new_size = domain->domain_id;
1922 new_size = MAX (new_size, old_info->max_domain);
1924 /* make the new size a power of two */
1926 while (new_size > i)
1929 /* this is a bounded memory retention issue: may want to
1930 * handle it differently when we'll have a rcu-like system.
1932 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1933 runtime_info->max_domain = new_size - 1;
1934 /* copy the stuff from the older info */
1936 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1938 runtime_info->domain_vtables [domain->domain_id] = vt;
1940 mono_memory_barrier ();
1941 class->runtime_info = runtime_info;
1944 /* Initialize vtable */
1945 if (vtable_trampoline) {
1946 // This also covers the AOT case
1947 for (i = 0; i < class->vtable_size; ++i) {
1948 vt->vtable [i] = vtable_trampoline;
1951 mono_class_setup_vtable (class);
1953 for (i = 0; i < class->vtable_size; ++i) {
1956 if ((cm = class->vtable [i]))
1957 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1961 if (ARCH_USE_IMT && imt_table_bytes) {
1962 /* Now that the vtable is full, we can actually fill up the IMT */
1963 if (imt_trampoline) {
1964 /* lazy construction of the IMT entries enabled */
1965 for (i = 0; i < MONO_IMT_SIZE; ++i)
1966 interface_offsets [i] = imt_trampoline;
1968 build_imt (class, vt, domain, interface_offsets, NULL);
1972 mono_domain_unlock (domain);
1973 mono_loader_unlock ();
1975 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1976 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
1977 mono_raise_exception (mono_class_get_exception_for_failure (class));
1979 /* make sure the parent is initialized */
1980 /*FIXME shouldn't this fail the current type?*/
1982 mono_class_vtable_full (domain, class->parent, raise_on_error);
1984 /*FIXME check for OOM*/
1985 vt->type = mono_type_get_object (domain, &class->byval_arg);
1986 if (class->contextbound)
1995 * mono_class_proxy_vtable:
1996 * @domain: the application domain
1997 * @remove_class: the remote class
1999 * Creates a vtable for transparent proxies. It is basically
2000 * a copy of the real vtable of the class wrapped in @remote_class,
2001 * but all function pointers invoke the remoting functions, and
2002 * vtable->klass points to the transparent proxy class, and not to @class.
2005 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2007 MonoVTable *vt, *pvt;
2008 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2010 GSList *extra_interfaces = NULL;
2011 MonoClass *class = remote_class->proxy_class;
2012 gpointer *interface_offsets;
2014 vt = mono_class_vtable (domain, class);
2015 g_assert (vt); /*FIXME property handle failure*/
2016 max_interface_id = vt->max_interface_id;
2018 /* Calculate vtable space for extra interfaces */
2019 for (j = 0; j < remote_class->interface_count; j++) {
2020 MonoClass* iclass = remote_class->interfaces[j];
2024 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2025 continue; /* interface implemented by the class */
2026 if (g_slist_find (extra_interfaces, iclass))
2029 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2031 method_count = mono_class_num_methods (iclass);
2033 ifaces = mono_class_get_implemented_interfaces (iclass);
2035 for (i = 0; i < ifaces->len; ++i) {
2036 MonoClass *ic = g_ptr_array_index (ifaces, i);
2037 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2038 continue; /* interface implemented by the class */
2039 if (g_slist_find (extra_interfaces, ic))
2041 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2042 method_count += mono_class_num_methods (ic);
2044 g_ptr_array_free (ifaces, TRUE);
2047 extra_interface_vtsize += method_count * sizeof (gpointer);
2048 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2052 mono_stats.imt_number_of_tables++;
2053 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2054 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2055 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2057 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2058 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2061 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2063 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2065 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2067 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2068 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2070 pvt->klass = mono_defaults.transparent_proxy_class;
2071 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2072 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2074 /* initialize vtable */
2075 mono_class_setup_vtable (class);
2076 for (i = 0; i < class->vtable_size; ++i) {
2079 if ((cm = class->vtable [i]))
2080 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2082 pvt->vtable [i] = NULL;
2085 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2086 /* create trampolines for abstract methods */
2087 for (k = class; k; k = k->parent) {
2089 gpointer iter = NULL;
2090 while ((m = mono_class_get_methods (k, &iter)))
2091 if (!pvt->vtable [m->slot])
2092 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2096 pvt->max_interface_id = max_interface_id;
2097 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2099 if (! ARCH_USE_IMT) {
2100 /* initialize interface offsets */
2101 for (i = 0; i < class->interface_offsets_count; ++i) {
2102 int interface_id = class->interfaces_packed [i]->interface_id;
2103 int slot = class->interface_offsets_packed [i];
2104 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2107 for (i = 0; i < class->interface_offsets_count; ++i) {
2108 int interface_id = class->interfaces_packed [i]->interface_id;
2109 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2112 if (extra_interfaces) {
2113 int slot = class->vtable_size;
2119 /* Create trampolines for the methods of the interfaces */
2120 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2121 interf = list_item->data;
2123 if (! ARCH_USE_IMT) {
2124 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2126 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2130 while ((cm = mono_class_get_methods (interf, &iter)))
2131 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2133 slot += mono_class_num_methods (interf);
2135 if (! ARCH_USE_IMT) {
2136 g_slist_free (extra_interfaces);
2141 /* Now that the vtable is full, we can actually fill up the IMT */
2142 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2143 if (extra_interfaces) {
2144 g_slist_free (extra_interfaces);
2152 * mono_class_field_is_special_static:
2154 * Returns whether @field is a thread/context static field.
2157 mono_class_field_is_special_static (MonoClassField *field)
2159 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2161 if (mono_field_is_deleted (field))
2163 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2164 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2171 * mono_class_has_special_static_fields:
2173 * Returns whenever @klass has any thread/context static fields.
2176 mono_class_has_special_static_fields (MonoClass *klass)
2178 MonoClassField *field;
2182 while ((field = mono_class_get_fields (klass, &iter))) {
2183 g_assert (field->parent == klass);
2184 if (mono_class_field_is_special_static (field))
2192 * create_remote_class_key:
2193 * Creates an array of pointers that can be used as a hash key for a remote class.
2194 * The first element of the array is the number of pointers.
2197 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2202 if (remote_class == NULL) {
2203 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2204 key = g_malloc (sizeof(gpointer) * 3);
2205 key [0] = GINT_TO_POINTER (2);
2206 key [1] = mono_defaults.marshalbyrefobject_class;
2207 key [2] = extra_class;
2209 key = g_malloc (sizeof(gpointer) * 2);
2210 key [0] = GINT_TO_POINTER (1);
2211 key [1] = extra_class;
2214 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2215 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2216 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2217 key [1] = remote_class->proxy_class;
2219 // Keep the list of interfaces sorted
2220 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2221 if (extra_class && remote_class->interfaces [i] > extra_class) {
2222 key [j++] = extra_class;
2225 key [j] = remote_class->interfaces [i];
2228 key [j] = extra_class;
2230 // Replace the old class. The interface list is the same
2231 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2232 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2233 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2234 for (i = 0; i < remote_class->interface_count; i++)
2235 key [2 + i] = remote_class->interfaces [i];
2243 * copy_remote_class_key:
2245 * Make a copy of KEY in the domain and return the copy.
2248 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2250 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2251 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2253 memcpy (mp_key, key, key_size);
2259 * mono_remote_class:
2260 * @domain: the application domain
2261 * @class_name: name of the remote class
2263 * Creates and initializes a MonoRemoteClass object for a remote type.
2267 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2269 MonoRemoteClass *rc;
2270 gpointer* key, *mp_key;
2272 key = create_remote_class_key (NULL, proxy_class);
2274 mono_domain_lock (domain);
2275 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2279 mono_domain_unlock (domain);
2283 mp_key = copy_remote_class_key (domain, key);
2287 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2288 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2289 rc->interface_count = 1;
2290 rc->interfaces [0] = proxy_class;
2291 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2293 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2294 rc->interface_count = 0;
2295 rc->proxy_class = proxy_class;
2298 rc->default_vtable = NULL;
2299 rc->xdomain_vtable = NULL;
2300 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2301 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2303 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2305 mono_domain_unlock (domain);
2310 * clone_remote_class:
2311 * Creates a copy of the remote_class, adding the provided class or interface
2313 static MonoRemoteClass*
2314 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2316 MonoRemoteClass *rc;
2317 gpointer* key, *mp_key;
2319 key = create_remote_class_key (remote_class, extra_class);
2320 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2326 mp_key = copy_remote_class_key (domain, key);
2330 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2332 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2333 rc->proxy_class = remote_class->proxy_class;
2334 rc->interface_count = remote_class->interface_count + 1;
2336 // Keep the list of interfaces sorted, since the hash key of
2337 // the remote class depends on this
2338 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2339 if (remote_class->interfaces [i] > extra_class && i == j)
2340 rc->interfaces [j++] = extra_class;
2341 rc->interfaces [j] = remote_class->interfaces [i];
2344 rc->interfaces [j] = extra_class;
2346 // Replace the old class. The interface array is the same
2347 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2348 rc->proxy_class = extra_class;
2349 rc->interface_count = remote_class->interface_count;
2350 if (rc->interface_count > 0)
2351 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2354 rc->default_vtable = NULL;
2355 rc->xdomain_vtable = NULL;
2356 rc->proxy_class_name = remote_class->proxy_class_name;
2358 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2364 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2366 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2367 mono_domain_lock (domain);
2368 if (rp->target_domain_id != -1) {
2369 if (remote_class->xdomain_vtable == NULL)
2370 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2371 mono_domain_unlock (domain);
2372 mono_loader_unlock ();
2373 return remote_class->xdomain_vtable;
2375 if (remote_class->default_vtable == NULL) {
2378 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2379 klass = mono_class_from_mono_type (type);
2380 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2381 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2383 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2386 mono_domain_unlock (domain);
2387 mono_loader_unlock ();
2388 return remote_class->default_vtable;
2392 * mono_upgrade_remote_class:
2393 * @domain: the application domain
2394 * @tproxy: the proxy whose remote class has to be upgraded.
2395 * @klass: class to which the remote class can be casted.
2397 * Updates the vtable of the remote class by adding the necessary method slots
2398 * and interface offsets so it can be safely casted to klass. klass can be a
2399 * class or an interface.
2402 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2404 MonoTransparentProxy *tproxy;
2405 MonoRemoteClass *remote_class;
2406 gboolean redo_vtable;
2408 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2409 mono_domain_lock (domain);
2411 tproxy = (MonoTransparentProxy*) proxy_object;
2412 remote_class = tproxy->remote_class;
2414 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2417 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2418 if (remote_class->interfaces [i] == klass)
2419 redo_vtable = FALSE;
2422 redo_vtable = (remote_class->proxy_class != klass);
2426 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2427 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2430 mono_domain_unlock (domain);
2431 mono_loader_unlock ();
2436 * mono_object_get_virtual_method:
2437 * @obj: object to operate on.
2440 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2441 * the instance of a callvirt of method.
2444 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2447 MonoMethod **vtable;
2449 MonoMethod *res = NULL;
2451 klass = mono_object_class (obj);
2452 if (klass == mono_defaults.transparent_proxy_class) {
2453 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2459 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2462 mono_class_setup_vtable (klass);
2463 vtable = klass->vtable;
2465 if (method->slot == -1) {
2466 /* method->slot might not be set for instances of generic methods */
2467 if (method->is_inflated) {
2468 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2469 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2472 g_assert_not_reached ();
2476 /* check method->slot is a valid index: perform isinstance? */
2477 if (method->slot != -1) {
2478 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2480 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2482 res = vtable [method->slot];
2487 /* It may be an interface, abstract class method or generic method */
2488 if (!res || mono_method_signature (res)->generic_param_count)
2491 /* generic methods demand invoke_with_check */
2492 if (mono_method_signature (res)->generic_param_count)
2493 res = mono_marshal_get_remoting_invoke_with_check (res);
2496 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2497 res = mono_cominterop_get_invoke (res);
2500 res = mono_marshal_get_remoting_invoke (res);
2503 if (method->is_inflated) {
2504 /* Have to inflate the result */
2505 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2515 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2517 g_error ("runtime invoke called on uninitialized runtime");
2521 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2524 * mono_runtime_invoke:
2525 * @method: method to invoke
2526 * @obJ: object instance
2527 * @params: arguments to the method
2528 * @exc: exception information.
2530 * Invokes the method represented by @method on the object @obj.
2532 * obj is the 'this' pointer, it should be NULL for static
2533 * methods, a MonoObject* for object instances and a pointer to
2534 * the value type for value types.
2536 * The params array contains the arguments to the method with the
2537 * same convention: MonoObject* pointers for object instances and
2538 * pointers to the value type otherwise.
2540 * From unmanaged code you'll usually use the
2541 * mono_runtime_invoke() variant.
2543 * Note that this function doesn't handle virtual methods for
2544 * you, it will exec the exact method you pass: we still need to
2545 * expose a function to lookup the derived class implementation
2546 * of a virtual method (there are examples of this in the code,
2549 * You can pass NULL as the exc argument if you don't want to
2550 * catch exceptions, otherwise, *exc will be set to the exception
2551 * thrown, if any. if an exception is thrown, you can't use the
2552 * MonoObject* result from the function.
2554 * If the method returns a value type, it is boxed in an object
2558 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2560 if (mono_runtime_get_no_exec ())
2561 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2563 return default_mono_runtime_invoke (method, obj, params, exc);
2567 * mono_method_get_unmanaged_thunk:
2568 * @method: method to generate a thunk for.
2570 * Returns an unmanaged->managed thunk that can be used to call
2571 * a managed method directly from C.
2573 * The thunk's C signature closely matches the managed signature:
2575 * C#: public bool Equals (object obj);
2576 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2577 * MonoObject*, MonoException**);
2579 * The 1st ("this") parameter must not be used with static methods:
2581 * C#: public static bool ReferenceEquals (object a, object b);
2582 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2585 * The last argument must be a non-null pointer of a MonoException* pointer.
2586 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2587 * exception has been thrown in managed code. Otherwise it will point
2588 * to the MonoException* caught by the thunk. In this case, the result of
2589 * the thunk is undefined:
2591 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2592 * MonoException *ex = NULL;
2593 * Equals func = mono_method_get_unmanaged_thunk (method);
2594 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2596 * // handle exception
2599 * The calling convention of the thunk matches the platform's default
2600 * convention. This means that under Windows, C declarations must
2601 * contain the __stdcall attribute:
2603 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2604 * MonoObject*, MonoException**);
2608 * Value type arguments and return values are treated as they were objects:
2610 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2611 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2613 * Arguments must be properly boxed upon trunk's invocation, while return
2614 * values must be unboxed.
2617 mono_method_get_unmanaged_thunk (MonoMethod *method)
2619 method = mono_marshal_get_thunk_invoke_wrapper (method);
2620 return mono_compile_method (method);
2624 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2628 /* object fields cannot be byref, so we don't need a
2630 gpointer *p = (gpointer*)dest;
2637 case MONO_TYPE_BOOLEAN:
2639 case MONO_TYPE_U1: {
2640 guint8 *p = (guint8*)dest;
2641 *p = value ? *(guint8*)value : 0;
2646 case MONO_TYPE_CHAR: {
2647 guint16 *p = (guint16*)dest;
2648 *p = value ? *(guint16*)value : 0;
2651 #if SIZEOF_VOID_P == 4
2656 case MONO_TYPE_U4: {
2657 gint32 *p = (gint32*)dest;
2658 *p = value ? *(gint32*)value : 0;
2661 #if SIZEOF_VOID_P == 8
2666 case MONO_TYPE_U8: {
2667 gint64 *p = (gint64*)dest;
2668 *p = value ? *(gint64*)value : 0;
2671 case MONO_TYPE_R4: {
2672 float *p = (float*)dest;
2673 *p = value ? *(float*)value : 0;
2676 case MONO_TYPE_R8: {
2677 double *p = (double*)dest;
2678 *p = value ? *(double*)value : 0;
2681 case MONO_TYPE_STRING:
2682 case MONO_TYPE_SZARRAY:
2683 case MONO_TYPE_CLASS:
2684 case MONO_TYPE_OBJECT:
2685 case MONO_TYPE_ARRAY:
2686 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2688 case MONO_TYPE_FNPTR:
2689 case MONO_TYPE_PTR: {
2690 gpointer *p = (gpointer*)dest;
2691 *p = deref_pointer? *(gpointer*)value: value;
2694 case MONO_TYPE_VALUETYPE:
2695 /* note that 't' and 'type->type' can be different */
2696 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2697 t = mono_class_enum_basetype (type->data.klass)->type;
2700 MonoClass *class = mono_class_from_mono_type (type);
2701 int size = mono_class_value_size (class, NULL);
2702 if (value == NULL) {
2703 memset (dest, 0, size);
2705 memcpy (dest, value, size);
2706 mono_gc_wbarrier_value_copy (dest, value, size, class);
2710 case MONO_TYPE_GENERICINST:
2711 t = type->data.generic_class->container_class->byval_arg.type;
2714 g_warning ("got type %x", type->type);
2715 g_assert_not_reached ();
2720 * mono_field_set_value:
2721 * @obj: Instance object
2722 * @field: MonoClassField describing the field to set
2723 * @value: The value to be set
2725 * Sets the value of the field described by @field in the object instance @obj
2726 * to the value passed in @value. This method should only be used for instance
2727 * fields. For static fields, use mono_field_static_set_value.
2729 * The value must be on the native format of the field type.
2732 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2736 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2738 dest = (char*)obj + field->offset;
2739 set_value (field->type, dest, value, FALSE);
2743 * mono_field_static_set_value:
2744 * @field: MonoClassField describing the field to set
2745 * @value: The value to be set
2747 * Sets the value of the static field described by @field
2748 * to the value passed in @value.
2750 * The value must be on the native format of the field type.
2753 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2757 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2758 /* you cant set a constant! */
2759 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2761 if (field->offset == -1) {
2762 /* Special static */
2763 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2764 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2766 dest = (char*)vt->data + field->offset;
2768 set_value (field->type, dest, value, FALSE);
2771 /* Used by the debugger */
2773 mono_vtable_get_static_field_data (MonoVTable *vt)
2779 * mono_field_get_value:
2780 * @obj: Object instance
2781 * @field: MonoClassField describing the field to fetch information from
2782 * @value: pointer to the location where the value will be stored
2784 * Use this routine to get the value of the field @field in the object
2787 * The pointer provided by value must be of the field type, for reference
2788 * types this is a MonoObject*, for value types its the actual pointer to
2793 * mono_field_get_value (obj, int_field, &i);
2796 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2800 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2802 src = (char*)obj + field->offset;
2803 set_value (field->type, value, src, TRUE);
2807 * mono_field_get_value_object:
2808 * @domain: domain where the object will be created (if boxing)
2809 * @field: MonoClassField describing the field to fetch information from
2810 * @obj: The object instance for the field.
2812 * Returns: a new MonoObject with the value from the given field. If the
2813 * field represents a value type, the value is boxed.
2817 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2821 MonoVTable *vtable = NULL;
2823 gboolean is_static = FALSE;
2824 gboolean is_ref = FALSE;
2826 switch (field->type->type) {
2827 case MONO_TYPE_STRING:
2828 case MONO_TYPE_OBJECT:
2829 case MONO_TYPE_CLASS:
2830 case MONO_TYPE_ARRAY:
2831 case MONO_TYPE_SZARRAY:
2836 case MONO_TYPE_BOOLEAN:
2839 case MONO_TYPE_CHAR:
2848 case MONO_TYPE_VALUETYPE:
2849 is_ref = field->type->byref;
2851 case MONO_TYPE_GENERICINST:
2852 is_ref = !field->type->data.generic_class->container_class->valuetype;
2855 g_error ("type 0x%x not handled in "
2856 "mono_field_get_value_object", field->type->type);
2860 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2862 vtable = mono_class_vtable (domain, field->parent);
2864 char *name = mono_type_get_full_name (field->parent);
2865 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2869 if (!vtable->initialized)
2870 mono_runtime_class_init (vtable);
2875 mono_field_static_get_value (vtable, field, &o);
2877 mono_field_get_value (obj, field, &o);
2882 /* boxed value type */
2883 klass = mono_class_from_mono_type (field->type);
2884 o = mono_object_new (domain, klass);
2885 v = ((gchar *) o) + sizeof (MonoObject);
2887 mono_field_static_get_value (vtable, field, v);
2889 mono_field_get_value (obj, field, v);
2896 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2899 const char *p = blob;
2900 mono_metadata_decode_blob_size (p, &p);
2903 case MONO_TYPE_BOOLEAN:
2906 *(guint8 *) value = *p;
2908 case MONO_TYPE_CHAR:
2911 *(guint16*) value = read16 (p);
2915 *(guint32*) value = read32 (p);
2919 *(guint64*) value = read64 (p);
2922 readr4 (p, (float*) value);
2925 readr8 (p, (double*) value);
2927 case MONO_TYPE_STRING:
2928 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2930 case MONO_TYPE_CLASS:
2931 *(gpointer*) value = NULL;
2935 g_warning ("type 0x%02x should not be in constant table", type);
2941 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2943 MonoTypeEnum def_type;
2946 data = mono_class_get_field_default_value (field, &def_type);
2947 mono_get_constant_value_from_blob (domain, def_type, data, value);
2951 * mono_field_static_get_value:
2952 * @vt: vtable to the object
2953 * @field: MonoClassField describing the field to fetch information from
2954 * @value: where the value is returned
2956 * Use this routine to get the value of the static field @field value.
2958 * The pointer provided by value must be of the field type, for reference
2959 * types this is a MonoObject*, for value types its the actual pointer to
2964 * mono_field_static_get_value (vt, int_field, &i);
2967 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2971 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2973 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2974 get_default_field_value (vt->domain, field, value);
2978 if (field->offset == -1) {
2979 /* Special static */
2980 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2981 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2983 src = (char*)vt->data + field->offset;
2985 set_value (field->type, value, src, TRUE);
2989 * mono_property_set_value:
2990 * @prop: MonoProperty to set
2991 * @obj: instance object on which to act
2992 * @params: parameters to pass to the propery
2993 * @exc: optional exception
2995 * Invokes the property's set method with the given arguments on the
2996 * object instance obj (or NULL for static properties).
2998 * You can pass NULL as the exc argument if you don't want to
2999 * catch exceptions, otherwise, *exc will be set to the exception
3000 * thrown, if any. if an exception is thrown, you can't use the
3001 * MonoObject* result from the function.
3004 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3006 default_mono_runtime_invoke (prop->set, obj, params, exc);
3010 * mono_property_get_value:
3011 * @prop: MonoProperty to fetch
3012 * @obj: instance object on which to act
3013 * @params: parameters to pass to the propery
3014 * @exc: optional exception
3016 * Invokes the property's get method with the given arguments on the
3017 * object instance obj (or NULL for static properties).
3019 * You can pass NULL as the exc argument if you don't want to
3020 * catch exceptions, otherwise, *exc will be set to the exception
3021 * thrown, if any. if an exception is thrown, you can't use the
3022 * MonoObject* result from the function.
3024 * Returns: the value from invoking the get method on the property.
3027 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3029 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3033 * mono_nullable_init:
3034 * @buf: The nullable structure to initialize.
3035 * @value: the value to initialize from
3036 * @klass: the type for the object
3038 * Initialize the nullable structure pointed to by @buf from @value which
3039 * should be a boxed value type. The size of @buf should be able to hold
3040 * as much data as the @klass->instance_size (which is the number of bytes
3041 * that will be copies).
3043 * Since Nullables have variable structure, we can not define a C
3044 * structure for them.
3047 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3049 MonoClass *param_class = klass->cast_class;
3051 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3052 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3054 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3056 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3058 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3062 * mono_nullable_box:
3063 * @buf: The buffer representing the data to be boxed
3064 * @klass: the type to box it as.
3066 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3070 mono_nullable_box (guint8 *buf, MonoClass *klass)
3072 MonoClass *param_class = klass->cast_class;
3074 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3075 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3077 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3078 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3079 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3087 * mono_get_delegate_invoke:
3088 * @klass: The delegate class
3090 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3093 mono_get_delegate_invoke (MonoClass *klass)
3097 /* This is called at runtime, so avoid the slower search in metadata */
3098 mono_class_setup_methods (klass);
3100 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3107 * mono_runtime_delegate_invoke:
3108 * @delegate: pointer to a delegate object.
3109 * @params: parameters for the delegate.
3110 * @exc: Pointer to the exception result.
3112 * Invokes the delegate method @delegate with the parameters provided.
3114 * You can pass NULL as the exc argument if you don't want to
3115 * catch exceptions, otherwise, *exc will be set to the exception
3116 * thrown, if any. if an exception is thrown, you can't use the
3117 * MonoObject* result from the function.
3120 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3124 im = mono_get_delegate_invoke (delegate->vtable->klass);
3127 return mono_runtime_invoke (im, delegate, params, exc);
3130 static char **main_args = NULL;
3131 static int num_main_args;
3134 * mono_runtime_get_main_args:
3136 * Returns: a MonoArray with the arguments passed to the main program
3139 mono_runtime_get_main_args (void)
3143 MonoDomain *domain = mono_domain_get ();
3148 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3150 for (i = 0; i < num_main_args; ++i)
3151 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3157 fire_process_exit_event (void)
3159 MonoClassField *field;
3160 MonoDomain *domain = mono_domain_get ();
3162 MonoObject *delegate, *exc;
3164 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3167 if (domain != mono_get_root_domain ())
3170 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3171 if (delegate == NULL)
3176 mono_runtime_delegate_invoke (delegate, pa, &exc);
3180 * mono_runtime_run_main:
3181 * @method: the method to start the application with (usually Main)
3182 * @argc: number of arguments from the command line
3183 * @argv: array of strings from the command line
3184 * @exc: excetption results
3186 * Execute a standard Main() method (argc/argv contains the
3187 * executable name). This method also sets the command line argument value
3188 * needed by System.Environment.
3193 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3197 MonoArray *args = NULL;
3198 MonoDomain *domain = mono_domain_get ();
3199 gchar *utf8_fullpath;
3202 g_assert (method != NULL);
3204 mono_thread_set_main (mono_thread_current ());
3206 main_args = g_new0 (char*, argc);
3207 num_main_args = argc;
3209 if (!g_path_is_absolute (argv [0])) {
3210 gchar *basename = g_path_get_basename (argv [0]);
3211 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3215 utf8_fullpath = mono_utf8_from_external (fullpath);
3216 if(utf8_fullpath == NULL) {
3217 /* Printing the arg text will cause glib to
3218 * whinge about "Invalid UTF-8", but at least
3219 * its relevant, and shows the problem text
3222 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3223 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3230 utf8_fullpath = mono_utf8_from_external (argv[0]);
3231 if(utf8_fullpath == NULL) {
3232 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3233 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3238 main_args [0] = utf8_fullpath;
3240 for (i = 1; i < argc; ++i) {
3243 utf8_arg=mono_utf8_from_external (argv[i]);
3244 if(utf8_arg==NULL) {
3245 /* Ditto the comment about Invalid UTF-8 here */
3246 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3247 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3251 main_args [i] = utf8_arg;
3255 if (mono_method_signature (method)->param_count) {
3256 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3257 for (i = 0; i < argc; ++i) {
3258 /* The encodings should all work, given that
3259 * we've checked all these args for the
3262 gchar *str = mono_utf8_from_external (argv [i]);
3263 MonoString *arg = mono_string_new (domain, str);
3264 mono_array_setref (args, i, arg);
3268 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3271 mono_assembly_set_main (method->klass->image->assembly);
3273 result = mono_runtime_exec_main (method, args, exc);
3274 fire_process_exit_event ();
3278 /* Used in call_unhandled_exception_delegate */
3280 create_unhandled_exception_eventargs (MonoObject *exc)
3284 MonoMethod *method = NULL;
3285 MonoBoolean is_terminating = TRUE;
3288 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3291 mono_class_init (klass);
3293 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3294 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3298 args [1] = &is_terminating;
3300 obj = mono_object_new (mono_domain_get (), klass);
3301 mono_runtime_invoke (method, obj, args, NULL);
3306 /* Used in mono_unhandled_exception */
3308 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3309 MonoObject *e = NULL;
3312 pa [0] = domain->domain;
3313 pa [1] = create_unhandled_exception_eventargs (exc);
3314 mono_runtime_delegate_invoke (delegate, pa, &e);
3317 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3318 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3323 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3326 * mono_runtime_unhandled_exception_policy_set:
3327 * @policy: the new policy
3329 * This is a VM internal routine.
3331 * Sets the runtime policy for handling unhandled exceptions.
3334 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3335 runtime_unhandled_exception_policy = policy;
3339 * mono_runtime_unhandled_exception_policy_get:
3341 * This is a VM internal routine.
3343 * Gets the runtime policy for handling unhandled exceptions.
3345 MonoRuntimeUnhandledExceptionPolicy
3346 mono_runtime_unhandled_exception_policy_get (void) {
3347 return runtime_unhandled_exception_policy;
3351 * mono_unhandled_exception:
3352 * @exc: exception thrown
3354 * This is a VM internal routine.
3356 * We call this function when we detect an unhandled exception
3357 * in the default domain.
3359 * It invokes the * UnhandledException event in AppDomain or prints
3360 * a warning to the console
3363 mono_unhandled_exception (MonoObject *exc)
3365 MonoDomain *current_domain = mono_domain_get ();
3366 MonoDomain *root_domain = mono_get_root_domain ();
3367 MonoClassField *field;
3368 MonoObject *current_appdomain_delegate;
3369 MonoObject *root_appdomain_delegate;
3371 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3372 "UnhandledException");
3375 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3376 gboolean abort_process = (mono_thread_current () == main_thread) ||
3377 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3378 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3379 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3380 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3382 current_appdomain_delegate = NULL;
3385 /* set exitcode only if we will abort the process */
3387 mono_environment_exitcode_set (1);
3388 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3389 mono_print_unhandled_exception (exc);
3391 if (root_appdomain_delegate) {
3392 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3394 if (current_appdomain_delegate) {
3395 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3402 * Launch a new thread to execute a function
3404 * main_func is called back from the thread with main_args as the
3405 * parameter. The callback function is expected to start Main()
3406 * eventually. This function then waits for all managed threads to
3408 * It is not necesseray anymore to execute managed code in a subthread,
3409 * so this function should not be used anymore by default: just
3410 * execute the code and then call mono_thread_manage ().
3413 mono_runtime_exec_managed_code (MonoDomain *domain,
3414 MonoMainThreadFunc main_func,
3417 mono_thread_create (domain, main_func, main_args);
3419 mono_thread_manage ();
3423 * Execute a standard Main() method (args doesn't contain the
3427 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3432 MonoCustomAttrInfo* cinfo;
3433 gboolean has_stathread_attribute;
3434 MonoThread* thread = mono_thread_current ();
3440 domain = mono_object_domain (args);
3441 if (!domain->entry_assembly) {
3443 MonoAssembly *assembly;
3445 assembly = method->klass->image->assembly;
3446 domain->entry_assembly = assembly;
3447 /* Domains created from another domain already have application_base and configuration_file set */
3448 if (domain->setup->application_base == NULL) {
3449 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3452 if (domain->setup->configuration_file == NULL) {
3453 str = g_strconcat (assembly->image->name, ".config", NULL);
3454 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3456 mono_set_private_bin_path_from_config (domain);
3460 cinfo = mono_custom_attrs_from_method (method);
3462 static MonoClass *stathread_attribute = NULL;
3463 if (!stathread_attribute)
3464 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3465 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3467 mono_custom_attrs_free (cinfo);
3469 has_stathread_attribute = FALSE;
3471 if (has_stathread_attribute) {
3472 thread->apartment_state = ThreadApartmentState_STA;
3473 } else if (mono_framework_version () == 1) {
3474 thread->apartment_state = ThreadApartmentState_Unknown;
3476 thread->apartment_state = ThreadApartmentState_MTA;
3478 mono_thread_init_apartment_state ();
3480 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3482 /* FIXME: check signature of method */
3483 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3485 res = mono_runtime_invoke (method, NULL, pa, exc);
3487 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3491 mono_environment_exitcode_set (rval);
3493 mono_runtime_invoke (method, NULL, pa, exc);
3497 /* If the return type of Main is void, only
3498 * set the exitcode if an exception was thrown
3499 * (we don't want to blow away an
3500 * explicitly-set exit code)
3503 mono_environment_exitcode_set (rval);
3507 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3513 * mono_install_runtime_invoke:
3514 * @func: Function to install
3516 * This is a VM internal routine
3519 mono_install_runtime_invoke (MonoInvokeFunc func)
3521 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3526 * mono_runtime_invoke_array:
3527 * @method: method to invoke
3528 * @obJ: object instance
3529 * @params: arguments to the method
3530 * @exc: exception information.
3532 * Invokes the method represented by @method on the object @obj.
3534 * obj is the 'this' pointer, it should be NULL for static
3535 * methods, a MonoObject* for object instances and a pointer to
3536 * the value type for value types.
3538 * The params array contains the arguments to the method with the
3539 * same convention: MonoObject* pointers for object instances and
3540 * pointers to the value type otherwise. The _invoke_array
3541 * variant takes a C# object[] as the params argument (MonoArray
3542 * *params): in this case the value types are boxed inside the
3543 * respective reference representation.
3545 * From unmanaged code you'll usually use the
3546 * mono_runtime_invoke() variant.
3548 * Note that this function doesn't handle virtual methods for
3549 * you, it will exec the exact method you pass: we still need to
3550 * expose a function to lookup the derived class implementation
3551 * of a virtual method (there are examples of this in the code,
3554 * You can pass NULL as the exc argument if you don't want to
3555 * catch exceptions, otherwise, *exc will be set to the exception
3556 * thrown, if any. if an exception is thrown, you can't use the
3557 * MonoObject* result from the function.
3559 * If the method returns a value type, it is boxed in an object
3563 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3566 MonoMethodSignature *sig = mono_method_signature (method);
3567 gpointer *pa = NULL;
3570 gboolean has_byref_nullables = FALSE;
3572 if (NULL != params) {
3573 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3574 for (i = 0; i < mono_array_length (params); i++) {
3575 MonoType *t = sig->params [i];
3581 case MONO_TYPE_BOOLEAN:
3584 case MONO_TYPE_CHAR:
3593 case MONO_TYPE_VALUETYPE:
3594 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3595 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3596 pa [i] = mono_array_get (params, MonoObject*, i);
3598 has_byref_nullables = TRUE;
3600 /* MS seems to create the objects if a null is passed in */
3601 if (!mono_array_get (params, MonoObject*, i))
3602 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3606 * We can't pass the unboxed vtype byref to the callee, since
3607 * that would mean the callee would be able to modify boxed
3608 * primitive types. So we (and MS) make a copy of the boxed
3609 * object, pass that to the callee, and replace the original
3610 * boxed object in the arg array with the copy.
3612 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3613 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3614 mono_array_setref (params, i, copy);
3617 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3620 case MONO_TYPE_STRING:
3621 case MONO_TYPE_OBJECT:
3622 case MONO_TYPE_CLASS:
3623 case MONO_TYPE_ARRAY:
3624 case MONO_TYPE_SZARRAY:
3626 pa [i] = mono_array_addr (params, MonoObject*, i);
3627 // FIXME: I need to check this code path
3629 pa [i] = mono_array_get (params, MonoObject*, i);
3631 case MONO_TYPE_GENERICINST:
3633 t = &t->data.generic_class->container_class->this_arg;
3635 t = &t->data.generic_class->container_class->byval_arg;
3637 case MONO_TYPE_PTR: {
3640 /* The argument should be an IntPtr */
3641 arg = mono_array_get (params, MonoObject*, i);
3645 g_assert (arg->vtable->klass == mono_defaults.int_class);
3646 pa [i] = ((MonoIntPtr*)arg)->m_value;
3651 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3656 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3659 if (mono_class_is_nullable (method->klass)) {
3660 /* Need to create a boxed vtype instead */
3666 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3670 obj = mono_object_new (mono_domain_get (), method->klass);
3671 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3672 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3674 if (method->klass->valuetype)
3675 o = mono_object_unbox (obj);
3678 } else if (method->klass->valuetype) {
3679 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3682 mono_runtime_invoke (method, o, pa, exc);
3685 if (mono_class_is_nullable (method->klass)) {
3686 MonoObject *nullable;
3688 /* Convert the unboxed vtype into a Nullable structure */
3689 nullable = mono_object_new (mono_domain_get (), method->klass);
3691 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3692 obj = mono_object_unbox (nullable);
3695 /* obj must be already unboxed if needed */
3696 res = mono_runtime_invoke (method, obj, pa, exc);
3698 if (sig->ret->type == MONO_TYPE_PTR) {
3699 MonoClass *pointer_class;
3700 static MonoMethod *box_method;
3702 MonoObject *box_exc;
3705 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3706 * convert it to a Pointer object.
3708 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3710 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3712 g_assert (res->vtable->klass == mono_defaults.int_class);
3713 box_args [0] = ((MonoIntPtr*)res)->m_value;
3714 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3715 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3716 g_assert (!box_exc);
3719 if (has_byref_nullables) {
3721 * The runtime invoke wrapper already converted byref nullables back,
3722 * and stored them in pa, we just need to copy them back to the
3725 for (i = 0; i < mono_array_length (params); i++) {
3726 MonoType *t = sig->params [i];
3728 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3729 mono_array_setref (params, i, pa [i]);
3738 arith_overflow (void)
3740 mono_raise_exception (mono_get_exception_overflow ());
3744 * mono_object_allocate:
3745 * @size: number of bytes to allocate
3747 * This is a very simplistic routine until we have our GC-aware
3750 * Returns: an allocated object of size @size, or NULL on failure.
3752 static inline void *
3753 mono_object_allocate (size_t size, MonoVTable *vtable)
3756 mono_stats.new_object_count++;
3757 ALLOC_OBJECT (o, vtable, size);
3763 * mono_object_allocate_ptrfree:
3764 * @size: number of bytes to allocate
3766 * Note that the memory allocated is not zeroed.
3767 * Returns: an allocated object of size @size, or NULL on failure.
3769 static inline void *
3770 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3773 mono_stats.new_object_count++;
3774 ALLOC_PTRFREE (o, vtable, size);
3778 static inline void *
3779 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3782 ALLOC_TYPED (o, size, vtable);
3783 mono_stats.new_object_count++;
3790 * @klass: the class of the object that we want to create
3792 * Returns: a newly created object whose definition is
3793 * looked up using @klass. This will not invoke any constructors,
3794 * so the consumer of this routine has to invoke any constructors on
3795 * its own to initialize the object.
3797 * It returns NULL on failure.
3800 mono_object_new (MonoDomain *domain, MonoClass *klass)
3804 MONO_ARCH_SAVE_REGS;
3805 vtable = mono_class_vtable (domain, klass);
3808 return mono_object_new_specific (vtable);
3812 * mono_object_new_specific:
3813 * @vtable: the vtable of the object that we want to create
3815 * Returns: A newly created object with class and domain specified
3819 mono_object_new_specific (MonoVTable *vtable)
3823 MONO_ARCH_SAVE_REGS;
3825 /* check for is_com_object for COM Interop */
3826 if (vtable->remote || vtable->klass->is_com_object)
3829 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3832 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3835 mono_class_init (klass);
3837 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3839 vtable->domain->create_proxy_for_type_method = im;
3842 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3844 o = mono_runtime_invoke (im, NULL, pa, NULL);
3845 if (o != NULL) return o;
3848 return mono_object_new_alloc_specific (vtable);
3852 mono_object_new_alloc_specific (MonoVTable *vtable)
3856 if (!vtable->klass->has_references) {
3857 o = mono_object_new_ptrfree (vtable);
3858 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3859 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3861 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3862 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3864 if (G_UNLIKELY (vtable->klass->has_finalize))
3865 mono_object_register_finalizer (o);
3867 if (G_UNLIKELY (profile_allocs))
3868 mono_profiler_allocation (o, vtable->klass);
3873 mono_object_new_fast (MonoVTable *vtable)
3876 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3881 mono_object_new_ptrfree (MonoVTable *vtable)
3884 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3885 #if NEED_TO_ZERO_PTRFREE
3886 /* an inline memset is much faster for the common vcase of small objects
3887 * note we assume the allocated size is a multiple of sizeof (void*).
3889 if (vtable->klass->instance_size < 128) {
3891 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3892 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3898 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3905 mono_object_new_ptrfree_box (MonoVTable *vtable)
3908 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3909 /* the object will be boxed right away, no need to memzero it */
3914 * mono_class_get_allocation_ftn:
3916 * @for_box: the object will be used for boxing
3917 * @pass_size_in_words:
3919 * Return the allocation function appropriate for the given class.
3923 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3925 *pass_size_in_words = FALSE;
3927 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3928 profile_allocs = FALSE;
3930 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3931 return mono_object_new_specific;
3933 if (!vtable->klass->has_references) {
3934 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3936 return mono_object_new_ptrfree_box;
3937 return mono_object_new_ptrfree;
3940 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3942 return mono_object_new_fast;
3945 * FIXME: This is actually slower than mono_object_new_fast, because
3946 * of the overhead of parameter passing.
3949 *pass_size_in_words = TRUE;
3950 #ifdef GC_REDIRECT_TO_LOCAL
3951 return GC_local_gcj_fast_malloc;
3953 return GC_gcj_fast_malloc;
3958 return mono_object_new_specific;
3962 * mono_object_new_from_token:
3963 * @image: Context where the type_token is hosted
3964 * @token: a token of the type that we want to create
3966 * Returns: A newly created object whose definition is
3967 * looked up using @token in the @image image
3970 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3974 class = mono_class_get (image, token);
3976 return mono_object_new (domain, class);
3981 * mono_object_clone:
3982 * @obj: the object to clone
3984 * Returns: A newly created object who is a shallow copy of @obj
3987 mono_object_clone (MonoObject *obj)
3992 size = obj->vtable->klass->instance_size;
3993 o = mono_object_allocate (size, obj->vtable);
3994 /* do not copy the sync state */
3995 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3998 if (obj->vtable->klass->has_references)
3999 mono_gc_wbarrier_object (o);
4001 if (G_UNLIKELY (profile_allocs))
4002 mono_profiler_allocation (o, obj->vtable->klass);
4004 if (obj->vtable->klass->has_finalize)
4005 mono_object_register_finalizer (o);
4010 * mono_array_full_copy:
4011 * @src: source array to copy
4012 * @dest: destination array
4014 * Copies the content of one array to another with exactly the same type and size.
4017 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4019 mono_array_size_t size;
4020 MonoClass *klass = src->obj.vtable->klass;
4022 MONO_ARCH_SAVE_REGS;
4024 g_assert (klass == dest->obj.vtable->klass);
4026 size = mono_array_length (src);
4027 g_assert (size == mono_array_length (dest));
4028 size *= mono_array_element_size (klass);
4030 if (klass->element_class->valuetype) {
4031 if (klass->element_class->has_references)
4032 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4034 memcpy (&dest->vector, &src->vector, size);
4036 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4039 memcpy (&dest->vector, &src->vector, size);
4044 * mono_array_clone_in_domain:
4045 * @domain: the domain in which the array will be cloned into
4046 * @array: the array to clone
4048 * This routine returns a copy of the array that is hosted on the
4049 * specified MonoDomain.
4052 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4055 mono_array_size_t size, i;
4056 mono_array_size_t *sizes;
4057 MonoClass *klass = array->obj.vtable->klass;
4059 MONO_ARCH_SAVE_REGS;
4061 if (array->bounds == NULL) {
4062 size = mono_array_length (array);
4063 o = mono_array_new_full (domain, klass, &size, NULL);
4065 size *= mono_array_element_size (klass);
4067 if (klass->element_class->valuetype) {
4068 if (klass->element_class->has_references)
4069 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4071 memcpy (&o->vector, &array->vector, size);
4073 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4076 memcpy (&o->vector, &array->vector, size);
4081 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4082 size = mono_array_element_size (klass);
4083 for (i = 0; i < klass->rank; ++i) {
4084 sizes [i] = array->bounds [i].length;
4085 size *= array->bounds [i].length;
4086 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4088 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4090 if (klass->element_class->valuetype) {
4091 if (klass->element_class->has_references)
4092 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4094 memcpy (&o->vector, &array->vector, size);
4096 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4099 memcpy (&o->vector, &array->vector, size);
4107 * @array: the array to clone
4109 * Returns: A newly created array who is a shallow copy of @array
4112 mono_array_clone (MonoArray *array)
4114 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4117 /* helper macros to check for overflow when calculating the size of arrays */
4118 #ifdef MONO_BIG_ARRAYS
4119 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4120 #define MYGUINT_MAX MYGUINT64_MAX
4121 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4122 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4123 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4124 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4125 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4127 #define MYGUINT32_MAX 4294967295U
4128 #define MYGUINT_MAX MYGUINT32_MAX
4129 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4130 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4131 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4132 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4133 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4137 * mono_array_new_full:
4138 * @domain: domain where the object is created
4139 * @array_class: array class
4140 * @lengths: lengths for each dimension in the array
4141 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4143 * This routine creates a new array objects with the given dimensions,
4144 * lower bounds and type.
4147 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4149 mono_array_size_t byte_len, len, bounds_size;
4155 if (!array_class->inited)
4156 mono_class_init (array_class);
4158 byte_len = mono_array_element_size (array_class);
4161 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4162 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4164 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4168 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4170 for (i = 0; i < array_class->rank; ++i) {
4171 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4173 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4174 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4179 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4180 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4182 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4183 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4184 byte_len += sizeof (MonoArray);
4187 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4188 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4189 byte_len = (byte_len + 3) & ~3;
4190 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4191 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4192 byte_len += bounds_size;
4195 * Following three lines almost taken from mono_object_new ():
4196 * they need to be kept in sync.
4198 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4199 if (!array_class->has_references) {
4200 o = mono_object_allocate_ptrfree (byte_len, vtable);
4201 #if NEED_TO_ZERO_PTRFREE
4202 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4204 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4205 o = mono_object_allocate_spec (byte_len, vtable);
4207 o = mono_object_allocate (byte_len, vtable);
4210 array = (MonoArray*)o;
4211 array->max_length = len;
4214 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4215 array->bounds = bounds;
4216 for (i = 0; i < array_class->rank; ++i) {
4217 bounds [i].length = lengths [i];
4219 bounds [i].lower_bound = lower_bounds [i];
4223 if (G_UNLIKELY (profile_allocs))
4224 mono_profiler_allocation (o, array_class);
4231 * @domain: domain where the object is created
4232 * @eclass: element class
4233 * @n: number of array elements
4235 * This routine creates a new szarray with @n elements of type @eclass.
4238 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4242 MONO_ARCH_SAVE_REGS;
4244 ac = mono_array_class_get (eclass, 1);
4247 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4251 * mono_array_new_specific:
4252 * @vtable: a vtable in the appropriate domain for an initialized class
4253 * @n: number of array elements
4255 * This routine is a fast alternative to mono_array_new() for code which
4256 * can be sure about the domain it operates in.
4259 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4263 guint32 byte_len, elem_size;
4265 MONO_ARCH_SAVE_REGS;
4267 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4272 elem_size = mono_array_element_size (vtable->klass);
4273 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4274 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4277 byte_len = n * elem_size;
4278 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4279 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4282 byte_len += sizeof (MonoArray);
4283 if (!vtable->klass->has_references) {
4284 o = mono_object_allocate_ptrfree (byte_len, vtable);
4285 #if NEED_TO_ZERO_PTRFREE
4286 ((MonoArray*)o)->bounds = NULL;
4287 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4289 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4290 o = mono_object_allocate_spec (byte_len, vtable);
4292 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4293 o = mono_object_allocate (byte_len, vtable);
4296 ao = (MonoArray *)o;
4298 if (G_UNLIKELY (profile_allocs))
4299 mono_profiler_allocation (o, vtable->klass);
4305 * mono_string_new_utf16:
4306 * @text: a pointer to an utf16 string
4307 * @len: the length of the string
4309 * Returns: A newly created string object which contains @text.
4312 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4316 s = mono_string_new_size (domain, len);
4317 g_assert (s != NULL);
4319 memcpy (mono_string_chars (s), text, len * 2);
4325 * mono_string_new_size:
4326 * @text: a pointer to an utf16 string
4327 * @len: the length of the string
4329 * Returns: A newly created string object of @len
4332 mono_string_new_size (MonoDomain *domain, gint32 len)
4336 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4338 /* overflow ? can't fit it, can't allocate it! */
4340 mono_gc_out_of_memory (-1);
4342 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4345 s = mono_object_allocate_ptrfree (size, vtable);
4348 #if NEED_TO_ZERO_PTRFREE
4351 if (G_UNLIKELY (profile_allocs))
4352 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4358 * mono_string_new_len:
4359 * @text: a pointer to an utf8 string
4360 * @length: number of bytes in @text to consider
4362 * Returns: A newly created string object which contains @text.
4365 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4367 GError *error = NULL;
4368 MonoString *o = NULL;
4370 glong items_written;
4372 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4375 o = mono_string_new_utf16 (domain, ut, items_written);
4377 g_error_free (error);
4386 * @text: a pointer to an utf8 string
4388 * Returns: A newly created string object which contains @text.
4391 mono_string_new (MonoDomain *domain, const char *text)
4393 GError *error = NULL;
4394 MonoString *o = NULL;
4396 glong items_written;
4401 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4404 o = mono_string_new_utf16 (domain, ut, items_written);
4406 g_error_free (error);
4409 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4414 MonoString *o = NULL;
4416 if (!g_utf8_validate (text, -1, &end))
4419 len = g_utf8_strlen (text, -1);
4420 o = mono_string_new_size (domain, len);
4421 str = mono_string_chars (o);
4423 while (text < end) {
4424 *str++ = g_utf8_get_char (text);
4425 text = g_utf8_next_char (text);
4432 * mono_string_new_wrapper:
4433 * @text: pointer to utf8 characters.
4435 * Helper function to create a string object from @text in the current domain.
4438 mono_string_new_wrapper (const char *text)
4440 MonoDomain *domain = mono_domain_get ();
4442 MONO_ARCH_SAVE_REGS;
4445 return mono_string_new (domain, text);
4452 * @class: the class of the value
4453 * @value: a pointer to the unboxed data
4455 * Returns: A newly created object which contains @value.
4458 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4464 g_assert (class->valuetype);
4465 if (mono_class_is_nullable (class))
4466 return mono_nullable_box (value, class);
4468 vtable = mono_class_vtable (domain, class);
4471 size = mono_class_instance_size (class);
4472 res = mono_object_new_alloc_specific (vtable);
4473 if (G_UNLIKELY (profile_allocs))
4474 mono_profiler_allocation (res, class);
4476 size = size - sizeof (MonoObject);
4479 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4482 #if NO_UNALIGNED_ACCESS
4483 memcpy ((char *)res + sizeof (MonoObject), value, size);
4487 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4490 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4493 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4496 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4499 memcpy ((char *)res + sizeof (MonoObject), value, size);
4502 if (class->has_finalize)
4503 mono_object_register_finalizer (res);
4509 * @dest: destination pointer
4510 * @src: source pointer
4511 * @klass: a valuetype class
4513 * Copy a valuetype from @src to @dest. This function must be used
4514 * when @klass contains references fields.
4517 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4519 int size = mono_class_value_size (klass, NULL);
4520 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4521 memcpy (dest, src, size);
4525 * mono_value_copy_array:
4526 * @dest: destination array
4527 * @dest_idx: index in the @dest array
4528 * @src: source pointer
4529 * @count: number of items
4531 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4532 * This function must be used when @klass contains references fields.
4533 * Overlap is handled.
4536 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4538 int size = mono_array_element_size (dest->obj.vtable->klass);
4539 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4540 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4541 memmove (d, src, size * count);
4545 * mono_object_get_domain:
4546 * @obj: object to query
4548 * Returns: the MonoDomain where the object is hosted
4551 mono_object_get_domain (MonoObject *obj)
4553 return mono_object_domain (obj);
4557 * mono_object_get_class:
4558 * @obj: object to query
4560 * Returns: the MonOClass of the object.
4563 mono_object_get_class (MonoObject *obj)
4565 return mono_object_class (obj);
4568 * mono_object_get_size:
4569 * @o: object to query
4571 * Returns: the size, in bytes, of @o
4574 mono_object_get_size (MonoObject* o)
4576 MonoClass* klass = mono_object_class (o);
4577 if (klass == mono_defaults.string_class) {
4578 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4579 } else if (o->vtable->rank) {
4580 MonoArray *array = (MonoArray*)o;
4581 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4582 if (array->bounds) {
4585 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4589 return mono_class_instance_size (klass);
4594 * mono_object_unbox:
4595 * @obj: object to unbox
4597 * Returns: a pointer to the start of the valuetype boxed in this
4600 * This method will assert if the object passed is not a valuetype.
4603 mono_object_unbox (MonoObject *obj)
4605 /* add assert for valuetypes? */
4606 g_assert (obj->vtable->klass->valuetype);
4607 return ((char*)obj) + sizeof (MonoObject);
4611 * mono_object_isinst:
4613 * @klass: a pointer to a class
4615 * Returns: @obj if @obj is derived from @klass
4618 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4621 mono_class_init (klass);
4623 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4624 return mono_object_isinst_mbyref (obj, klass);
4629 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4633 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4642 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4643 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4647 MonoClass *oklass = vt->klass;
4648 if ((oklass == mono_defaults.transparent_proxy_class))
4649 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4651 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4655 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4657 MonoDomain *domain = mono_domain_get ();
4659 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4660 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4661 MonoMethod *im = NULL;
4664 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4665 im = mono_object_get_virtual_method (rp, im);
4668 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4671 res = mono_runtime_invoke (im, rp, pa, NULL);
4673 if (*(MonoBoolean *) mono_object_unbox(res)) {
4674 /* Update the vtable of the remote type, so it can safely cast to this new type */
4675 mono_upgrade_remote_class (domain, obj, klass);
4684 * mono_object_castclass_mbyref:
4686 * @klass: a pointer to a class
4688 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4691 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4693 if (!obj) return NULL;
4694 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4696 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4698 "InvalidCastException"));
4703 MonoDomain *orig_domain;
4709 str_lookup (MonoDomain *domain, gpointer user_data)
4711 LDStrInfo *info = user_data;
4712 if (info->res || domain == info->orig_domain)
4714 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4720 mono_string_get_pinned (MonoString *str)
4724 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4725 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4726 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4727 news->length = mono_string_length (str);
4732 #define mono_string_get_pinned(str) (str)
4736 mono_string_is_interned_lookup (MonoString *str, int insert)
4738 MonoGHashTable *ldstr_table;
4742 domain = ((MonoObject *)str)->vtable->domain;
4743 ldstr_table = domain->ldstr_table;
4745 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4750 str = mono_string_get_pinned (str);
4751 mono_g_hash_table_insert (ldstr_table, str, str);
4755 LDStrInfo ldstr_info;
4756 ldstr_info.orig_domain = domain;
4757 ldstr_info.ins = str;
4758 ldstr_info.res = NULL;
4760 mono_domain_foreach (str_lookup, &ldstr_info);
4761 if (ldstr_info.res) {
4763 * the string was already interned in some other domain:
4764 * intern it in the current one as well.
4766 mono_g_hash_table_insert (ldstr_table, str, str);
4776 * mono_string_is_interned:
4777 * @o: String to probe
4779 * Returns whether the string has been interned.
4782 mono_string_is_interned (MonoString *o)
4784 return mono_string_is_interned_lookup (o, FALSE);
4788 * mono_string_intern:
4789 * @o: String to intern
4791 * Interns the string passed.
4792 * Returns: The interned string.
4795 mono_string_intern (MonoString *str)
4797 return mono_string_is_interned_lookup (str, TRUE);
4802 * @domain: the domain where the string will be used.
4803 * @image: a metadata context
4804 * @idx: index into the user string table.
4806 * Implementation for the ldstr opcode.
4807 * Returns: a loaded string from the @image/@idx combination.
4810 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4812 MONO_ARCH_SAVE_REGS;
4815 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4817 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4821 * mono_ldstr_metadata_sig
4822 * @domain: the domain for the string
4823 * @sig: the signature of a metadata string
4825 * Returns: a MonoString for a string stored in the metadata
4828 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4830 const char *str = sig;
4831 MonoString *o, *interned;
4834 len2 = mono_metadata_decode_blob_size (str, &str);
4837 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4838 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4841 guint16 *p2 = (guint16*)mono_string_chars (o);
4842 for (i = 0; i < len2; ++i) {
4843 *p2 = GUINT16_FROM_LE (*p2);
4849 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4851 /* o will get garbage collected */
4855 o = mono_string_get_pinned (o);
4856 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4863 * mono_string_to_utf8:
4864 * @s: a System.String
4866 * Return the UTF8 representation for @s.
4867 * the resulting buffer nedds to be freed with g_free().
4870 mono_string_to_utf8 (MonoString *s)
4874 GError *error = NULL;
4880 return g_strdup ("");
4882 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4884 MonoException *exc = mono_get_exception_argument ("string", error->message);
4885 g_error_free (error);
4886 mono_raise_exception(exc);
4888 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4889 if (s->length > written) {
4890 /* allocate the total length and copy the part of the string that has been converted */
4891 char *as2 = g_malloc0 (s->length);
4892 memcpy (as2, as, written);
4901 * mono_string_to_utf16:
4904 * Return an null-terminated array of the utf-16 chars
4905 * contained in @s. The result must be freed with g_free().
4906 * This is a temporary helper until our string implementation
4907 * is reworked to always include the null terminating char.
4910 mono_string_to_utf16 (MonoString *s)
4917 as = g_malloc ((s->length * 2) + 2);
4918 as [(s->length * 2)] = '\0';
4919 as [(s->length * 2) + 1] = '\0';
4922 return (gunichar2 *)(as);
4925 memcpy (as, mono_string_chars(s), s->length * 2);
4926 return (gunichar2 *)(as);
4930 * mono_string_from_utf16:
4931 * @data: the UTF16 string (LPWSTR) to convert
4933 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4935 * Returns: a MonoString.
4938 mono_string_from_utf16 (gunichar2 *data)
4940 MonoDomain *domain = mono_domain_get ();
4946 while (data [len]) len++;
4948 return mono_string_new_utf16 (domain, data, len);
4953 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4960 return mono_string_to_utf8 (s);
4962 r = mono_string_to_utf8 (s);
4966 len = strlen (r) + 1;
4968 mp_s = mono_mempool_alloc (mp, len);
4970 mp_s = mono_image_alloc (image, len);
4972 memcpy (mp_s, r, len);
4980 * mono_string_to_utf8_image:
4981 * @s: a System.String
4983 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4986 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4988 return mono_string_to_utf8_internal (NULL, image, s);
4992 * mono_string_to_utf8_mp:
4993 * @s: a System.String
4995 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4998 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
5000 return mono_string_to_utf8_internal (mp, NULL, s);
5004 default_ex_handler (MonoException *ex)
5006 MonoObject *o = (MonoObject*)ex;
5007 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5011 static MonoExceptionFunc ex_handler = default_ex_handler;
5014 * mono_install_handler:
5015 * @func: exception handler
5017 * This is an internal JIT routine used to install the handler for exceptions
5021 mono_install_handler (MonoExceptionFunc func)
5023 ex_handler = func? func: default_ex_handler;
5027 * mono_raise_exception:
5028 * @ex: exception object
5030 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5033 mono_raise_exception (MonoException *ex)
5036 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5037 * that will cause gcc to omit the function epilog, causing problems when
5038 * the JIT tries to walk the stack, since the return address on the stack
5039 * will point into the next function in the executable, not this one.
5042 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5043 MonoThread *thread = mono_thread_current ();
5044 g_assert (ex->object.vtable->domain == mono_domain_get ());
5045 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5052 * mono_wait_handle_new:
5053 * @domain: Domain where the object will be created
5054 * @handle: Handle for the wait handle
5056 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5059 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5061 MonoWaitHandle *res;
5062 gpointer params [1];
5063 static MonoMethod *handle_set;
5065 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5067 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5069 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5071 params [0] = &handle;
5072 mono_runtime_invoke (handle_set, res, params, NULL);
5078 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5080 static MonoClassField *f_os_handle;
5081 static MonoClassField *f_safe_handle;
5083 if (!f_os_handle && !f_safe_handle) {
5084 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5085 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5090 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5094 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5101 mono_runtime_capture_context (MonoDomain *domain)
5103 RuntimeInvokeFunction runtime_invoke;
5105 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5106 MonoMethod *method = mono_get_context_capture_method ();
5107 MonoMethod *wrapper;
5110 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5111 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5112 domain->capture_context_method = mono_compile_method (method);
5115 runtime_invoke = domain->capture_context_runtime_invoke;
5117 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5120 * mono_async_result_new:
5121 * @domain:domain where the object will be created.
5122 * @handle: wait handle.
5123 * @state: state to pass to AsyncResult
5124 * @data: C closure data.
5126 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5127 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5131 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5133 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5134 MonoObject *context = mono_runtime_capture_context (domain);
5135 /* we must capture the execution context from the original thread */
5137 MONO_OBJECT_SETREF (res, execution_context, context);
5138 /* note: result may be null if the flow is suppressed */
5142 MONO_OBJECT_SETREF (res, object_data, object_data);
5143 MONO_OBJECT_SETREF (res, async_state, state);
5145 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5147 res->sync_completed = FALSE;
5148 res->completed = FALSE;
5154 mono_message_init (MonoDomain *domain,
5155 MonoMethodMessage *this,
5156 MonoReflectionMethod *method,
5157 MonoArray *out_args)
5159 static MonoClass *object_array_klass;
5160 static MonoClass *byte_array_klass;
5161 static MonoClass *string_array_klass;
5162 MonoMethodSignature *sig = mono_method_signature (method->method);
5168 if (!object_array_klass) {
5171 klass = mono_array_class_get (mono_defaults.object_class, 1);
5174 mono_memory_barrier ();
5175 object_array_klass = klass;
5177 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5180 mono_memory_barrier ();
5181 byte_array_klass = klass;
5183 klass = mono_array_class_get (mono_defaults.string_class, 1);
5186 mono_memory_barrier ();
5187 string_array_klass = klass;
5190 MONO_OBJECT_SETREF (this, method, method);
5192 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5193 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5194 this->async_result = NULL;
5195 this->call_type = CallType_Sync;
5197 names = g_new (char *, sig->param_count);
5198 mono_method_get_param_names (method->method, (const char **) names);
5199 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5201 for (i = 0; i < sig->param_count; i++) {
5202 name = mono_string_new (domain, names [i]);
5203 mono_array_setref (this->names, i, name);
5207 for (i = 0, j = 0; i < sig->param_count; i++) {
5208 if (sig->params [i]->byref) {
5210 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5211 mono_array_setref (this->args, i, arg);
5215 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5219 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5222 mono_array_set (this->arg_types, guint8, i, arg_type);
5227 * mono_remoting_invoke:
5228 * @real_proxy: pointer to a RealProxy object
5229 * @msg: The MonoMethodMessage to execute
5230 * @exc: used to store exceptions
5231 * @out_args: used to store output arguments
5233 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5234 * IMessage interface and it is not trivial to extract results from there. So
5235 * we call an helper method PrivateInvoke instead of calling
5236 * RealProxy::Invoke() directly.
5238 * Returns: the result object.
5241 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5242 MonoObject **exc, MonoArray **out_args)
5244 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5247 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5250 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5252 real_proxy->vtable->domain->private_invoke_method = im;
5255 pa [0] = real_proxy;
5260 return mono_runtime_invoke (im, NULL, pa, exc);
5264 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5265 MonoObject **exc, MonoArray **out_args)
5267 static MonoClass *object_array_klass;
5270 MonoMethodSignature *sig;
5272 int i, j, outarg_count = 0;
5274 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5276 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5277 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5278 target = tp->rp->unwrapped_server;
5280 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5284 domain = mono_domain_get ();
5285 method = msg->method->method;
5286 sig = mono_method_signature (method);
5288 for (i = 0; i < sig->param_count; i++) {
5289 if (sig->params [i]->byref)
5293 if (!object_array_klass) {
5296 klass = mono_array_class_get (mono_defaults.object_class, 1);
5299 mono_memory_barrier ();
5300 object_array_klass = klass;
5303 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5304 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5307 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5309 for (i = 0, j = 0; i < sig->param_count; i++) {
5310 if (sig->params [i]->byref) {
5312 arg = mono_array_get (msg->args, gpointer, i);
5313 mono_array_setref (*out_args, j, arg);
5322 * mono_print_unhandled_exception:
5323 * @exc: The exception
5325 * Prints the unhandled exception.
5328 mono_print_unhandled_exception (MonoObject *exc)
5330 char *message = (char *) "";
5334 gboolean free_message = FALSE;
5336 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5337 klass = exc->vtable->klass;
5339 while (klass && method == NULL) {
5340 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5342 klass = klass->parent;
5347 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5349 message = mono_string_to_utf8 (str);
5350 free_message = TRUE;
5355 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5356 * exc->vtable->klass->name, message);
5358 g_printerr ("\nUnhandled Exception: %s\n", message);
5365 * mono_delegate_ctor:
5366 * @this: pointer to an uninitialized delegate object
5367 * @target: target object
5368 * @addr: pointer to native code
5371 * Initialize a delegate and sets a specific method, not the one
5372 * associated with addr. This is useful when sharing generic code.
5373 * In that case addr will most probably not be associated with the
5374 * correct instantiation of the method.
5377 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5379 MonoDelegate *delegate = (MonoDelegate *)this;
5386 delegate->method = method;
5388 class = this->vtable->klass;
5389 mono_stats.delegate_creations++;
5391 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5393 method = mono_marshal_get_remoting_invoke (method);
5394 delegate->method_ptr = mono_compile_method (method);
5395 MONO_OBJECT_SETREF (delegate, target, target);
5396 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5397 method = mono_marshal_get_unbox_wrapper (method);
5398 delegate->method_ptr = mono_compile_method (method);
5399 MONO_OBJECT_SETREF (delegate, target, target);
5401 delegate->method_ptr = addr;
5402 MONO_OBJECT_SETREF (delegate, target, target);
5405 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5409 * mono_delegate_ctor:
5410 * @this: pointer to an uninitialized delegate object
5411 * @target: target object
5412 * @addr: pointer to native code
5414 * This is used to initialize a delegate.
5417 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5419 MonoDomain *domain = mono_domain_get ();
5421 MonoMethod *method = NULL;
5425 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5426 method = ji->method;
5427 g_assert (!method->klass->generic_container);
5430 mono_delegate_ctor_with_method (this, target, addr, method);
5434 * mono_method_call_message_new:
5435 * @method: method to encapsulate
5436 * @params: parameters to the method
5437 * @invoke: optional, delegate invoke.
5438 * @cb: async callback delegate.
5439 * @state: state passed to the async callback.
5441 * Translates arguments pointers into a MonoMethodMessage.
5444 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5445 MonoDelegate **cb, MonoObject **state)
5447 MonoDomain *domain = mono_domain_get ();
5448 MonoMethodSignature *sig = mono_method_signature (method);
5449 MonoMethodMessage *msg;
5452 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5455 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5456 count = sig->param_count - 2;
5458 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5459 count = sig->param_count;
5462 for (i = 0; i < count; i++) {
5467 if (sig->params [i]->byref)
5468 vpos = *((gpointer *)params [i]);
5472 type = sig->params [i]->type;
5473 class = mono_class_from_mono_type (sig->params [i]);
5475 if (class->valuetype)
5476 arg = mono_value_box (domain, class, vpos);
5478 arg = *((MonoObject **)vpos);
5480 mono_array_setref (msg->args, i, arg);
5483 if (cb != NULL && state != NULL) {
5484 *cb = *((MonoDelegate **)params [i]);
5486 *state = *((MonoObject **)params [i]);
5493 * mono_method_return_message_restore:
5495 * Restore results from message based processing back to arguments pointers
5498 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5500 MonoMethodSignature *sig = mono_method_signature (method);
5501 int i, j, type, size, out_len;
5503 if (out_args == NULL)
5505 out_len = mono_array_length (out_args);
5509 for (i = 0, j = 0; i < sig->param_count; i++) {
5510 MonoType *pt = sig->params [i];
5515 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5517 arg = mono_array_get (out_args, gpointer, j);
5521 case MONO_TYPE_VOID:
5522 g_assert_not_reached ();
5526 case MONO_TYPE_BOOLEAN:
5529 case MONO_TYPE_CHAR:
5536 case MONO_TYPE_VALUETYPE: {
5538 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5539 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5542 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5543 memset (*((gpointer *)params [i]), 0, size);
5547 case MONO_TYPE_STRING:
5548 case MONO_TYPE_CLASS:
5549 case MONO_TYPE_ARRAY:
5550 case MONO_TYPE_SZARRAY:
5551 case MONO_TYPE_OBJECT:
5552 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5555 g_assert_not_reached ();
5564 * mono_load_remote_field:
5565 * @this: pointer to an object
5566 * @klass: klass of the object containing @field
5567 * @field: the field to load
5568 * @res: a storage to store the result
5570 * This method is called by the runtime on attempts to load fields of
5571 * transparent proxy objects. @this points to such TP, @klass is the class of
5572 * the object containing @field. @res is a storage location which can be
5573 * used to store the result.
5575 * Returns: an address pointing to the value of field.
5578 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5580 static MonoMethod *getter = NULL;
5581 MonoDomain *domain = mono_domain_get ();
5582 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5583 MonoClass *field_class;
5584 MonoMethodMessage *msg;
5585 MonoArray *out_args;
5589 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5590 g_assert (res != NULL);
5592 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5593 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5598 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5602 field_class = mono_class_from_mono_type (field->type);
5604 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5605 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5606 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5608 full_name = mono_type_get_full_name (klass);
5609 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5610 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5613 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5615 if (exc) mono_raise_exception ((MonoException *)exc);
5617 if (mono_array_length (out_args) == 0)
5620 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5622 if (field_class->valuetype) {
5623 return ((char *)*res) + sizeof (MonoObject);
5629 * mono_load_remote_field_new:
5634 * Missing documentation.
5637 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5639 static MonoMethod *getter = NULL;
5640 MonoDomain *domain = mono_domain_get ();
5641 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5642 MonoClass *field_class;
5643 MonoMethodMessage *msg;
5644 MonoArray *out_args;
5645 MonoObject *exc, *res;
5648 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5650 field_class = mono_class_from_mono_type (field->type);
5652 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5654 if (field_class->valuetype) {
5655 res = mono_object_new (domain, field_class);
5656 val = ((gchar *) res) + sizeof (MonoObject);
5660 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5665 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5669 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5670 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5672 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5674 full_name = mono_type_get_full_name (klass);
5675 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5676 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5679 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5681 if (exc) mono_raise_exception ((MonoException *)exc);
5683 if (mono_array_length (out_args) == 0)
5686 res = mono_array_get (out_args, MonoObject *, 0);
5692 * mono_store_remote_field:
5693 * @this: pointer to an object
5694 * @klass: klass of the object containing @field
5695 * @field: the field to load
5696 * @val: the value/object to store
5698 * This method is called by the runtime on attempts to store fields of
5699 * transparent proxy objects. @this points to such TP, @klass is the class of
5700 * the object containing @field. @val is the new value to store in @field.
5703 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5705 static MonoMethod *setter = NULL;
5706 MonoDomain *domain = mono_domain_get ();
5707 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5708 MonoClass *field_class;
5709 MonoMethodMessage *msg;
5710 MonoArray *out_args;
5715 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5717 field_class = mono_class_from_mono_type (field->type);
5719 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5720 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5721 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5726 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5730 if (field_class->valuetype)
5731 arg = mono_value_box (domain, field_class, val);
5733 arg = *((MonoObject **)val);
5736 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5737 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5739 full_name = mono_type_get_full_name (klass);
5740 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5741 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5742 mono_array_setref (msg->args, 2, arg);
5745 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5747 if (exc) mono_raise_exception ((MonoException *)exc);
5751 * mono_store_remote_field_new:
5757 * Missing documentation
5760 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5762 static MonoMethod *setter = NULL;
5763 MonoDomain *domain = mono_domain_get ();
5764 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5765 MonoClass *field_class;
5766 MonoMethodMessage *msg;
5767 MonoArray *out_args;
5771 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5773 field_class = mono_class_from_mono_type (field->type);
5775 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5776 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5777 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5782 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5786 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5787 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5789 full_name = mono_type_get_full_name (klass);
5790 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5791 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5792 mono_array_setref (msg->args, 2, arg);
5795 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5797 if (exc) mono_raise_exception ((MonoException *)exc);
5801 * mono_create_ftnptr:
5803 * Given a function address, create a function descriptor for it.
5804 * This is only needed on some platforms.
5807 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5809 return callbacks.create_ftnptr (domain, addr);
5813 * mono_get_addr_from_ftnptr:
5815 * Given a pointer to a function descriptor, return the function address.
5816 * This is only needed on some platforms.
5819 mono_get_addr_from_ftnptr (gpointer descr)
5821 return callbacks.get_addr_from_ftnptr (descr);
5826 * mono_string_chars:
5829 * Returns a pointer to the UCS16 characters stored in the MonoString
5832 mono_string_chars(MonoString *s)
5834 /* This method is here only for documentation extraction, this is a macro */
5838 * mono_string_length:
5841 * Returns the lenght in characters of the string
5844 mono_string_length (MonoString *s)
5846 /* This method is here only for documentation extraction, this is a macro */