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 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
268 method = mono_class_get_cctor (klass);
271 MonoDomain *domain = vtable->domain;
272 TypeInitializationLock *lock;
273 guint32 tid = GetCurrentThreadId();
274 int do_initialization = 0;
275 MonoDomain *last_domain = NULL;
277 mono_type_initialization_lock ();
278 /* double check... */
279 if (vtable->initialized) {
280 mono_type_initialization_unlock ();
283 if (vtable->init_failed) {
284 mono_type_initialization_unlock ();
286 /* The type initialization already failed once, rethrow the same exception */
288 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
289 return get_type_init_exception_for_vtable (vtable);
291 lock = g_hash_table_lookup (type_initialization_hash, vtable);
293 /* This thread will get to do the initialization */
294 if (mono_domain_get () != domain) {
295 /* Transfer into the target domain */
296 last_domain = mono_domain_get ();
297 if (!mono_domain_set (domain, FALSE)) {
298 vtable->initialized = 1;
299 mono_type_initialization_unlock ();
301 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
302 return mono_get_exception_appdomain_unloaded ();
305 lock = g_malloc (sizeof(TypeInitializationLock));
306 InitializeCriticalSection (&lock->initialization_section);
307 lock->initializing_tid = tid;
308 lock->waiting_count = 1;
310 /* grab the vtable lock while this thread still owns type_initialization_section */
311 EnterCriticalSection (&lock->initialization_section);
312 g_hash_table_insert (type_initialization_hash, vtable, lock);
313 do_initialization = 1;
316 TypeInitializationLock *pending_lock;
318 if (lock->initializing_tid == tid || lock->done) {
319 mono_type_initialization_unlock ();
322 /* see if the thread doing the initialization is already blocked on this thread */
323 blocked = GUINT_TO_POINTER (lock->initializing_tid);
324 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
325 if (pending_lock->initializing_tid == tid) {
326 if (!pending_lock->done) {
327 mono_type_initialization_unlock ();
330 /* the thread doing the initialization is blocked on this thread,
331 but on a lock that has already been freed. It just hasn't got
336 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
338 ++lock->waiting_count;
339 /* record the fact that we are waiting on the initializing thread */
340 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
342 mono_type_initialization_unlock ();
344 if (do_initialization) {
345 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
347 /* If the initialization failed, mark the class as unusable. */
348 /* Avoid infinite loops */
350 (klass->image == mono_defaults.corlib &&
351 !strcmp (klass->name_space, "System") &&
352 !strcmp (klass->name, "TypeInitializationException")))) {
353 vtable->init_failed = 1;
355 if (klass->name_space && *klass->name_space)
356 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
358 full_name = g_strdup (klass->name);
359 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
363 * Store the exception object so it could be thrown on subsequent
366 mono_domain_lock (domain);
367 if (!domain->type_init_exception_hash)
368 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
369 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
370 mono_domain_unlock (domain);
374 mono_domain_set (last_domain, TRUE);
376 LeaveCriticalSection (&lock->initialization_section);
378 /* this just blocks until the initializing thread is done */
379 EnterCriticalSection (&lock->initialization_section);
380 LeaveCriticalSection (&lock->initialization_section);
383 mono_type_initialization_lock ();
384 if (lock->initializing_tid != tid)
385 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
386 --lock->waiting_count;
387 if (lock->waiting_count == 0) {
388 DeleteCriticalSection (&lock->initialization_section);
389 g_hash_table_remove (type_initialization_hash, vtable);
392 if (!vtable->init_failed)
393 vtable->initialized = 1;
394 mono_type_initialization_unlock ();
396 if (vtable->init_failed) {
397 /* Either we were the initializing thread or we waited for the initialization */
399 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
400 return get_type_init_exception_for_vtable (vtable);
403 vtable->initialized = 1;
410 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
412 MonoVTable *vtable = (MonoVTable*)key;
414 TypeInitializationLock *lock = (TypeInitializationLock*) value;
415 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
418 * Have to set this since it cannot be set by the normal code in
419 * mono_runtime_class_init (). In this case, the exception object is not stored,
420 * and get_type_init_exception_for_class () needs to be aware of this.
422 vtable->init_failed = 1;
423 LeaveCriticalSection (&lock->initialization_section);
424 --lock->waiting_count;
425 if (lock->waiting_count == 0) {
426 DeleteCriticalSection (&lock->initialization_section);
435 mono_release_type_locks (MonoThread *thread)
437 mono_type_initialization_lock ();
438 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
439 mono_type_initialization_unlock ();
443 default_trampoline (MonoMethod *method)
449 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
451 g_assert_not_reached ();
457 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
459 g_error ("remoting not installed");
464 default_delegate_trampoline (MonoClass *klass)
466 g_assert_not_reached ();
470 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
471 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
472 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
473 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
474 static MonoImtThunkBuilder imt_thunk_builder = NULL;
475 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
476 #if (MONO_IMT_SIZE > 32)
477 #error "MONO_IMT_SIZE cannot be larger than 32"
481 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
483 memcpy (&callbacks, cbs, sizeof (*cbs));
486 MonoRuntimeCallbacks*
487 mono_get_runtime_callbacks (void)
493 mono_install_trampoline (MonoTrampoline func)
495 arch_create_jit_trampoline = func? func: default_trampoline;
499 mono_install_jump_trampoline (MonoJumpTrampoline func)
501 arch_create_jump_trampoline = func? func: default_jump_trampoline;
505 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
507 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
511 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
513 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
517 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
518 imt_thunk_builder = func;
521 static MonoCompileFunc default_mono_compile_method = NULL;
524 * mono_install_compile_method:
525 * @func: function to install
527 * This is a VM internal routine
530 mono_install_compile_method (MonoCompileFunc func)
532 default_mono_compile_method = func;
536 * mono_compile_method:
537 * @method: The method to compile.
539 * This JIT-compiles the method, and returns the pointer to the native code
543 mono_compile_method (MonoMethod *method)
545 if (!default_mono_compile_method) {
546 g_error ("compile method called on uninitialized runtime");
549 return default_mono_compile_method (method);
553 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
555 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
559 mono_runtime_create_delegate_trampoline (MonoClass *klass)
561 return arch_create_delegate_trampoline (klass);
564 static MonoFreeMethodFunc default_mono_free_method = NULL;
567 * mono_install_free_method:
568 * @func: pointer to the MonoFreeMethodFunc used to release a method
570 * This is an internal VM routine, it is used for the engines to
571 * register a handler to release the resources associated with a method.
573 * Methods are freed when no more references to the delegate that holds
577 mono_install_free_method (MonoFreeMethodFunc func)
579 default_mono_free_method = func;
583 * mono_runtime_free_method:
584 * @domain; domain where the method is hosted
585 * @method: method to release
587 * This routine is invoked to free the resources associated with
588 * a method that has been JIT compiled. This is used to discard
589 * methods that were used only temporarily (for example, used in marshalling)
593 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
595 if (default_mono_free_method != NULL)
596 default_mono_free_method (domain, method);
598 mono_method_clear_object (domain, method);
600 mono_free_method (method);
604 * The vtables in the root appdomain are assumed to be reachable by other
605 * roots, and we don't use typed allocation in the other domains.
608 /* The sync block is no longer a GC pointer */
609 #define GC_HEADER_BITMAP (0)
611 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
614 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
616 MonoClassField *field;
622 max_size = mono_class_data_size (class) / sizeof (gpointer);
624 max_size = class->instance_size / sizeof (gpointer);
625 if (max_size >= size) {
626 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
629 for (p = class; p != NULL; p = p->parent) {
630 gpointer iter = NULL;
631 while ((field = mono_class_get_fields (p, &iter))) {
635 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
637 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
640 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
643 /* FIXME: should not happen, flag as type load error */
644 if (field->type->byref)
647 if (static_fields && field->offset == -1)
651 pos = field->offset / sizeof (gpointer);
654 type = mono_type_get_underlying_type (field->type);
655 switch (type->type) {
658 case MONO_TYPE_FNPTR:
660 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
665 if (class->image != mono_defaults.corlib)
668 case MONO_TYPE_STRING:
669 case MONO_TYPE_SZARRAY:
670 case MONO_TYPE_CLASS:
671 case MONO_TYPE_OBJECT:
672 case MONO_TYPE_ARRAY:
673 g_assert ((field->offset % sizeof(gpointer)) == 0);
675 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
676 *max_set = MAX (*max_set, pos);
678 case MONO_TYPE_GENERICINST:
679 if (!mono_type_generic_inst_is_valuetype (type)) {
680 g_assert ((field->offset % sizeof(gpointer)) == 0);
682 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
683 *max_set = MAX (*max_set, pos);
688 case MONO_TYPE_VALUETYPE: {
689 MonoClass *fclass = mono_class_from_mono_type (field->type);
690 if (fclass->has_references) {
691 /* remove the object header */
692 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
706 case MONO_TYPE_BOOLEAN:
710 g_assert_not_reached ();
722 * similar to the above, but sets the bits in the bitmap for any non-ref field
723 * and ignores static fields
726 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
728 MonoClassField *field;
733 max_size = class->instance_size / sizeof (gpointer);
734 if (max_size >= size) {
735 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
738 for (p = class; p != NULL; p = p->parent) {
739 gpointer iter = NULL;
740 while ((field = mono_class_get_fields (p, &iter))) {
743 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
745 /* FIXME: should not happen, flag as type load error */
746 if (field->type->byref)
749 pos = field->offset / sizeof (gpointer);
752 type = mono_type_get_underlying_type (field->type);
753 switch (type->type) {
754 #if SIZEOF_VOID_P == 8
758 case MONO_TYPE_FNPTR:
763 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
764 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
765 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
768 #if SIZEOF_VOID_P == 4
772 case MONO_TYPE_FNPTR:
777 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
778 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
779 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
785 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
786 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
787 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
790 case MONO_TYPE_BOOLEAN:
793 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795 case MONO_TYPE_STRING:
796 case MONO_TYPE_SZARRAY:
797 case MONO_TYPE_CLASS:
798 case MONO_TYPE_OBJECT:
799 case MONO_TYPE_ARRAY:
801 case MONO_TYPE_GENERICINST:
802 if (!mono_type_generic_inst_is_valuetype (type)) {
807 case MONO_TYPE_VALUETYPE: {
808 MonoClass *fclass = mono_class_from_mono_type (field->type);
809 /* remove the object header */
810 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
814 g_assert_not_reached ();
823 * mono_class_insecure_overlapping:
824 * check if a class with explicit layout has references and non-references
825 * fields overlapping.
827 * Returns: TRUE if it is insecure to load the type.
830 mono_class_insecure_overlapping (MonoClass *klass)
834 gsize default_bitmap [4] = {0};
836 gsize default_nrbitmap [4] = {0};
837 int i, insecure = FALSE;
840 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
841 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
843 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
844 int idx = i % (sizeof (bitmap [0]) * 8);
845 if (bitmap [idx] & nrbitmap [idx]) {
850 if (bitmap != default_bitmap)
852 if (nrbitmap != default_nrbitmap)
855 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
863 mono_string_alloc (int length)
865 return mono_string_new_size (mono_domain_get (), length);
869 mono_class_compute_gc_descriptor (MonoClass *class)
873 gsize default_bitmap [4] = {0};
874 static gboolean gcj_inited = FALSE;
879 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
880 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
881 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
882 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
884 #ifdef HAVE_GC_GCJ_MALLOC
886 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
890 #ifdef GC_REDIRECT_TO_LOCAL
891 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
892 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
894 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
895 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
900 mono_loader_unlock ();
904 mono_class_init (class);
906 if (class->gc_descr_inited)
909 class->gc_descr_inited = TRUE;
910 class->gc_descr = GC_NO_DESCRIPTOR;
912 bitmap = default_bitmap;
913 if (class == mono_defaults.string_class) {
914 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
915 } else if (class->rank) {
916 mono_class_compute_gc_descriptor (class->element_class);
917 if (!class->element_class->valuetype) {
919 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
920 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
921 class->name_space, class->name);*/
923 /* remove the object header */
924 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
925 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
926 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
927 class->name_space, class->name);*/
928 if (bitmap != default_bitmap)
932 /*static int count = 0;
935 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
936 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
938 if (class->gc_descr == GC_NO_DESCRIPTOR)
939 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
941 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
942 if (bitmap != default_bitmap)
948 * field_is_special_static:
949 * @fklass: The MonoClass to look up.
950 * @field: The MonoClassField describing the field.
952 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
953 * SPECIAL_STATIC_NONE otherwise.
956 field_is_special_static (MonoClass *fklass, MonoClassField *field)
958 MonoCustomAttrInfo *ainfo;
960 ainfo = mono_custom_attrs_from_field (fklass, field);
963 for (i = 0; i < ainfo->num_attrs; ++i) {
964 MonoClass *klass = ainfo->attrs [i].ctor->klass;
965 if (klass->image == mono_defaults.corlib) {
966 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
967 mono_custom_attrs_free (ainfo);
968 return SPECIAL_STATIC_THREAD;
970 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
971 mono_custom_attrs_free (ainfo);
972 return SPECIAL_STATIC_CONTEXT;
976 mono_custom_attrs_free (ainfo);
977 return SPECIAL_STATIC_NONE;
980 static gpointer imt_trampoline = NULL;
983 mono_install_imt_trampoline (gpointer tramp_code)
985 imt_trampoline = tramp_code;
988 static gpointer vtable_trampoline = NULL;
991 mono_install_vtable_trampoline (gpointer tramp_code)
993 vtable_trampoline = tramp_code;
996 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
997 #define mix(a,b,c) { \
998 a -= c; a ^= rot(c, 4); c += b; \
999 b -= a; b ^= rot(a, 6); a += c; \
1000 c -= b; c ^= rot(b, 8); b += a; \
1001 a -= c; a ^= rot(c,16); c += b; \
1002 b -= a; b ^= rot(a,19); a += c; \
1003 c -= b; c ^= rot(b, 4); b += a; \
1005 #define final(a,b,c) { \
1006 c ^= b; c -= rot(b,14); \
1007 a ^= c; a -= rot(c,11); \
1008 b ^= a; b -= rot(a,25); \
1009 c ^= b; c -= rot(b,16); \
1010 a ^= c; a -= rot(c,4); \
1011 b ^= a; b -= rot(a,14); \
1012 c ^= b; c -= rot(b,24); \
1016 mono_method_get_imt_slot (MonoMethod *method)
1018 MonoMethodSignature *sig;
1020 guint32 *hashes_start, *hashes;
1024 /* This can be used to stress tests the collision code */
1028 * We do this to simplify generic sharing. It will hurt
1029 * performance in cases where a class implements two different
1030 * instantiations of the same generic interface.
1031 * The code in build_imt_slots () depends on this.
1033 if (method->is_inflated)
1034 method = ((MonoMethodInflated*)method)->declaring;
1036 sig = mono_method_signature (method);
1037 hashes_count = sig->param_count + 4;
1038 hashes_start = malloc (hashes_count * sizeof (guint32));
1039 hashes = hashes_start;
1041 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1042 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1043 method->klass->name_space, method->klass->name, method->name);
1044 g_assert_not_reached ();
1047 /* Initialize hashes */
1048 hashes [0] = g_str_hash (method->klass->name);
1049 hashes [1] = g_str_hash (method->klass->name_space);
1050 hashes [2] = g_str_hash (method->name);
1051 hashes [3] = mono_metadata_type_hash (sig->ret);
1052 for (i = 0; i < sig->param_count; i++) {
1053 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1056 /* Setup internal state */
1057 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1059 /* Handle most of the hashes */
1060 while (hashes_count > 3) {
1069 /* Handle the last 3 hashes (all the case statements fall through) */
1070 switch (hashes_count) {
1071 case 3 : c += hashes [2];
1072 case 2 : b += hashes [1];
1073 case 1 : a += hashes [0];
1075 case 0: /* nothing left to add */
1079 free (hashes_start);
1080 /* Report the result */
1081 return c % MONO_IMT_SIZE;
1090 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1091 guint32 imt_slot = mono_method_get_imt_slot (method);
1092 MonoImtBuilderEntry *entry;
1094 if (slot_num >= 0 && imt_slot != slot_num) {
1095 /* we build just a single imt slot and this is not it */
1099 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1100 entry->key = method;
1101 entry->value.vtable_slot = vtable_slot;
1102 entry->next = imt_builder [imt_slot];
1103 if (imt_builder [imt_slot] != NULL) {
1104 entry->children = imt_builder [imt_slot]->children + 1;
1105 if (entry->children == 1) {
1106 mono_stats.imt_slots_with_collisions++;
1107 *imt_collisions_bitmap |= (1 << imt_slot);
1110 entry->children = 0;
1111 mono_stats.imt_used_slots++;
1113 imt_builder [imt_slot] = entry;
1115 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1116 method, method->klass->name_space, method->klass->name,
1117 method->name, imt_slot, vtable_slot, entry->children);
1123 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1125 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1129 e->method->klass->name_space,
1130 e->method->klass->name,
1133 printf (" * %s: NULL\n", message);
1139 compare_imt_builder_entries (const void *p1, const void *p2) {
1140 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1141 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1143 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1147 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1149 int count = end - start;
1150 int chunk_start = out_array->len;
1153 for (i = start; i < end; ++i) {
1154 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1155 item->key = sorted_array [i]->key;
1156 item->value = sorted_array [i]->value;
1157 item->has_target_code = sorted_array [i]->has_target_code;
1158 item->is_equals = TRUE;
1160 item->check_target_idx = out_array->len + 1;
1162 item->check_target_idx = 0;
1163 g_ptr_array_add (out_array, item);
1166 int middle = start + count / 2;
1167 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1169 item->key = sorted_array [middle]->key;
1170 item->is_equals = FALSE;
1171 g_ptr_array_add (out_array, item);
1172 imt_emit_ir (sorted_array, start, middle, out_array);
1173 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1179 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1180 int number_of_entries = entries->children + 1;
1181 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1182 GPtrArray *result = g_ptr_array_new ();
1183 MonoImtBuilderEntry *current_entry;
1186 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1187 sorted_array [i] = current_entry;
1189 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1191 /*for (i = 0; i < number_of_entries; i++) {
1192 print_imt_entry (" sorted array:", sorted_array [i], i);
1195 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1197 free (sorted_array);
1202 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1204 if (imt_builder_entry != NULL) {
1205 if (imt_builder_entry->children == 0 && !fail_tramp) {
1206 /* No collision, return the vtable slot contents */
1207 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1209 /* Collision, build the thunk */
1210 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1213 result = imt_thunk_builder (vtable, domain,
1214 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1215 for (i = 0; i < imt_ir->len; ++i)
1216 g_free (g_ptr_array_index (imt_ir, i));
1217 g_ptr_array_free (imt_ir, TRUE);
1229 static MonoImtBuilderEntry*
1230 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1233 * LOCKING: requires the loader and domain locks.
1237 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1241 guint32 imt_collisions_bitmap = 0;
1242 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1243 int method_count = 0;
1244 gboolean record_method_count_for_max_collisions = FALSE;
1245 gboolean has_generic_virtual = FALSE;
1248 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1250 for (i = 0; i < klass->interface_offsets_count; ++i) {
1251 MonoClass *iface = klass->interfaces_packed [i];
1252 int interface_offset = klass->interface_offsets_packed [i];
1253 int method_slot_in_interface;
1254 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1257 if (slot_num >= 0 && iface->is_inflated) {
1259 * The imt slot of the method is the same as for its declaring method,
1260 * see the comment in mono_method_get_imt_slot (), so we can
1261 * avoid inflating methods which will be discarded by
1262 * add_imt_builder_entry anyway.
1264 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1265 if (mono_method_get_imt_slot (method) != slot_num)
1268 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1269 if (method->is_generic) {
1270 has_generic_virtual = TRUE;
1273 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1276 if (extra_interfaces) {
1277 int interface_offset = klass->vtable_size;
1279 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1280 MonoClass* iface = list_item->data;
1281 int method_slot_in_interface;
1282 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1283 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1284 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1286 interface_offset += iface->method.count;
1289 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1290 /* overwrite the imt slot only if we're building all the entries or if
1291 * we're building this specific one
1293 if (slot_num < 0 || i == slot_num) {
1294 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1297 if (imt_builder [i]) {
1298 MonoImtBuilderEntry *entry;
1300 /* Link entries with imt_builder [i] */
1301 for (entry = entries; entry->next; entry = entry->next)
1303 entry->next = imt_builder [i];
1304 entries->children += imt_builder [i]->children + 1;
1306 imt_builder [i] = entries;
1309 if (has_generic_virtual) {
1311 * There might be collisions later when the the thunk is expanded.
1313 imt_collisions_bitmap |= (1 << i);
1316 * The IMT thunk might be called with an instance of one of the
1317 * generic virtual methods, so has to fallback to the IMT trampoline.
1319 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1321 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1325 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1327 if (imt_builder [i] != NULL) {
1328 int methods_in_slot = imt_builder [i]->children + 1;
1329 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1330 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1331 record_method_count_for_max_collisions = TRUE;
1333 method_count += methods_in_slot;
1337 mono_stats.imt_number_of_methods += method_count;
1338 if (record_method_count_for_max_collisions) {
1339 mono_stats.imt_method_count_when_max_collisions = method_count;
1342 for (i = 0; i < MONO_IMT_SIZE; i++) {
1343 MonoImtBuilderEntry* entry = imt_builder [i];
1344 while (entry != NULL) {
1345 MonoImtBuilderEntry* next = entry->next;
1351 /* we OR the bitmap since we may build just a single imt slot at a time */
1352 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1356 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1357 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1361 * mono_vtable_build_imt_slot:
1362 * @vtable: virtual object table struct
1363 * @imt_slot: slot in the IMT table
1365 * Fill the given @imt_slot in the IMT table of @vtable with
1366 * a trampoline or a thunk for the case of collisions.
1367 * This is part of the internal mono API.
1369 * LOCKING: Take the domain lock.
1372 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1374 gpointer *imt = (gpointer*)vtable;
1375 imt -= MONO_IMT_SIZE;
1376 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1378 /* no support for extra interfaces: the proxy objects will need
1379 * to build the complete IMT
1380 * Update and heck needs to ahppen inside the proper domain lock, as all
1381 * the changes made to a MonoVTable.
1383 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1384 mono_domain_lock (vtable->domain);
1385 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1386 if (imt [imt_slot] == imt_trampoline)
1387 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1388 mono_domain_unlock (vtable->domain);
1389 mono_loader_unlock ();
1394 * The first two free list entries both belong to the wait list: The
1395 * first entry is the pointer to the head of the list and the second
1396 * entry points to the last element. That way appending and removing
1397 * the first element are both O(1) operations.
1399 #define NUM_FREE_LISTS 12
1400 #define FIRST_FREE_LIST_SIZE 64
1401 #define MAX_WAIT_LENGTH 50
1402 #define THUNK_THRESHOLD 10
1405 * LOCKING: The domain lock must be held.
1408 init_thunk_free_lists (MonoDomain *domain)
1410 if (domain->thunk_free_lists)
1412 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1416 list_index_for_size (int item_size)
1419 int size = FIRST_FREE_LIST_SIZE;
1421 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1430 * mono_method_alloc_generic_virtual_thunk:
1432 * @size: size in bytes
1434 * Allocs size bytes to be used for the code of a generic virtual
1435 * thunk. It's either allocated from the domain's code manager or
1436 * reused from a previously invalidated piece.
1438 * LOCKING: The domain lock must be held.
1441 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1443 static gboolean inited = FALSE;
1444 static int generic_virtual_thunks_size = 0;
1448 MonoThunkFreeList **l;
1450 init_thunk_free_lists (domain);
1452 size += sizeof (guint32);
1453 if (size < sizeof (MonoThunkFreeList))
1454 size = sizeof (MonoThunkFreeList);
1456 i = list_index_for_size (size);
1457 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1458 if ((*l)->size >= size) {
1459 MonoThunkFreeList *item = *l;
1461 return ((guint32*)item) + 1;
1465 /* no suitable item found - search lists of larger sizes */
1466 while (++i < NUM_FREE_LISTS) {
1467 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1470 g_assert (item->size > size);
1471 domain->thunk_free_lists [i] = item->next;
1472 return ((guint32*)item) + 1;
1475 /* still nothing found - allocate it */
1477 mono_counters_register ("Generic virtual thunk bytes",
1478 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1481 generic_virtual_thunks_size += size;
1483 p = mono_domain_code_reserve (domain, size);
1490 * LOCKING: The domain lock must be held.
1493 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1496 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1498 init_thunk_free_lists (domain);
1500 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1501 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1502 int length = item->length;
1505 /* unlink the first item from the wait list */
1506 domain->thunk_free_lists [0] = item->next;
1507 domain->thunk_free_lists [0]->length = length - 1;
1509 i = list_index_for_size (item->size);
1511 /* put it in the free list */
1512 item->next = domain->thunk_free_lists [i];
1513 domain->thunk_free_lists [i] = item;
1517 if (domain->thunk_free_lists [1]) {
1518 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1519 domain->thunk_free_lists [0]->length++;
1521 g_assert (!domain->thunk_free_lists [0]);
1523 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1524 domain->thunk_free_lists [0]->length = 1;
1528 typedef struct _GenericVirtualCase {
1532 struct _GenericVirtualCase *next;
1533 } GenericVirtualCase;
1536 * get_generic_virtual_entries:
1538 * Return IMT entries for the generic virtual method instances for vtable slot
1541 static MonoImtBuilderEntry*
1542 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1544 GenericVirtualCase *list;
1545 MonoImtBuilderEntry *entries;
1547 mono_domain_lock (domain);
1548 if (!domain->generic_virtual_cases)
1549 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1551 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1554 for (; list; list = list->next) {
1555 MonoImtBuilderEntry *entry;
1557 if (list->count < THUNK_THRESHOLD)
1560 entry = g_new0 (MonoImtBuilderEntry, 1);
1561 entry->key = list->method;
1562 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1563 entry->has_target_code = 1;
1565 entry->children = entries->children + 1;
1566 entry->next = entries;
1570 mono_domain_unlock (domain);
1572 /* FIXME: Leaking memory ? */
1577 * mono_method_add_generic_virtual_invocation:
1579 * @vtable_slot: pointer to the vtable slot
1580 * @method: the inflated generic virtual method
1581 * @code: the method's code
1583 * Registers a call via unmanaged code to a generic virtual method
1584 * instantiation. If the number of calls reaches a threshold
1585 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1586 * virtual method thunk.
1589 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1590 gpointer *vtable_slot,
1591 MonoMethod *method, gpointer code)
1593 static gboolean inited = FALSE;
1594 static int num_added = 0;
1596 GenericVirtualCase *gvc, *list;
1597 MonoImtBuilderEntry *entries;
1601 mono_domain_lock (domain);
1602 if (!domain->generic_virtual_cases)
1603 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1605 /* Check whether the case was already added */
1606 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1609 if (gvc->method == method)
1614 /* If not found, make a new one */
1616 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1617 gvc->method = method;
1620 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1622 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1625 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1631 if (++gvc->count == THUNK_THRESHOLD) {
1632 gpointer *old_thunk = *vtable_slot;
1634 if ((gpointer)vtable_slot < (gpointer)vtable)
1635 /* Force the rebuild of the thunk at the next call */
1636 *vtable_slot = imt_trampoline;
1638 entries = get_generic_virtual_entries (domain, vtable_slot);
1640 sorted = imt_sort_slot_entries (entries);
1642 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1646 MonoImtBuilderEntry *next = entries->next;
1651 for (i = 0; i < sorted->len; ++i)
1652 g_free (g_ptr_array_index (sorted, i));
1653 g_ptr_array_free (sorted, TRUE);
1656 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1657 invalidate_generic_virtual_thunk (domain, old_thunk);
1660 mono_domain_unlock (domain);
1663 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1666 * mono_class_vtable:
1667 * @domain: the application domain
1668 * @class: the class to initialize
1670 * VTables are domain specific because we create domain specific code, and
1671 * they contain the domain specific static class data.
1672 * On failure, NULL is returned, and class->exception_type is set.
1675 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1677 return mono_class_vtable_full (domain, class, FALSE);
1681 * mono_class_vtable_full:
1682 * @domain: the application domain
1683 * @class: the class to initialize
1684 * @raise_on_error if an exception should be raised on failure or not
1686 * VTables are domain specific because we create domain specific code, and
1687 * they contain the domain specific static class data.
1690 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1692 MonoClassRuntimeInfo *runtime_info;
1696 if (class->exception_type) {
1698 mono_raise_exception (mono_class_get_exception_for_failure (class));
1702 /* this check can be inlined in jitted code, too */
1703 runtime_info = class->runtime_info;
1704 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1705 return runtime_info->domain_vtables [domain->domain_id];
1706 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1710 * mono_class_try_get_vtable:
1711 * @domain: the application domain
1712 * @class: the class to initialize
1714 * This function tries to get the associated vtable from @class if
1715 * it was already created.
1718 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1720 MonoClassRuntimeInfo *runtime_info;
1724 runtime_info = class->runtime_info;
1725 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1726 return runtime_info->domain_vtables [domain->domain_id];
1731 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1734 MonoClassRuntimeInfo *runtime_info, *old_info;
1735 MonoClassField *field;
1738 int imt_table_bytes = 0;
1739 guint32 vtable_size, class_size;
1742 gpointer *interface_offsets;
1744 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1745 mono_domain_lock (domain);
1746 runtime_info = class->runtime_info;
1747 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1748 mono_domain_unlock (domain);
1749 mono_loader_unlock ();
1750 return runtime_info->domain_vtables [domain->domain_id];
1752 if (!class->inited || class->exception_type) {
1753 if (!mono_class_init (class) || class->exception_type){
1755 mono_domain_unlock (domain);
1756 mono_loader_unlock ();
1758 mono_raise_exception (mono_class_get_exception_for_failure (class));
1764 * For some classes, mono_class_init () already computed class->vtable_size, and
1765 * that is all that is needed because of the vtable trampolines.
1767 if (!class->vtable_size)
1768 mono_class_setup_vtable (class);
1770 if (class->exception_type) {
1771 mono_domain_unlock (domain);
1772 mono_loader_unlock ();
1774 mono_raise_exception (mono_class_get_exception_for_failure (class));
1779 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1780 if (class->interface_offsets_count) {
1781 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1782 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1783 mono_stats.imt_number_of_tables++;
1784 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1787 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1788 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1791 mono_stats.used_class_count++;
1792 mono_stats.class_vtable_size += vtable_size;
1793 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1796 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1798 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1800 vt->rank = class->rank;
1801 vt->domain = domain;
1803 mono_class_compute_gc_descriptor (class);
1805 * We can't use typed allocation in the non-root domains, since the
1806 * collector needs the GC descriptor stored in the vtable even after
1807 * the mempool containing the vtable is destroyed when the domain is
1808 * unloaded. An alternative might be to allocate vtables in the GC
1809 * heap, but this does not seem to work (it leads to crashes inside
1810 * libgc). If that approach is tried, two gc descriptors need to be
1811 * allocated for each class: one for the root domain, and one for all
1812 * other domains. The second descriptor should contain a bit for the
1813 * vtable field in MonoObject, since we can no longer assume the
1814 * vtable is reachable by other roots after the appdomain is unloaded.
1816 #ifdef HAVE_BOEHM_GC
1817 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1818 vt->gc_descr = GC_NO_DESCRIPTOR;
1821 vt->gc_descr = class->gc_descr;
1823 if ((class_size = mono_class_data_size (class))) {
1824 if (class->has_static_refs) {
1825 gpointer statics_gc_descr;
1827 gsize default_bitmap [4] = {0};
1830 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1831 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1832 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1833 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1834 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1835 if (bitmap != default_bitmap)
1838 vt->data = mono_domain_alloc0 (domain, class_size);
1840 mono_stats.class_static_data_size += class_size;
1845 while ((field = mono_class_get_fields (class, &iter))) {
1846 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1848 if (mono_field_is_deleted (field))
1850 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1851 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1852 if (special_static != SPECIAL_STATIC_NONE) {
1853 guint32 size, offset;
1855 size = mono_type_size (field->type, &align);
1856 offset = mono_alloc_special_static_data (special_static, size, align);
1857 if (!domain->special_static_fields)
1858 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1859 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1861 * This marks the field as special static to speed up the
1862 * checks in mono_field_static_get/set_value ().
1868 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1869 MonoClass *fklass = mono_class_from_mono_type (field->type);
1870 const char *data = mono_field_get_data (field);
1872 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1873 t = (char*)vt->data + field->offset;
1874 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1877 if (fklass->valuetype) {
1878 memcpy (t, data, mono_class_value_size (fklass, NULL));
1880 /* it's a pointer type: add check */
1881 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1888 vt->max_interface_id = class->max_interface_id;
1889 vt->interface_bitmap = class->interface_bitmap;
1891 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1892 // class->name, class->interface_offsets_count);
1894 if (! ARCH_USE_IMT) {
1895 /* initialize interface offsets */
1896 for (i = 0; i < class->interface_offsets_count; ++i) {
1897 int interface_id = class->interfaces_packed [i]->interface_id;
1898 int slot = class->interface_offsets_packed [i];
1899 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1903 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1904 * as we change the code in appdomain.c to invalidate vtables by
1905 * looking at the possible MonoClasses created for the domain.
1907 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1908 /* class->runtime_info is protected by the loader lock, both when
1909 * it it enlarged and when it is stored info.
1912 old_info = class->runtime_info;
1913 if (old_info && old_info->max_domain >= domain->domain_id) {
1914 /* someone already created a large enough runtime info */
1915 mono_memory_barrier ();
1916 old_info->domain_vtables [domain->domain_id] = vt;
1918 int new_size = domain->domain_id;
1920 new_size = MAX (new_size, old_info->max_domain);
1922 /* make the new size a power of two */
1924 while (new_size > i)
1927 /* this is a bounded memory retention issue: may want to
1928 * handle it differently when we'll have a rcu-like system.
1930 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1931 runtime_info->max_domain = new_size - 1;
1932 /* copy the stuff from the older info */
1934 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1936 runtime_info->domain_vtables [domain->domain_id] = vt;
1938 mono_memory_barrier ();
1939 class->runtime_info = runtime_info;
1942 /* Initialize vtable */
1943 if (vtable_trampoline) {
1944 // This also covers the AOT case
1945 for (i = 0; i < class->vtable_size; ++i) {
1946 vt->vtable [i] = vtable_trampoline;
1949 mono_class_setup_vtable (class);
1951 for (i = 0; i < class->vtable_size; ++i) {
1954 if ((cm = class->vtable [i]))
1955 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1959 if (ARCH_USE_IMT && imt_table_bytes) {
1960 /* Now that the vtable is full, we can actually fill up the IMT */
1961 if (imt_trampoline) {
1962 /* lazy construction of the IMT entries enabled */
1963 for (i = 0; i < MONO_IMT_SIZE; ++i)
1964 interface_offsets [i] = imt_trampoline;
1966 build_imt (class, vt, domain, interface_offsets, NULL);
1970 mono_domain_unlock (domain);
1971 mono_loader_unlock ();
1973 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1974 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
1975 mono_raise_exception (mono_class_get_exception_for_failure (class));
1977 /* make sure the parent is initialized */
1978 /*FIXME shouldn't this fail the current type?*/
1980 mono_class_vtable_full (domain, class->parent, raise_on_error);
1982 /*FIXME check for OOM*/
1983 vt->type = mono_type_get_object (domain, &class->byval_arg);
1984 if (class->contextbound)
1993 * mono_class_proxy_vtable:
1994 * @domain: the application domain
1995 * @remove_class: the remote class
1997 * Creates a vtable for transparent proxies. It is basically
1998 * a copy of the real vtable of the class wrapped in @remote_class,
1999 * but all function pointers invoke the remoting functions, and
2000 * vtable->klass points to the transparent proxy class, and not to @class.
2003 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2005 MonoVTable *vt, *pvt;
2006 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2008 GSList *extra_interfaces = NULL;
2009 MonoClass *class = remote_class->proxy_class;
2010 gpointer *interface_offsets;
2012 vt = mono_class_vtable (domain, class);
2013 max_interface_id = vt->max_interface_id;
2015 /* Calculate vtable space for extra interfaces */
2016 for (j = 0; j < remote_class->interface_count; j++) {
2017 MonoClass* iclass = remote_class->interfaces[j];
2021 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2022 continue; /* interface implemented by the class */
2023 if (g_slist_find (extra_interfaces, iclass))
2026 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2028 method_count = mono_class_num_methods (iclass);
2030 ifaces = mono_class_get_implemented_interfaces (iclass);
2032 for (i = 0; i < ifaces->len; ++i) {
2033 MonoClass *ic = g_ptr_array_index (ifaces, i);
2034 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2035 continue; /* interface implemented by the class */
2036 if (g_slist_find (extra_interfaces, ic))
2038 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2039 method_count += mono_class_num_methods (ic);
2041 g_ptr_array_free (ifaces, TRUE);
2044 extra_interface_vtsize += method_count * sizeof (gpointer);
2045 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2049 mono_stats.imt_number_of_tables++;
2050 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2051 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2052 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2054 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2055 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2058 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2060 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2062 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2064 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2065 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2067 pvt->klass = mono_defaults.transparent_proxy_class;
2068 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2069 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2071 /* initialize vtable */
2072 mono_class_setup_vtable (class);
2073 for (i = 0; i < class->vtable_size; ++i) {
2076 if ((cm = class->vtable [i]))
2077 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2079 pvt->vtable [i] = NULL;
2082 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2083 /* create trampolines for abstract methods */
2084 for (k = class; k; k = k->parent) {
2086 gpointer iter = NULL;
2087 while ((m = mono_class_get_methods (k, &iter)))
2088 if (!pvt->vtable [m->slot])
2089 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2093 pvt->max_interface_id = max_interface_id;
2094 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2096 if (! ARCH_USE_IMT) {
2097 /* initialize interface offsets */
2098 for (i = 0; i < class->interface_offsets_count; ++i) {
2099 int interface_id = class->interfaces_packed [i]->interface_id;
2100 int slot = class->interface_offsets_packed [i];
2101 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2104 for (i = 0; i < class->interface_offsets_count; ++i) {
2105 int interface_id = class->interfaces_packed [i]->interface_id;
2106 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2109 if (extra_interfaces) {
2110 int slot = class->vtable_size;
2116 /* Create trampolines for the methods of the interfaces */
2117 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2118 interf = list_item->data;
2120 if (! ARCH_USE_IMT) {
2121 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2123 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2127 while ((cm = mono_class_get_methods (interf, &iter)))
2128 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2130 slot += mono_class_num_methods (interf);
2132 if (! ARCH_USE_IMT) {
2133 g_slist_free (extra_interfaces);
2138 /* Now that the vtable is full, we can actually fill up the IMT */
2139 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2140 if (extra_interfaces) {
2141 g_slist_free (extra_interfaces);
2149 * mono_class_field_is_special_static:
2151 * Returns whether @field is a thread/context static field.
2154 mono_class_field_is_special_static (MonoClassField *field)
2156 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2158 if (mono_field_is_deleted (field))
2160 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2161 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2168 * mono_class_has_special_static_fields:
2170 * Returns whenever @klass has any thread/context static fields.
2173 mono_class_has_special_static_fields (MonoClass *klass)
2175 MonoClassField *field;
2179 while ((field = mono_class_get_fields (klass, &iter))) {
2180 g_assert (field->parent == klass);
2181 if (mono_class_field_is_special_static (field))
2189 * create_remote_class_key:
2190 * Creates an array of pointers that can be used as a hash key for a remote class.
2191 * The first element of the array is the number of pointers.
2194 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2199 if (remote_class == NULL) {
2200 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2201 key = g_malloc (sizeof(gpointer) * 3);
2202 key [0] = GINT_TO_POINTER (2);
2203 key [1] = mono_defaults.marshalbyrefobject_class;
2204 key [2] = extra_class;
2206 key = g_malloc (sizeof(gpointer) * 2);
2207 key [0] = GINT_TO_POINTER (1);
2208 key [1] = extra_class;
2211 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2212 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2213 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2214 key [1] = remote_class->proxy_class;
2216 // Keep the list of interfaces sorted
2217 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2218 if (extra_class && remote_class->interfaces [i] > extra_class) {
2219 key [j++] = extra_class;
2222 key [j] = remote_class->interfaces [i];
2225 key [j] = extra_class;
2227 // Replace the old class. The interface list is the same
2228 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2229 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2230 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2231 for (i = 0; i < remote_class->interface_count; i++)
2232 key [2 + i] = remote_class->interfaces [i];
2240 * copy_remote_class_key:
2242 * Make a copy of KEY in the domain and return the copy.
2245 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2247 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2248 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2250 memcpy (mp_key, key, key_size);
2256 * mono_remote_class:
2257 * @domain: the application domain
2258 * @class_name: name of the remote class
2260 * Creates and initializes a MonoRemoteClass object for a remote type.
2264 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2266 MonoRemoteClass *rc;
2267 gpointer* key, *mp_key;
2269 key = create_remote_class_key (NULL, proxy_class);
2271 mono_domain_lock (domain);
2272 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2276 mono_domain_unlock (domain);
2280 mp_key = copy_remote_class_key (domain, key);
2284 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2285 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2286 rc->interface_count = 1;
2287 rc->interfaces [0] = proxy_class;
2288 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2290 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2291 rc->interface_count = 0;
2292 rc->proxy_class = proxy_class;
2295 rc->default_vtable = NULL;
2296 rc->xdomain_vtable = NULL;
2297 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2298 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2300 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2302 mono_domain_unlock (domain);
2307 * clone_remote_class:
2308 * Creates a copy of the remote_class, adding the provided class or interface
2310 static MonoRemoteClass*
2311 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2313 MonoRemoteClass *rc;
2314 gpointer* key, *mp_key;
2316 key = create_remote_class_key (remote_class, extra_class);
2317 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2323 mp_key = copy_remote_class_key (domain, key);
2327 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2329 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2330 rc->proxy_class = remote_class->proxy_class;
2331 rc->interface_count = remote_class->interface_count + 1;
2333 // Keep the list of interfaces sorted, since the hash key of
2334 // the remote class depends on this
2335 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2336 if (remote_class->interfaces [i] > extra_class && i == j)
2337 rc->interfaces [j++] = extra_class;
2338 rc->interfaces [j] = remote_class->interfaces [i];
2341 rc->interfaces [j] = extra_class;
2343 // Replace the old class. The interface array is the same
2344 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2345 rc->proxy_class = extra_class;
2346 rc->interface_count = remote_class->interface_count;
2347 if (rc->interface_count > 0)
2348 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2351 rc->default_vtable = NULL;
2352 rc->xdomain_vtable = NULL;
2353 rc->proxy_class_name = remote_class->proxy_class_name;
2355 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2361 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2363 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2364 mono_domain_lock (domain);
2365 if (rp->target_domain_id != -1) {
2366 if (remote_class->xdomain_vtable == NULL)
2367 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2368 mono_domain_unlock (domain);
2369 mono_loader_unlock ();
2370 return remote_class->xdomain_vtable;
2372 if (remote_class->default_vtable == NULL) {
2375 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2376 klass = mono_class_from_mono_type (type);
2377 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2378 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2380 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2383 mono_domain_unlock (domain);
2384 mono_loader_unlock ();
2385 return remote_class->default_vtable;
2389 * mono_upgrade_remote_class:
2390 * @domain: the application domain
2391 * @tproxy: the proxy whose remote class has to be upgraded.
2392 * @klass: class to which the remote class can be casted.
2394 * Updates the vtable of the remote class by adding the necessary method slots
2395 * and interface offsets so it can be safely casted to klass. klass can be a
2396 * class or an interface.
2399 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2401 MonoTransparentProxy *tproxy;
2402 MonoRemoteClass *remote_class;
2403 gboolean redo_vtable;
2405 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2406 mono_domain_lock (domain);
2408 tproxy = (MonoTransparentProxy*) proxy_object;
2409 remote_class = tproxy->remote_class;
2411 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2414 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2415 if (remote_class->interfaces [i] == klass)
2416 redo_vtable = FALSE;
2419 redo_vtable = (remote_class->proxy_class != klass);
2423 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2424 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2427 mono_domain_unlock (domain);
2428 mono_loader_unlock ();
2433 * mono_object_get_virtual_method:
2434 * @obj: object to operate on.
2437 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2438 * the instance of a callvirt of method.
2441 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2444 MonoMethod **vtable;
2446 MonoMethod *res = NULL;
2448 klass = mono_object_class (obj);
2449 if (klass == mono_defaults.transparent_proxy_class) {
2450 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2456 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2459 mono_class_setup_vtable (klass);
2460 vtable = klass->vtable;
2462 if (method->slot == -1) {
2463 /* method->slot might not be set for instances of generic methods */
2464 if (method->is_inflated) {
2465 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2466 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2469 g_assert_not_reached ();
2473 /* check method->slot is a valid index: perform isinstance? */
2474 if (method->slot != -1) {
2475 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2477 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2479 res = vtable [method->slot];
2484 /* It may be an interface, abstract class method or generic method */
2485 if (!res || mono_method_signature (res)->generic_param_count)
2488 /* generic methods demand invoke_with_check */
2489 if (mono_method_signature (res)->generic_param_count)
2490 res = mono_marshal_get_remoting_invoke_with_check (res);
2493 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2494 res = mono_cominterop_get_invoke (res);
2497 res = mono_marshal_get_remoting_invoke (res);
2500 if (method->is_inflated) {
2501 /* Have to inflate the result */
2502 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2512 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2514 g_error ("runtime invoke called on uninitialized runtime");
2518 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2521 * mono_runtime_invoke:
2522 * @method: method to invoke
2523 * @obJ: object instance
2524 * @params: arguments to the method
2525 * @exc: exception information.
2527 * Invokes the method represented by @method on the object @obj.
2529 * obj is the 'this' pointer, it should be NULL for static
2530 * methods, a MonoObject* for object instances and a pointer to
2531 * the value type for value types.
2533 * The params array contains the arguments to the method with the
2534 * same convention: MonoObject* pointers for object instances and
2535 * pointers to the value type otherwise.
2537 * From unmanaged code you'll usually use the
2538 * mono_runtime_invoke() variant.
2540 * Note that this function doesn't handle virtual methods for
2541 * you, it will exec the exact method you pass: we still need to
2542 * expose a function to lookup the derived class implementation
2543 * of a virtual method (there are examples of this in the code,
2546 * You can pass NULL as the exc argument if you don't want to
2547 * catch exceptions, otherwise, *exc will be set to the exception
2548 * thrown, if any. if an exception is thrown, you can't use the
2549 * MonoObject* result from the function.
2551 * If the method returns a value type, it is boxed in an object
2555 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2557 if (mono_runtime_get_no_exec ())
2558 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2560 return default_mono_runtime_invoke (method, obj, params, exc);
2564 * mono_method_get_unmanaged_thunk:
2565 * @method: method to generate a thunk for.
2567 * Returns an unmanaged->managed thunk that can be used to call
2568 * a managed method directly from C.
2570 * The thunk's C signature closely matches the managed signature:
2572 * C#: public bool Equals (object obj);
2573 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2574 * MonoObject*, MonoException**);
2576 * The 1st ("this") parameter must not be used with static methods:
2578 * C#: public static bool ReferenceEquals (object a, object b);
2579 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2582 * The last argument must be a non-null pointer of a MonoException* pointer.
2583 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2584 * exception has been thrown in managed code. Otherwise it will point
2585 * to the MonoException* caught by the thunk. In this case, the result of
2586 * the thunk is undefined:
2588 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2589 * MonoException *ex = NULL;
2590 * Equals func = mono_method_get_unmanaged_thunk (method);
2591 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2593 * // handle exception
2596 * The calling convention of the thunk matches the platform's default
2597 * convention. This means that under Windows, C declarations must
2598 * contain the __stdcall attribute:
2600 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2601 * MonoObject*, MonoException**);
2605 * Value type arguments and return values are treated as they were objects:
2607 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2608 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2610 * Arguments must be properly boxed upon trunk's invocation, while return
2611 * values must be unboxed.
2614 mono_method_get_unmanaged_thunk (MonoMethod *method)
2616 method = mono_marshal_get_thunk_invoke_wrapper (method);
2617 return mono_compile_method (method);
2621 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2625 /* object fields cannot be byref, so we don't need a
2627 gpointer *p = (gpointer*)dest;
2634 case MONO_TYPE_BOOLEAN:
2636 case MONO_TYPE_U1: {
2637 guint8 *p = (guint8*)dest;
2638 *p = value ? *(guint8*)value : 0;
2643 case MONO_TYPE_CHAR: {
2644 guint16 *p = (guint16*)dest;
2645 *p = value ? *(guint16*)value : 0;
2648 #if SIZEOF_VOID_P == 4
2653 case MONO_TYPE_U4: {
2654 gint32 *p = (gint32*)dest;
2655 *p = value ? *(gint32*)value : 0;
2658 #if SIZEOF_VOID_P == 8
2663 case MONO_TYPE_U8: {
2664 gint64 *p = (gint64*)dest;
2665 *p = value ? *(gint64*)value : 0;
2668 case MONO_TYPE_R4: {
2669 float *p = (float*)dest;
2670 *p = value ? *(float*)value : 0;
2673 case MONO_TYPE_R8: {
2674 double *p = (double*)dest;
2675 *p = value ? *(double*)value : 0;
2678 case MONO_TYPE_STRING:
2679 case MONO_TYPE_SZARRAY:
2680 case MONO_TYPE_CLASS:
2681 case MONO_TYPE_OBJECT:
2682 case MONO_TYPE_ARRAY:
2683 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2685 case MONO_TYPE_FNPTR:
2686 case MONO_TYPE_PTR: {
2687 gpointer *p = (gpointer*)dest;
2688 *p = deref_pointer? *(gpointer*)value: value;
2691 case MONO_TYPE_VALUETYPE:
2692 /* note that 't' and 'type->type' can be different */
2693 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2694 t = mono_class_enum_basetype (type->data.klass)->type;
2697 MonoClass *class = mono_class_from_mono_type (type);
2698 int size = mono_class_value_size (class, NULL);
2699 if (value == NULL) {
2700 memset (dest, 0, size);
2702 memcpy (dest, value, size);
2703 mono_gc_wbarrier_value_copy (dest, value, size, class);
2707 case MONO_TYPE_GENERICINST:
2708 t = type->data.generic_class->container_class->byval_arg.type;
2711 g_warning ("got type %x", type->type);
2712 g_assert_not_reached ();
2717 * mono_field_set_value:
2718 * @obj: Instance object
2719 * @field: MonoClassField describing the field to set
2720 * @value: The value to be set
2722 * Sets the value of the field described by @field in the object instance @obj
2723 * to the value passed in @value. This method should only be used for instance
2724 * fields. For static fields, use mono_field_static_set_value.
2726 * The value must be on the native format of the field type.
2729 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2733 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2735 dest = (char*)obj + field->offset;
2736 set_value (field->type, dest, value, FALSE);
2740 * mono_field_static_set_value:
2741 * @field: MonoClassField describing the field to set
2742 * @value: The value to be set
2744 * Sets the value of the static field described by @field
2745 * to the value passed in @value.
2747 * The value must be on the native format of the field type.
2750 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2754 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2755 /* you cant set a constant! */
2756 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2758 if (field->offset == -1) {
2759 /* Special static */
2760 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2761 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2763 dest = (char*)vt->data + field->offset;
2765 set_value (field->type, dest, value, FALSE);
2768 /* Used by the debugger */
2770 mono_vtable_get_static_field_data (MonoVTable *vt)
2776 * mono_field_get_value:
2777 * @obj: Object instance
2778 * @field: MonoClassField describing the field to fetch information from
2779 * @value: pointer to the location where the value will be stored
2781 * Use this routine to get the value of the field @field in the object
2784 * The pointer provided by value must be of the field type, for reference
2785 * types this is a MonoObject*, for value types its the actual pointer to
2790 * mono_field_get_value (obj, int_field, &i);
2793 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2797 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2799 src = (char*)obj + field->offset;
2800 set_value (field->type, value, src, TRUE);
2804 * mono_field_get_value_object:
2805 * @domain: domain where the object will be created (if boxing)
2806 * @field: MonoClassField describing the field to fetch information from
2807 * @obj: The object instance for the field.
2809 * Returns: a new MonoObject with the value from the given field. If the
2810 * field represents a value type, the value is boxed.
2814 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2818 MonoVTable *vtable = NULL;
2820 gboolean is_static = FALSE;
2821 gboolean is_ref = FALSE;
2823 switch (field->type->type) {
2824 case MONO_TYPE_STRING:
2825 case MONO_TYPE_OBJECT:
2826 case MONO_TYPE_CLASS:
2827 case MONO_TYPE_ARRAY:
2828 case MONO_TYPE_SZARRAY:
2833 case MONO_TYPE_BOOLEAN:
2836 case MONO_TYPE_CHAR:
2845 case MONO_TYPE_VALUETYPE:
2846 is_ref = field->type->byref;
2848 case MONO_TYPE_GENERICINST:
2849 is_ref = !field->type->data.generic_class->container_class->valuetype;
2852 g_error ("type 0x%x not handled in "
2853 "mono_field_get_value_object", field->type->type);
2857 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2859 vtable = mono_class_vtable (domain, field->parent);
2860 if (!vtable->initialized)
2861 mono_runtime_class_init (vtable);
2866 mono_field_static_get_value (vtable, field, &o);
2868 mono_field_get_value (obj, field, &o);
2873 /* boxed value type */
2874 klass = mono_class_from_mono_type (field->type);
2875 o = mono_object_new (domain, klass);
2876 v = ((gchar *) o) + sizeof (MonoObject);
2878 mono_field_static_get_value (vtable, field, v);
2880 mono_field_get_value (obj, field, v);
2887 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2890 const char *p = blob;
2891 mono_metadata_decode_blob_size (p, &p);
2894 case MONO_TYPE_BOOLEAN:
2897 *(guint8 *) value = *p;
2899 case MONO_TYPE_CHAR:
2902 *(guint16*) value = read16 (p);
2906 *(guint32*) value = read32 (p);
2910 *(guint64*) value = read64 (p);
2913 readr4 (p, (float*) value);
2916 readr8 (p, (double*) value);
2918 case MONO_TYPE_STRING:
2919 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2921 case MONO_TYPE_CLASS:
2922 *(gpointer*) value = NULL;
2926 g_warning ("type 0x%02x should not be in constant table", type);
2932 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2934 MonoTypeEnum def_type;
2937 data = mono_class_get_field_default_value (field, &def_type);
2938 mono_get_constant_value_from_blob (domain, def_type, data, value);
2942 * mono_field_static_get_value:
2943 * @vt: vtable to the object
2944 * @field: MonoClassField describing the field to fetch information from
2945 * @value: where the value is returned
2947 * Use this routine to get the value of the static field @field value.
2949 * The pointer provided by value must be of the field type, for reference
2950 * types this is a MonoObject*, for value types its the actual pointer to
2955 * mono_field_static_get_value (vt, int_field, &i);
2958 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2962 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2964 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2965 get_default_field_value (vt->domain, field, value);
2969 if (field->offset == -1) {
2970 /* Special static */
2971 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2972 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2974 src = (char*)vt->data + field->offset;
2976 set_value (field->type, value, src, TRUE);
2980 * mono_property_set_value:
2981 * @prop: MonoProperty to set
2982 * @obj: instance object on which to act
2983 * @params: parameters to pass to the propery
2984 * @exc: optional exception
2986 * Invokes the property's set method with the given arguments on the
2987 * object instance obj (or NULL for static properties).
2989 * You can pass NULL as the exc argument if you don't want to
2990 * catch exceptions, otherwise, *exc will be set to the exception
2991 * thrown, if any. if an exception is thrown, you can't use the
2992 * MonoObject* result from the function.
2995 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2997 default_mono_runtime_invoke (prop->set, obj, params, exc);
3001 * mono_property_get_value:
3002 * @prop: MonoProperty to fetch
3003 * @obj: instance object on which to act
3004 * @params: parameters to pass to the propery
3005 * @exc: optional exception
3007 * Invokes the property's get method with the given arguments on the
3008 * object instance obj (or NULL for static properties).
3010 * You can pass NULL as the exc argument if you don't want to
3011 * catch exceptions, otherwise, *exc will be set to the exception
3012 * thrown, if any. if an exception is thrown, you can't use the
3013 * MonoObject* result from the function.
3015 * Returns: the value from invoking the get method on the property.
3018 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3020 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3024 * mono_nullable_init:
3025 * @buf: The nullable structure to initialize.
3026 * @value: the value to initialize from
3027 * @klass: the type for the object
3029 * Initialize the nullable structure pointed to by @buf from @value which
3030 * should be a boxed value type. The size of @buf should be able to hold
3031 * as much data as the @klass->instance_size (which is the number of bytes
3032 * that will be copies).
3034 * Since Nullables have variable structure, we can not define a C
3035 * structure for them.
3038 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3040 MonoClass *param_class = klass->cast_class;
3042 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3043 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3045 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3047 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3049 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3053 * mono_nullable_box:
3054 * @buf: The buffer representing the data to be boxed
3055 * @klass: the type to box it as.
3057 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3061 mono_nullable_box (guint8 *buf, MonoClass *klass)
3063 MonoClass *param_class = klass->cast_class;
3065 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3066 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3068 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3069 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3070 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3078 * mono_get_delegate_invoke:
3079 * @klass: The delegate class
3081 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3084 mono_get_delegate_invoke (MonoClass *klass)
3088 /* This is called at runtime, so avoid the slower search in metadata */
3089 mono_class_setup_methods (klass);
3091 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3098 * mono_runtime_delegate_invoke:
3099 * @delegate: pointer to a delegate object.
3100 * @params: parameters for the delegate.
3101 * @exc: Pointer to the exception result.
3103 * Invokes the delegate method @delegate with the parameters provided.
3105 * You can pass NULL as the exc argument if you don't want to
3106 * catch exceptions, otherwise, *exc will be set to the exception
3107 * thrown, if any. if an exception is thrown, you can't use the
3108 * MonoObject* result from the function.
3111 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3115 im = mono_get_delegate_invoke (delegate->vtable->klass);
3118 return mono_runtime_invoke (im, delegate, params, exc);
3121 static char **main_args = NULL;
3122 static int num_main_args;
3125 * mono_runtime_get_main_args:
3127 * Returns: a MonoArray with the arguments passed to the main program
3130 mono_runtime_get_main_args (void)
3134 MonoDomain *domain = mono_domain_get ();
3139 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3141 for (i = 0; i < num_main_args; ++i)
3142 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3148 fire_process_exit_event (void)
3150 MonoClassField *field;
3151 MonoDomain *domain = mono_domain_get ();
3153 MonoObject *delegate, *exc;
3155 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3158 if (domain != mono_get_root_domain ())
3161 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3162 if (delegate == NULL)
3167 mono_runtime_delegate_invoke (delegate, pa, &exc);
3171 * mono_runtime_run_main:
3172 * @method: the method to start the application with (usually Main)
3173 * @argc: number of arguments from the command line
3174 * @argv: array of strings from the command line
3175 * @exc: excetption results
3177 * Execute a standard Main() method (argc/argv contains the
3178 * executable name). This method also sets the command line argument value
3179 * needed by System.Environment.
3184 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3188 MonoArray *args = NULL;
3189 MonoDomain *domain = mono_domain_get ();
3190 gchar *utf8_fullpath;
3193 g_assert (method != NULL);
3195 mono_thread_set_main (mono_thread_current ());
3197 main_args = g_new0 (char*, argc);
3198 num_main_args = argc;
3200 if (!g_path_is_absolute (argv [0])) {
3201 gchar *basename = g_path_get_basename (argv [0]);
3202 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3206 utf8_fullpath = mono_utf8_from_external (fullpath);
3207 if(utf8_fullpath == NULL) {
3208 /* Printing the arg text will cause glib to
3209 * whinge about "Invalid UTF-8", but at least
3210 * its relevant, and shows the problem text
3213 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3214 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3221 utf8_fullpath = mono_utf8_from_external (argv[0]);
3222 if(utf8_fullpath == NULL) {
3223 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3224 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3229 main_args [0] = utf8_fullpath;
3231 for (i = 1; i < argc; ++i) {
3234 utf8_arg=mono_utf8_from_external (argv[i]);
3235 if(utf8_arg==NULL) {
3236 /* Ditto the comment about Invalid UTF-8 here */
3237 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3238 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3242 main_args [i] = utf8_arg;
3246 if (mono_method_signature (method)->param_count) {
3247 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3248 for (i = 0; i < argc; ++i) {
3249 /* The encodings should all work, given that
3250 * we've checked all these args for the
3253 gchar *str = mono_utf8_from_external (argv [i]);
3254 MonoString *arg = mono_string_new (domain, str);
3255 mono_array_setref (args, i, arg);
3259 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3262 mono_assembly_set_main (method->klass->image->assembly);
3264 result = mono_runtime_exec_main (method, args, exc);
3265 fire_process_exit_event ();
3269 /* Used in call_unhandled_exception_delegate */
3271 create_unhandled_exception_eventargs (MonoObject *exc)
3275 MonoMethod *method = NULL;
3276 MonoBoolean is_terminating = TRUE;
3279 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3282 mono_class_init (klass);
3284 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3285 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3289 args [1] = &is_terminating;
3291 obj = mono_object_new (mono_domain_get (), klass);
3292 mono_runtime_invoke (method, obj, args, NULL);
3297 /* Used in mono_unhandled_exception */
3299 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3300 MonoObject *e = NULL;
3303 pa [0] = domain->domain;
3304 pa [1] = create_unhandled_exception_eventargs (exc);
3305 mono_runtime_delegate_invoke (delegate, pa, &e);
3308 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3309 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3314 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3317 * mono_runtime_unhandled_exception_policy_set:
3318 * @policy: the new policy
3320 * This is a VM internal routine.
3322 * Sets the runtime policy for handling unhandled exceptions.
3325 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3326 runtime_unhandled_exception_policy = policy;
3330 * mono_runtime_unhandled_exception_policy_get:
3332 * This is a VM internal routine.
3334 * Gets the runtime policy for handling unhandled exceptions.
3336 MonoRuntimeUnhandledExceptionPolicy
3337 mono_runtime_unhandled_exception_policy_get (void) {
3338 return runtime_unhandled_exception_policy;
3342 * mono_unhandled_exception:
3343 * @exc: exception thrown
3345 * This is a VM internal routine.
3347 * We call this function when we detect an unhandled exception
3348 * in the default domain.
3350 * It invokes the * UnhandledException event in AppDomain or prints
3351 * a warning to the console
3354 mono_unhandled_exception (MonoObject *exc)
3356 MonoDomain *current_domain = mono_domain_get ();
3357 MonoDomain *root_domain = mono_get_root_domain ();
3358 MonoClassField *field;
3359 MonoObject *current_appdomain_delegate;
3360 MonoObject *root_appdomain_delegate;
3362 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3363 "UnhandledException");
3366 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3367 gboolean abort_process = (mono_thread_current () == main_thread) ||
3368 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3369 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3370 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3371 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3373 current_appdomain_delegate = NULL;
3376 /* set exitcode only if we will abort the process */
3378 mono_environment_exitcode_set (1);
3379 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3380 mono_print_unhandled_exception (exc);
3382 if (root_appdomain_delegate) {
3383 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3385 if (current_appdomain_delegate) {
3386 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3393 * Launch a new thread to execute a function
3395 * main_func is called back from the thread with main_args as the
3396 * parameter. The callback function is expected to start Main()
3397 * eventually. This function then waits for all managed threads to
3399 * It is not necesseray anymore to execute managed code in a subthread,
3400 * so this function should not be used anymore by default: just
3401 * execute the code and then call mono_thread_manage ().
3404 mono_runtime_exec_managed_code (MonoDomain *domain,
3405 MonoMainThreadFunc main_func,
3408 mono_thread_create (domain, main_func, main_args);
3410 mono_thread_manage ();
3414 * Execute a standard Main() method (args doesn't contain the
3418 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3423 MonoCustomAttrInfo* cinfo;
3424 gboolean has_stathread_attribute;
3425 MonoThread* thread = mono_thread_current ();
3431 domain = mono_object_domain (args);
3432 if (!domain->entry_assembly) {
3434 MonoAssembly *assembly;
3436 assembly = method->klass->image->assembly;
3437 domain->entry_assembly = assembly;
3438 /* Domains created from another domain already have application_base and configuration_file set */
3439 if (domain->setup->application_base == NULL) {
3440 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3443 if (domain->setup->configuration_file == NULL) {
3444 str = g_strconcat (assembly->image->name, ".config", NULL);
3445 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3447 mono_set_private_bin_path_from_config (domain);
3451 cinfo = mono_custom_attrs_from_method (method);
3453 static MonoClass *stathread_attribute = NULL;
3454 if (!stathread_attribute)
3455 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3456 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3458 mono_custom_attrs_free (cinfo);
3460 has_stathread_attribute = FALSE;
3462 if (has_stathread_attribute) {
3463 thread->apartment_state = ThreadApartmentState_STA;
3464 } else if (mono_framework_version () == 1) {
3465 thread->apartment_state = ThreadApartmentState_Unknown;
3467 thread->apartment_state = ThreadApartmentState_MTA;
3469 mono_thread_init_apartment_state ();
3471 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3473 /* FIXME: check signature of method */
3474 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3476 res = mono_runtime_invoke (method, NULL, pa, exc);
3478 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3482 mono_environment_exitcode_set (rval);
3484 mono_runtime_invoke (method, NULL, pa, exc);
3488 /* If the return type of Main is void, only
3489 * set the exitcode if an exception was thrown
3490 * (we don't want to blow away an
3491 * explicitly-set exit code)
3494 mono_environment_exitcode_set (rval);
3498 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3504 * mono_install_runtime_invoke:
3505 * @func: Function to install
3507 * This is a VM internal routine
3510 mono_install_runtime_invoke (MonoInvokeFunc func)
3512 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3517 * mono_runtime_invoke_array:
3518 * @method: method to invoke
3519 * @obJ: object instance
3520 * @params: arguments to the method
3521 * @exc: exception information.
3523 * Invokes the method represented by @method on the object @obj.
3525 * obj is the 'this' pointer, it should be NULL for static
3526 * methods, a MonoObject* for object instances and a pointer to
3527 * the value type for value types.
3529 * The params array contains the arguments to the method with the
3530 * same convention: MonoObject* pointers for object instances and
3531 * pointers to the value type otherwise. The _invoke_array
3532 * variant takes a C# object[] as the params argument (MonoArray
3533 * *params): in this case the value types are boxed inside the
3534 * respective reference representation.
3536 * From unmanaged code you'll usually use the
3537 * mono_runtime_invoke() variant.
3539 * Note that this function doesn't handle virtual methods for
3540 * you, it will exec the exact method you pass: we still need to
3541 * expose a function to lookup the derived class implementation
3542 * of a virtual method (there are examples of this in the code,
3545 * You can pass NULL as the exc argument if you don't want to
3546 * catch exceptions, otherwise, *exc will be set to the exception
3547 * thrown, if any. if an exception is thrown, you can't use the
3548 * MonoObject* result from the function.
3550 * If the method returns a value type, it is boxed in an object
3554 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3557 MonoMethodSignature *sig = mono_method_signature (method);
3558 gpointer *pa = NULL;
3561 gboolean has_byref_nullables = FALSE;
3563 if (NULL != params) {
3564 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3565 for (i = 0; i < mono_array_length (params); i++) {
3566 MonoType *t = sig->params [i];
3572 case MONO_TYPE_BOOLEAN:
3575 case MONO_TYPE_CHAR:
3584 case MONO_TYPE_VALUETYPE:
3585 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3586 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3587 pa [i] = mono_array_get (params, MonoObject*, i);
3589 has_byref_nullables = TRUE;
3591 /* MS seems to create the objects if a null is passed in */
3592 if (!mono_array_get (params, MonoObject*, i))
3593 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3597 * We can't pass the unboxed vtype byref to the callee, since
3598 * that would mean the callee would be able to modify boxed
3599 * primitive types. So we (and MS) make a copy of the boxed
3600 * object, pass that to the callee, and replace the original
3601 * boxed object in the arg array with the copy.
3603 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3604 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3605 mono_array_setref (params, i, copy);
3608 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3611 case MONO_TYPE_STRING:
3612 case MONO_TYPE_OBJECT:
3613 case MONO_TYPE_CLASS:
3614 case MONO_TYPE_ARRAY:
3615 case MONO_TYPE_SZARRAY:
3617 pa [i] = mono_array_addr (params, MonoObject*, i);
3618 // FIXME: I need to check this code path
3620 pa [i] = mono_array_get (params, MonoObject*, i);
3622 case MONO_TYPE_GENERICINST:
3624 t = &t->data.generic_class->container_class->this_arg;
3626 t = &t->data.generic_class->container_class->byval_arg;
3628 case MONO_TYPE_PTR: {
3631 /* The argument should be an IntPtr */
3632 arg = mono_array_get (params, MonoObject*, i);
3636 g_assert (arg->vtable->klass == mono_defaults.int_class);
3637 pa [i] = ((MonoIntPtr*)arg)->m_value;
3642 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3647 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3650 if (mono_class_is_nullable (method->klass)) {
3651 /* Need to create a boxed vtype instead */
3657 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3661 obj = mono_object_new (mono_domain_get (), method->klass);
3662 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3663 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3665 if (method->klass->valuetype)
3666 o = mono_object_unbox (obj);
3669 } else if (method->klass->valuetype) {
3670 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3673 mono_runtime_invoke (method, o, pa, exc);
3676 if (mono_class_is_nullable (method->klass)) {
3677 MonoObject *nullable;
3679 /* Convert the unboxed vtype into a Nullable structure */
3680 nullable = mono_object_new (mono_domain_get (), method->klass);
3682 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3683 obj = mono_object_unbox (nullable);
3686 /* obj must be already unboxed if needed */
3687 res = mono_runtime_invoke (method, obj, pa, exc);
3689 if (sig->ret->type == MONO_TYPE_PTR) {
3690 MonoClass *pointer_class;
3691 static MonoMethod *box_method;
3693 MonoObject *box_exc;
3696 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3697 * convert it to a Pointer object.
3699 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3701 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3703 g_assert (res->vtable->klass == mono_defaults.int_class);
3704 box_args [0] = ((MonoIntPtr*)res)->m_value;
3705 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3706 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3707 g_assert (!box_exc);
3710 if (has_byref_nullables) {
3712 * The runtime invoke wrapper already converted byref nullables back,
3713 * and stored them in pa, we just need to copy them back to the
3716 for (i = 0; i < mono_array_length (params); i++) {
3717 MonoType *t = sig->params [i];
3719 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3720 mono_array_setref (params, i, pa [i]);
3729 arith_overflow (void)
3731 mono_raise_exception (mono_get_exception_overflow ());
3735 * mono_object_allocate:
3736 * @size: number of bytes to allocate
3738 * This is a very simplistic routine until we have our GC-aware
3741 * Returns: an allocated object of size @size, or NULL on failure.
3743 static inline void *
3744 mono_object_allocate (size_t size, MonoVTable *vtable)
3747 mono_stats.new_object_count++;
3748 ALLOC_OBJECT (o, vtable, size);
3754 * mono_object_allocate_ptrfree:
3755 * @size: number of bytes to allocate
3757 * Note that the memory allocated is not zeroed.
3758 * Returns: an allocated object of size @size, or NULL on failure.
3760 static inline void *
3761 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3764 mono_stats.new_object_count++;
3765 ALLOC_PTRFREE (o, vtable, size);
3769 static inline void *
3770 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3773 ALLOC_TYPED (o, size, vtable);
3774 mono_stats.new_object_count++;
3781 * @klass: the class of the object that we want to create
3783 * Returns: a newly created object whose definition is
3784 * looked up using @klass. This will not invoke any constructors,
3785 * so the consumer of this routine has to invoke any constructors on
3786 * its own to initialize the object.
3789 mono_object_new (MonoDomain *domain, MonoClass *klass)
3791 MONO_ARCH_SAVE_REGS;
3792 return mono_object_new_specific (mono_class_vtable (domain, klass));
3796 * mono_object_new_specific:
3797 * @vtable: the vtable of the object that we want to create
3799 * Returns: A newly created object with class and domain specified
3803 mono_object_new_specific (MonoVTable *vtable)
3807 MONO_ARCH_SAVE_REGS;
3809 /* check for is_com_object for COM Interop */
3810 if (vtable->remote || vtable->klass->is_com_object)
3813 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3816 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3819 mono_class_init (klass);
3821 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3823 vtable->domain->create_proxy_for_type_method = im;
3826 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3828 o = mono_runtime_invoke (im, NULL, pa, NULL);
3829 if (o != NULL) return o;
3832 return mono_object_new_alloc_specific (vtable);
3836 mono_object_new_alloc_specific (MonoVTable *vtable)
3840 if (!vtable->klass->has_references) {
3841 o = mono_object_new_ptrfree (vtable);
3842 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3843 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3845 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3846 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3848 if (G_UNLIKELY (vtable->klass->has_finalize))
3849 mono_object_register_finalizer (o);
3851 if (G_UNLIKELY (profile_allocs))
3852 mono_profiler_allocation (o, vtable->klass);
3857 mono_object_new_fast (MonoVTable *vtable)
3860 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3865 mono_object_new_ptrfree (MonoVTable *vtable)
3868 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3869 #if NEED_TO_ZERO_PTRFREE
3870 /* an inline memset is much faster for the common vcase of small objects
3871 * note we assume the allocated size is a multiple of sizeof (void*).
3873 if (vtable->klass->instance_size < 128) {
3875 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3876 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3882 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3889 mono_object_new_ptrfree_box (MonoVTable *vtable)
3892 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3893 /* the object will be boxed right away, no need to memzero it */
3898 * mono_class_get_allocation_ftn:
3900 * @for_box: the object will be used for boxing
3901 * @pass_size_in_words:
3903 * Return the allocation function appropriate for the given class.
3907 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3909 *pass_size_in_words = FALSE;
3911 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3912 profile_allocs = FALSE;
3914 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3915 return mono_object_new_specific;
3917 if (!vtable->klass->has_references) {
3918 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3920 return mono_object_new_ptrfree_box;
3921 return mono_object_new_ptrfree;
3924 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3926 return mono_object_new_fast;
3929 * FIXME: This is actually slower than mono_object_new_fast, because
3930 * of the overhead of parameter passing.
3933 *pass_size_in_words = TRUE;
3934 #ifdef GC_REDIRECT_TO_LOCAL
3935 return GC_local_gcj_fast_malloc;
3937 return GC_gcj_fast_malloc;
3942 return mono_object_new_specific;
3946 * mono_object_new_from_token:
3947 * @image: Context where the type_token is hosted
3948 * @token: a token of the type that we want to create
3950 * Returns: A newly created object whose definition is
3951 * looked up using @token in the @image image
3954 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3958 class = mono_class_get (image, token);
3960 return mono_object_new (domain, class);
3965 * mono_object_clone:
3966 * @obj: the object to clone
3968 * Returns: A newly created object who is a shallow copy of @obj
3971 mono_object_clone (MonoObject *obj)
3976 size = obj->vtable->klass->instance_size;
3977 o = mono_object_allocate (size, obj->vtable);
3978 /* do not copy the sync state */
3979 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3982 if (obj->vtable->klass->has_references)
3983 mono_gc_wbarrier_object (o);
3985 if (G_UNLIKELY (profile_allocs))
3986 mono_profiler_allocation (o, obj->vtable->klass);
3988 if (obj->vtable->klass->has_finalize)
3989 mono_object_register_finalizer (o);
3994 * mono_array_full_copy:
3995 * @src: source array to copy
3996 * @dest: destination array
3998 * Copies the content of one array to another with exactly the same type and size.
4001 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4003 mono_array_size_t size;
4004 MonoClass *klass = src->obj.vtable->klass;
4006 MONO_ARCH_SAVE_REGS;
4008 g_assert (klass == dest->obj.vtable->klass);
4010 size = mono_array_length (src);
4011 g_assert (size == mono_array_length (dest));
4012 size *= mono_array_element_size (klass);
4014 if (klass->element_class->valuetype) {
4015 if (klass->element_class->has_references)
4016 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4018 memcpy (&dest->vector, &src->vector, size);
4020 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4023 memcpy (&dest->vector, &src->vector, size);
4028 * mono_array_clone_in_domain:
4029 * @domain: the domain in which the array will be cloned into
4030 * @array: the array to clone
4032 * This routine returns a copy of the array that is hosted on the
4033 * specified MonoDomain.
4036 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4039 mono_array_size_t size, i;
4040 mono_array_size_t *sizes;
4041 MonoClass *klass = array->obj.vtable->klass;
4043 MONO_ARCH_SAVE_REGS;
4045 if (array->bounds == NULL) {
4046 size = mono_array_length (array);
4047 o = mono_array_new_full (domain, klass, &size, NULL);
4049 size *= mono_array_element_size (klass);
4051 if (klass->element_class->valuetype) {
4052 if (klass->element_class->has_references)
4053 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4055 memcpy (&o->vector, &array->vector, size);
4057 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4060 memcpy (&o->vector, &array->vector, size);
4065 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4066 size = mono_array_element_size (klass);
4067 for (i = 0; i < klass->rank; ++i) {
4068 sizes [i] = array->bounds [i].length;
4069 size *= array->bounds [i].length;
4070 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4072 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4074 if (klass->element_class->valuetype) {
4075 if (klass->element_class->has_references)
4076 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4078 memcpy (&o->vector, &array->vector, size);
4080 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4083 memcpy (&o->vector, &array->vector, size);
4091 * @array: the array to clone
4093 * Returns: A newly created array who is a shallow copy of @array
4096 mono_array_clone (MonoArray *array)
4098 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4101 /* helper macros to check for overflow when calculating the size of arrays */
4102 #ifdef MONO_BIG_ARRAYS
4103 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4104 #define MYGUINT_MAX MYGUINT64_MAX
4105 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4106 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4107 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4108 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4109 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4111 #define MYGUINT32_MAX 4294967295U
4112 #define MYGUINT_MAX MYGUINT32_MAX
4113 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4114 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4115 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4116 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4117 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4121 * mono_array_new_full:
4122 * @domain: domain where the object is created
4123 * @array_class: array class
4124 * @lengths: lengths for each dimension in the array
4125 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4127 * This routine creates a new array objects with the given dimensions,
4128 * lower bounds and type.
4131 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4133 mono_array_size_t byte_len, len, bounds_size;
4139 if (!array_class->inited)
4140 mono_class_init (array_class);
4142 byte_len = mono_array_element_size (array_class);
4145 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4146 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4148 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4152 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4154 for (i = 0; i < array_class->rank; ++i) {
4155 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4157 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4158 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4163 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4164 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4166 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4167 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4168 byte_len += sizeof (MonoArray);
4171 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4172 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4173 byte_len = (byte_len + 3) & ~3;
4174 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4175 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4176 byte_len += bounds_size;
4179 * Following three lines almost taken from mono_object_new ():
4180 * they need to be kept in sync.
4182 vtable = mono_class_vtable (domain, array_class);
4183 if (!array_class->has_references) {
4184 o = mono_object_allocate_ptrfree (byte_len, vtable);
4185 #if NEED_TO_ZERO_PTRFREE
4186 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4188 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4189 o = mono_object_allocate_spec (byte_len, vtable);
4191 o = mono_object_allocate (byte_len, vtable);
4194 array = (MonoArray*)o;
4195 array->max_length = len;
4198 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4199 array->bounds = bounds;
4200 for (i = 0; i < array_class->rank; ++i) {
4201 bounds [i].length = lengths [i];
4203 bounds [i].lower_bound = lower_bounds [i];
4207 if (G_UNLIKELY (profile_allocs))
4208 mono_profiler_allocation (o, array_class);
4215 * @domain: domain where the object is created
4216 * @eclass: element class
4217 * @n: number of array elements
4219 * This routine creates a new szarray with @n elements of type @eclass.
4222 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4226 MONO_ARCH_SAVE_REGS;
4228 ac = mono_array_class_get (eclass, 1);
4231 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4235 * mono_array_new_specific:
4236 * @vtable: a vtable in the appropriate domain for an initialized class
4237 * @n: number of array elements
4239 * This routine is a fast alternative to mono_array_new() for code which
4240 * can be sure about the domain it operates in.
4243 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4247 guint32 byte_len, elem_size;
4249 MONO_ARCH_SAVE_REGS;
4251 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4256 elem_size = mono_array_element_size (vtable->klass);
4257 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4258 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4261 byte_len = n * elem_size;
4262 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4263 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4266 byte_len += sizeof (MonoArray);
4267 if (!vtable->klass->has_references) {
4268 o = mono_object_allocate_ptrfree (byte_len, vtable);
4269 #if NEED_TO_ZERO_PTRFREE
4270 ((MonoArray*)o)->bounds = NULL;
4271 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4273 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4274 o = mono_object_allocate_spec (byte_len, vtable);
4276 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4277 o = mono_object_allocate (byte_len, vtable);
4280 ao = (MonoArray *)o;
4282 if (G_UNLIKELY (profile_allocs))
4283 mono_profiler_allocation (o, vtable->klass);
4289 * mono_string_new_utf16:
4290 * @text: a pointer to an utf16 string
4291 * @len: the length of the string
4293 * Returns: A newly created string object which contains @text.
4296 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4300 s = mono_string_new_size (domain, len);
4301 g_assert (s != NULL);
4303 memcpy (mono_string_chars (s), text, len * 2);
4309 * mono_string_new_size:
4310 * @text: a pointer to an utf16 string
4311 * @len: the length of the string
4313 * Returns: A newly created string object of @len
4316 mono_string_new_size (MonoDomain *domain, gint32 len)
4320 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4322 /* overflow ? can't fit it, can't allocate it! */
4324 mono_gc_out_of_memory (-1);
4326 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4328 s = mono_object_allocate_ptrfree (size, vtable);
4331 #if NEED_TO_ZERO_PTRFREE
4334 if (G_UNLIKELY (profile_allocs))
4335 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4341 * mono_string_new_len:
4342 * @text: a pointer to an utf8 string
4343 * @length: number of bytes in @text to consider
4345 * Returns: A newly created string object which contains @text.
4348 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4350 GError *error = NULL;
4351 MonoString *o = NULL;
4353 glong items_written;
4355 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4358 o = mono_string_new_utf16 (domain, ut, items_written);
4360 g_error_free (error);
4369 * @text: a pointer to an utf8 string
4371 * Returns: A newly created string object which contains @text.
4374 mono_string_new (MonoDomain *domain, const char *text)
4376 GError *error = NULL;
4377 MonoString *o = NULL;
4379 glong items_written;
4384 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4387 o = mono_string_new_utf16 (domain, ut, items_written);
4389 g_error_free (error);
4392 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4397 MonoString *o = NULL;
4399 if (!g_utf8_validate (text, -1, &end))
4402 len = g_utf8_strlen (text, -1);
4403 o = mono_string_new_size (domain, len);
4404 str = mono_string_chars (o);
4406 while (text < end) {
4407 *str++ = g_utf8_get_char (text);
4408 text = g_utf8_next_char (text);
4415 * mono_string_new_wrapper:
4416 * @text: pointer to utf8 characters.
4418 * Helper function to create a string object from @text in the current domain.
4421 mono_string_new_wrapper (const char *text)
4423 MonoDomain *domain = mono_domain_get ();
4425 MONO_ARCH_SAVE_REGS;
4428 return mono_string_new (domain, text);
4435 * @class: the class of the value
4436 * @value: a pointer to the unboxed data
4438 * Returns: A newly created object which contains @value.
4441 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4447 g_assert (class->valuetype);
4448 if (mono_class_is_nullable (class))
4449 return mono_nullable_box (value, class);
4451 vtable = mono_class_vtable (domain, class);
4452 size = mono_class_instance_size (class);
4453 res = mono_object_new_alloc_specific (vtable);
4454 if (G_UNLIKELY (profile_allocs))
4455 mono_profiler_allocation (res, class);
4457 size = size - sizeof (MonoObject);
4460 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4463 #if NO_UNALIGNED_ACCESS
4464 memcpy ((char *)res + sizeof (MonoObject), value, size);
4468 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4471 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4474 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4477 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4480 memcpy ((char *)res + sizeof (MonoObject), value, size);
4483 if (class->has_finalize)
4484 mono_object_register_finalizer (res);
4490 * @dest: destination pointer
4491 * @src: source pointer
4492 * @klass: a valuetype class
4494 * Copy a valuetype from @src to @dest. This function must be used
4495 * when @klass contains references fields.
4498 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4500 int size = mono_class_value_size (klass, NULL);
4501 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4502 memcpy (dest, src, size);
4506 * mono_value_copy_array:
4507 * @dest: destination array
4508 * @dest_idx: index in the @dest array
4509 * @src: source pointer
4510 * @count: number of items
4512 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4513 * This function must be used when @klass contains references fields.
4514 * Overlap is handled.
4517 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4519 int size = mono_array_element_size (dest->obj.vtable->klass);
4520 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4521 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4522 memmove (d, src, size * count);
4526 * mono_object_get_domain:
4527 * @obj: object to query
4529 * Returns: the MonoDomain where the object is hosted
4532 mono_object_get_domain (MonoObject *obj)
4534 return mono_object_domain (obj);
4538 * mono_object_get_class:
4539 * @obj: object to query
4541 * Returns: the MonOClass of the object.
4544 mono_object_get_class (MonoObject *obj)
4546 return mono_object_class (obj);
4549 * mono_object_get_size:
4550 * @o: object to query
4552 * Returns: the size, in bytes, of @o
4555 mono_object_get_size (MonoObject* o)
4557 MonoClass* klass = mono_object_class (o);
4558 if (klass == mono_defaults.string_class) {
4559 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4560 } else if (o->vtable->rank) {
4561 MonoArray *array = (MonoArray*)o;
4562 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4563 if (array->bounds) {
4566 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4570 return mono_class_instance_size (klass);
4575 * mono_object_unbox:
4576 * @obj: object to unbox
4578 * Returns: a pointer to the start of the valuetype boxed in this
4581 * This method will assert if the object passed is not a valuetype.
4584 mono_object_unbox (MonoObject *obj)
4586 /* add assert for valuetypes? */
4587 g_assert (obj->vtable->klass->valuetype);
4588 return ((char*)obj) + sizeof (MonoObject);
4592 * mono_object_isinst:
4594 * @klass: a pointer to a class
4596 * Returns: @obj if @obj is derived from @klass
4599 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4602 mono_class_init (klass);
4604 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4605 return mono_object_isinst_mbyref (obj, klass);
4610 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4614 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4623 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4624 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4628 MonoClass *oklass = vt->klass;
4629 if ((oklass == mono_defaults.transparent_proxy_class))
4630 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4632 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4636 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4638 MonoDomain *domain = mono_domain_get ();
4640 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4641 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4642 MonoMethod *im = NULL;
4645 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4646 im = mono_object_get_virtual_method (rp, im);
4649 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4652 res = mono_runtime_invoke (im, rp, pa, NULL);
4654 if (*(MonoBoolean *) mono_object_unbox(res)) {
4655 /* Update the vtable of the remote type, so it can safely cast to this new type */
4656 mono_upgrade_remote_class (domain, obj, klass);
4665 * mono_object_castclass_mbyref:
4667 * @klass: a pointer to a class
4669 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4672 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4674 if (!obj) return NULL;
4675 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4677 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4679 "InvalidCastException"));
4684 MonoDomain *orig_domain;
4690 str_lookup (MonoDomain *domain, gpointer user_data)
4692 LDStrInfo *info = user_data;
4693 if (info->res || domain == info->orig_domain)
4695 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4701 mono_string_get_pinned (MonoString *str)
4705 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4706 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4707 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4708 news->length = mono_string_length (str);
4713 #define mono_string_get_pinned(str) (str)
4717 mono_string_is_interned_lookup (MonoString *str, int insert)
4719 MonoGHashTable *ldstr_table;
4723 domain = ((MonoObject *)str)->vtable->domain;
4724 ldstr_table = domain->ldstr_table;
4726 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4731 str = mono_string_get_pinned (str);
4732 mono_g_hash_table_insert (ldstr_table, str, str);
4736 LDStrInfo ldstr_info;
4737 ldstr_info.orig_domain = domain;
4738 ldstr_info.ins = str;
4739 ldstr_info.res = NULL;
4741 mono_domain_foreach (str_lookup, &ldstr_info);
4742 if (ldstr_info.res) {
4744 * the string was already interned in some other domain:
4745 * intern it in the current one as well.
4747 mono_g_hash_table_insert (ldstr_table, str, str);
4757 * mono_string_is_interned:
4758 * @o: String to probe
4760 * Returns whether the string has been interned.
4763 mono_string_is_interned (MonoString *o)
4765 return mono_string_is_interned_lookup (o, FALSE);
4769 * mono_string_intern:
4770 * @o: String to intern
4772 * Interns the string passed.
4773 * Returns: The interned string.
4776 mono_string_intern (MonoString *str)
4778 return mono_string_is_interned_lookup (str, TRUE);
4783 * @domain: the domain where the string will be used.
4784 * @image: a metadata context
4785 * @idx: index into the user string table.
4787 * Implementation for the ldstr opcode.
4788 * Returns: a loaded string from the @image/@idx combination.
4791 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4793 MONO_ARCH_SAVE_REGS;
4796 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4798 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4802 * mono_ldstr_metadata_sig
4803 * @domain: the domain for the string
4804 * @sig: the signature of a metadata string
4806 * Returns: a MonoString for a string stored in the metadata
4809 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4811 const char *str = sig;
4812 MonoString *o, *interned;
4815 len2 = mono_metadata_decode_blob_size (str, &str);
4818 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4819 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4822 guint16 *p2 = (guint16*)mono_string_chars (o);
4823 for (i = 0; i < len2; ++i) {
4824 *p2 = GUINT16_FROM_LE (*p2);
4830 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4832 /* o will get garbage collected */
4836 o = mono_string_get_pinned (o);
4837 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4844 * mono_string_to_utf8:
4845 * @s: a System.String
4847 * Return the UTF8 representation for @s.
4848 * the resulting buffer nedds to be freed with g_free().
4851 mono_string_to_utf8 (MonoString *s)
4855 GError *error = NULL;
4861 return g_strdup ("");
4863 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4865 MonoException *exc = mono_get_exception_argument ("string", error->message);
4866 g_error_free (error);
4867 mono_raise_exception(exc);
4869 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4870 if (s->length > written) {
4871 /* allocate the total length and copy the part of the string that has been converted */
4872 char *as2 = g_malloc0 (s->length);
4873 memcpy (as2, as, written);
4882 * mono_string_to_utf16:
4885 * Return an null-terminated array of the utf-16 chars
4886 * contained in @s. The result must be freed with g_free().
4887 * This is a temporary helper until our string implementation
4888 * is reworked to always include the null terminating char.
4891 mono_string_to_utf16 (MonoString *s)
4898 as = g_malloc ((s->length * 2) + 2);
4899 as [(s->length * 2)] = '\0';
4900 as [(s->length * 2) + 1] = '\0';
4903 return (gunichar2 *)(as);
4906 memcpy (as, mono_string_chars(s), s->length * 2);
4907 return (gunichar2 *)(as);
4911 * mono_string_from_utf16:
4912 * @data: the UTF16 string (LPWSTR) to convert
4914 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4916 * Returns: a MonoString.
4919 mono_string_from_utf16 (gunichar2 *data)
4921 MonoDomain *domain = mono_domain_get ();
4927 while (data [len]) len++;
4929 return mono_string_new_utf16 (domain, data, len);
4934 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4941 return mono_string_to_utf8 (s);
4943 r = mono_string_to_utf8 (s);
4947 len = strlen (r) + 1;
4949 mp_s = mono_mempool_alloc (mp, len);
4951 mp_s = mono_image_alloc (image, len);
4953 memcpy (mp_s, r, len);
4961 * mono_string_to_utf8_image:
4962 * @s: a System.String
4964 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4967 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4969 return mono_string_to_utf8_internal (NULL, image, s);
4973 * mono_string_to_utf8_mp:
4974 * @s: a System.String
4976 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4979 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4981 return mono_string_to_utf8_internal (mp, NULL, s);
4985 default_ex_handler (MonoException *ex)
4987 MonoObject *o = (MonoObject*)ex;
4988 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4992 static MonoExceptionFunc ex_handler = default_ex_handler;
4995 * mono_install_handler:
4996 * @func: exception handler
4998 * This is an internal JIT routine used to install the handler for exceptions
5002 mono_install_handler (MonoExceptionFunc func)
5004 ex_handler = func? func: default_ex_handler;
5008 * mono_raise_exception:
5009 * @ex: exception object
5011 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5014 mono_raise_exception (MonoException *ex)
5017 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5018 * that will cause gcc to omit the function epilog, causing problems when
5019 * the JIT tries to walk the stack, since the return address on the stack
5020 * will point into the next function in the executable, not this one.
5023 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5024 MonoThread *thread = mono_thread_current ();
5025 g_assert (ex->object.vtable->domain == mono_domain_get ());
5026 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5033 * mono_wait_handle_new:
5034 * @domain: Domain where the object will be created
5035 * @handle: Handle for the wait handle
5037 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5040 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5042 MonoWaitHandle *res;
5043 gpointer params [1];
5044 static MonoMethod *handle_set;
5046 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
5048 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5050 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
5052 params [0] = &handle;
5053 mono_runtime_invoke (handle_set, res, params, NULL);
5059 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5061 static MonoClassField *f_os_handle;
5062 static MonoClassField *f_safe_handle;
5064 if (!f_os_handle && !f_safe_handle) {
5065 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
5066 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
5071 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5075 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5082 mono_runtime_capture_context (MonoDomain *domain)
5084 RuntimeInvokeFunction runtime_invoke;
5086 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5087 MonoMethod *method = mono_get_context_capture_method ();
5088 MonoMethod *wrapper;
5091 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5092 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5093 domain->capture_context_method = mono_compile_method (method);
5096 runtime_invoke = domain->capture_context_runtime_invoke;
5098 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5101 * mono_async_result_new:
5102 * @domain:domain where the object will be created.
5103 * @handle: wait handle.
5104 * @state: state to pass to AsyncResult
5105 * @data: C closure data.
5107 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5108 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5112 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5114 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5115 MonoObject *context = mono_runtime_capture_context (domain);
5116 /* we must capture the execution context from the original thread */
5118 MONO_OBJECT_SETREF (res, execution_context, context);
5119 /* note: result may be null if the flow is suppressed */
5123 MONO_OBJECT_SETREF (res, object_data, object_data);
5124 MONO_OBJECT_SETREF (res, async_state, state);
5126 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5128 res->sync_completed = FALSE;
5129 res->completed = FALSE;
5135 mono_message_init (MonoDomain *domain,
5136 MonoMethodMessage *this,
5137 MonoReflectionMethod *method,
5138 MonoArray *out_args)
5140 static MonoClass *object_array_klass;
5141 static MonoClass *byte_array_klass;
5142 static MonoClass *string_array_klass;
5143 MonoMethodSignature *sig = mono_method_signature (method->method);
5149 if (!object_array_klass) {
5152 klass = mono_array_class_get (mono_defaults.object_class, 1);
5155 mono_memory_barrier ();
5156 object_array_klass = klass;
5158 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5161 mono_memory_barrier ();
5162 byte_array_klass = klass;
5164 klass = mono_array_class_get (mono_defaults.string_class, 1);
5167 mono_memory_barrier ();
5168 string_array_klass = klass;
5171 MONO_OBJECT_SETREF (this, method, method);
5173 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5174 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5175 this->async_result = NULL;
5176 this->call_type = CallType_Sync;
5178 names = g_new (char *, sig->param_count);
5179 mono_method_get_param_names (method->method, (const char **) names);
5180 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5182 for (i = 0; i < sig->param_count; i++) {
5183 name = mono_string_new (domain, names [i]);
5184 mono_array_setref (this->names, i, name);
5188 for (i = 0, j = 0; i < sig->param_count; i++) {
5189 if (sig->params [i]->byref) {
5191 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5192 mono_array_setref (this->args, i, arg);
5196 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5200 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5203 mono_array_set (this->arg_types, guint8, i, arg_type);
5208 * mono_remoting_invoke:
5209 * @real_proxy: pointer to a RealProxy object
5210 * @msg: The MonoMethodMessage to execute
5211 * @exc: used to store exceptions
5212 * @out_args: used to store output arguments
5214 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5215 * IMessage interface and it is not trivial to extract results from there. So
5216 * we call an helper method PrivateInvoke instead of calling
5217 * RealProxy::Invoke() directly.
5219 * Returns: the result object.
5222 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5223 MonoObject **exc, MonoArray **out_args)
5225 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5228 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5231 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5233 real_proxy->vtable->domain->private_invoke_method = im;
5236 pa [0] = real_proxy;
5241 return mono_runtime_invoke (im, NULL, pa, exc);
5245 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5246 MonoObject **exc, MonoArray **out_args)
5248 static MonoClass *object_array_klass;
5251 MonoMethodSignature *sig;
5253 int i, j, outarg_count = 0;
5255 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5257 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5258 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5259 target = tp->rp->unwrapped_server;
5261 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5265 domain = mono_domain_get ();
5266 method = msg->method->method;
5267 sig = mono_method_signature (method);
5269 for (i = 0; i < sig->param_count; i++) {
5270 if (sig->params [i]->byref)
5274 if (!object_array_klass) {
5277 klass = mono_array_class_get (mono_defaults.object_class, 1);
5280 mono_memory_barrier ();
5281 object_array_klass = klass;
5284 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5285 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5288 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5290 for (i = 0, j = 0; i < sig->param_count; i++) {
5291 if (sig->params [i]->byref) {
5293 arg = mono_array_get (msg->args, gpointer, i);
5294 mono_array_setref (*out_args, j, arg);
5303 * mono_print_unhandled_exception:
5304 * @exc: The exception
5306 * Prints the unhandled exception.
5309 mono_print_unhandled_exception (MonoObject *exc)
5311 char *message = (char *) "";
5315 gboolean free_message = FALSE;
5317 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5318 klass = exc->vtable->klass;
5320 while (klass && method == NULL) {
5321 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5323 klass = klass->parent;
5328 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5330 message = mono_string_to_utf8 (str);
5331 free_message = TRUE;
5336 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5337 * exc->vtable->klass->name, message);
5339 g_printerr ("\nUnhandled Exception: %s\n", message);
5346 * mono_delegate_ctor:
5347 * @this: pointer to an uninitialized delegate object
5348 * @target: target object
5349 * @addr: pointer to native code
5352 * Initialize a delegate and sets a specific method, not the one
5353 * associated with addr. This is useful when sharing generic code.
5354 * In that case addr will most probably not be associated with the
5355 * correct instantiation of the method.
5358 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5360 MonoDelegate *delegate = (MonoDelegate *)this;
5367 delegate->method = method;
5369 class = this->vtable->klass;
5370 mono_stats.delegate_creations++;
5372 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5374 method = mono_marshal_get_remoting_invoke (method);
5375 delegate->method_ptr = mono_compile_method (method);
5376 MONO_OBJECT_SETREF (delegate, target, target);
5377 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5378 method = mono_marshal_get_unbox_wrapper (method);
5379 delegate->method_ptr = mono_compile_method (method);
5380 MONO_OBJECT_SETREF (delegate, target, target);
5382 delegate->method_ptr = addr;
5383 MONO_OBJECT_SETREF (delegate, target, target);
5386 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5390 * mono_delegate_ctor:
5391 * @this: pointer to an uninitialized delegate object
5392 * @target: target object
5393 * @addr: pointer to native code
5395 * This is used to initialize a delegate.
5398 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5400 MonoDomain *domain = mono_domain_get ();
5402 MonoMethod *method = NULL;
5406 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5407 method = ji->method;
5408 g_assert (!method->klass->generic_container);
5411 mono_delegate_ctor_with_method (this, target, addr, method);
5415 * mono_method_call_message_new:
5416 * @method: method to encapsulate
5417 * @params: parameters to the method
5418 * @invoke: optional, delegate invoke.
5419 * @cb: async callback delegate.
5420 * @state: state passed to the async callback.
5422 * Translates arguments pointers into a MonoMethodMessage.
5425 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5426 MonoDelegate **cb, MonoObject **state)
5428 MonoDomain *domain = mono_domain_get ();
5429 MonoMethodSignature *sig = mono_method_signature (method);
5430 MonoMethodMessage *msg;
5433 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5436 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5437 count = sig->param_count - 2;
5439 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5440 count = sig->param_count;
5443 for (i = 0; i < count; i++) {
5448 if (sig->params [i]->byref)
5449 vpos = *((gpointer *)params [i]);
5453 type = sig->params [i]->type;
5454 class = mono_class_from_mono_type (sig->params [i]);
5456 if (class->valuetype)
5457 arg = mono_value_box (domain, class, vpos);
5459 arg = *((MonoObject **)vpos);
5461 mono_array_setref (msg->args, i, arg);
5464 if (cb != NULL && state != NULL) {
5465 *cb = *((MonoDelegate **)params [i]);
5467 *state = *((MonoObject **)params [i]);
5474 * mono_method_return_message_restore:
5476 * Restore results from message based processing back to arguments pointers
5479 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5481 MonoMethodSignature *sig = mono_method_signature (method);
5482 int i, j, type, size, out_len;
5484 if (out_args == NULL)
5486 out_len = mono_array_length (out_args);
5490 for (i = 0, j = 0; i < sig->param_count; i++) {
5491 MonoType *pt = sig->params [i];
5496 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5498 arg = mono_array_get (out_args, gpointer, j);
5502 case MONO_TYPE_VOID:
5503 g_assert_not_reached ();
5507 case MONO_TYPE_BOOLEAN:
5510 case MONO_TYPE_CHAR:
5517 case MONO_TYPE_VALUETYPE: {
5519 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5520 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5523 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5524 memset (*((gpointer *)params [i]), 0, size);
5528 case MONO_TYPE_STRING:
5529 case MONO_TYPE_CLASS:
5530 case MONO_TYPE_ARRAY:
5531 case MONO_TYPE_SZARRAY:
5532 case MONO_TYPE_OBJECT:
5533 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5536 g_assert_not_reached ();
5545 * mono_load_remote_field:
5546 * @this: pointer to an object
5547 * @klass: klass of the object containing @field
5548 * @field: the field to load
5549 * @res: a storage to store the result
5551 * This method is called by the runtime on attempts to load fields of
5552 * transparent proxy objects. @this points to such TP, @klass is the class of
5553 * the object containing @field. @res is a storage location which can be
5554 * used to store the result.
5556 * Returns: an address pointing to the value of field.
5559 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5561 static MonoMethod *getter = NULL;
5562 MonoDomain *domain = mono_domain_get ();
5563 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5564 MonoClass *field_class;
5565 MonoMethodMessage *msg;
5566 MonoArray *out_args;
5570 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5571 g_assert (res != NULL);
5573 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5574 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5579 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5583 field_class = mono_class_from_mono_type (field->type);
5585 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5586 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5587 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5589 full_name = mono_type_get_full_name (klass);
5590 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5591 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5594 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5596 if (exc) mono_raise_exception ((MonoException *)exc);
5598 if (mono_array_length (out_args) == 0)
5601 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5603 if (field_class->valuetype) {
5604 return ((char *)*res) + sizeof (MonoObject);
5610 * mono_load_remote_field_new:
5615 * Missing documentation.
5618 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5620 static MonoMethod *getter = NULL;
5621 MonoDomain *domain = mono_domain_get ();
5622 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5623 MonoClass *field_class;
5624 MonoMethodMessage *msg;
5625 MonoArray *out_args;
5626 MonoObject *exc, *res;
5629 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5631 field_class = mono_class_from_mono_type (field->type);
5633 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5635 if (field_class->valuetype) {
5636 res = mono_object_new (domain, field_class);
5637 val = ((gchar *) res) + sizeof (MonoObject);
5641 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5646 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5650 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5651 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5653 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5655 full_name = mono_type_get_full_name (klass);
5656 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5657 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5660 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5662 if (exc) mono_raise_exception ((MonoException *)exc);
5664 if (mono_array_length (out_args) == 0)
5667 res = mono_array_get (out_args, MonoObject *, 0);
5673 * mono_store_remote_field:
5674 * @this: pointer to an object
5675 * @klass: klass of the object containing @field
5676 * @field: the field to load
5677 * @val: the value/object to store
5679 * This method is called by the runtime on attempts to store fields of
5680 * transparent proxy objects. @this points to such TP, @klass is the class of
5681 * the object containing @field. @val is the new value to store in @field.
5684 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5686 static MonoMethod *setter = NULL;
5687 MonoDomain *domain = mono_domain_get ();
5688 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5689 MonoClass *field_class;
5690 MonoMethodMessage *msg;
5691 MonoArray *out_args;
5696 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5698 field_class = mono_class_from_mono_type (field->type);
5700 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5701 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5702 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5707 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5711 if (field_class->valuetype)
5712 arg = mono_value_box (domain, field_class, val);
5714 arg = *((MonoObject **)val);
5717 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5718 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5720 full_name = mono_type_get_full_name (klass);
5721 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5722 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5723 mono_array_setref (msg->args, 2, arg);
5726 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5728 if (exc) mono_raise_exception ((MonoException *)exc);
5732 * mono_store_remote_field_new:
5738 * Missing documentation
5741 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5743 static MonoMethod *setter = NULL;
5744 MonoDomain *domain = mono_domain_get ();
5745 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5746 MonoClass *field_class;
5747 MonoMethodMessage *msg;
5748 MonoArray *out_args;
5752 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5754 field_class = mono_class_from_mono_type (field->type);
5756 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5757 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5758 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5763 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5767 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5768 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5770 full_name = mono_type_get_full_name (klass);
5771 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5772 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5773 mono_array_setref (msg->args, 2, arg);
5776 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5778 if (exc) mono_raise_exception ((MonoException *)exc);
5782 * mono_create_ftnptr:
5784 * Given a function address, create a function descriptor for it.
5785 * This is only needed on some platforms.
5788 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5790 return callbacks.create_ftnptr (domain, addr);
5794 * mono_get_addr_from_ftnptr:
5796 * Given a pointer to a function descriptor, return the function address.
5797 * This is only needed on some platforms.
5800 mono_get_addr_from_ftnptr (gpointer descr)
5802 return callbacks.get_addr_from_ftnptr (descr);
5807 * mono_string_chars:
5810 * Returns a pointer to the UCS16 characters stored in the MonoString
5813 mono_string_chars(MonoString *s)
5815 /* This method is here only for documentation extraction, this is a macro */
5819 * mono_string_length:
5822 * Returns the lenght in characters of the string
5825 mono_string_length (MonoString *s)
5827 /* This method is here only for documentation extraction, this is a macro */