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>
45 #define NEED_TO_ZERO_PTRFREE 1
46 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
47 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
48 #ifdef HAVE_GC_GCJ_MALLOC
49 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
50 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
52 #define GC_NO_DESCRIPTOR (NULL)
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
62 #define NEED_TO_ZERO_PTRFREE 1
63 #define GC_NO_DESCRIPTOR (NULL)
64 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
65 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
66 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
70 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
71 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
74 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
77 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
79 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
80 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
81 static CRITICAL_SECTION ldstr_section;
83 static gboolean profile_allocs = TRUE;
86 mono_runtime_object_init (MonoObject *this)
88 MonoMethod *method = NULL;
89 MonoClass *klass = this->vtable->klass;
91 method = mono_class_get_method_from_name (klass, ".ctor", 0);
94 if (method->klass->valuetype)
95 this = mono_object_unbox (this);
96 mono_runtime_invoke (method, this, NULL, NULL);
99 /* The pseudo algorithm for type initialization from the spec
100 Note it doesn't say anything about domains - only threads.
102 2. If the type is initialized you are done.
103 2.1. If the type is not yet initialized, try to take an
105 2.2. If successful, record this thread as responsible for
106 initializing the type and proceed to step 2.3.
107 2.2.1. If not, see whether this thread or any thread
108 waiting for this thread to complete already holds the lock.
109 2.2.2. If so, return since blocking would create a deadlock. This thread
110 will now see an incompletely initialized state for the type,
111 but no deadlock will arise.
112 2.2.3 If not, block until the type is initialized then return.
113 2.3 Initialize the parent type and then all interfaces implemented
115 2.4 Execute the type initialization code for this type.
116 2.5 Mark the type as initialized, release the initialization lock,
117 awaken any threads waiting for this type to be initialized,
124 guint32 initializing_tid;
125 guint32 waiting_count;
127 CRITICAL_SECTION initialization_section;
128 } TypeInitializationLock;
130 /* for locking access to type_initialization_hash and blocked_thread_hash */
131 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
132 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
133 static CRITICAL_SECTION type_initialization_section;
135 /* from vtable to lock */
136 static GHashTable *type_initialization_hash;
138 /* from thread id to thread id being waited on */
139 static GHashTable *blocked_thread_hash;
142 static MonoThread *main_thread;
144 /* Functions supplied by the runtime */
145 static MonoRuntimeCallbacks callbacks;
148 * mono_thread_set_main:
149 * @thread: thread to set as the main thread
151 * This function can be used to instruct the runtime to treat @thread
152 * as the main thread, ie, the thread that would normally execute the Main()
153 * method. This basically means that at the end of @thread, the runtime will
154 * wait for the existing foreground threads to quit and other such details.
157 mono_thread_set_main (MonoThread *thread)
159 main_thread = thread;
163 mono_thread_get_main (void)
169 mono_type_initialization_init (void)
171 InitializeCriticalSection (&type_initialization_section);
172 type_initialization_hash = g_hash_table_new (NULL, NULL);
173 blocked_thread_hash = g_hash_table_new (NULL, NULL);
174 InitializeCriticalSection (&ldstr_section);
178 mono_type_initialization_cleanup (void)
181 /* This is causing race conditions with
182 * mono_release_type_locks
184 DeleteCriticalSection (&type_initialization_section);
186 DeleteCriticalSection (&ldstr_section);
190 * get_type_init_exception_for_vtable:
192 * Return the stored type initialization exception for VTABLE.
194 static MonoException*
195 get_type_init_exception_for_vtable (MonoVTable *vtable)
197 MonoDomain *domain = vtable->domain;
198 MonoClass *klass = vtable->klass;
202 g_assert (vtable->init_failed);
205 * If the initializing thread was rudely aborted, the exception is not stored
209 mono_domain_lock (domain);
210 if (domain->type_init_exception_hash)
211 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
212 mono_domain_unlock (domain);
215 if (klass->name_space && *klass->name_space)
216 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
218 full_name = g_strdup (klass->name);
219 ex = mono_get_exception_type_initialization (full_name, NULL);
226 * mono_runtime_class_init:
227 * @vtable: vtable that needs to be initialized
229 * This routine calls the class constructor for @vtable.
232 mono_runtime_class_init (MonoVTable *vtable)
234 mono_runtime_class_init_full (vtable, TRUE);
238 * mono_runtime_class_init_full:
239 * @vtable that neeeds to be initialized
240 * @raise_exception is TRUE, exceptions are raised intead of returned
244 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
247 MonoException *exc_to_throw;
248 MonoMethod *method = NULL;
254 if (vtable->initialized)
258 klass = vtable->klass;
260 if (!klass->image->checked_module_cctor) {
261 mono_image_check_for_module_cctor (klass->image);
262 if (klass->image->has_module_cctor) {
263 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
264 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
267 method = mono_class_get_cctor (klass);
270 MonoDomain *domain = vtable->domain;
271 TypeInitializationLock *lock;
272 guint32 tid = GetCurrentThreadId();
273 int do_initialization = 0;
274 MonoDomain *last_domain = NULL;
276 mono_type_initialization_lock ();
277 /* double check... */
278 if (vtable->initialized) {
279 mono_type_initialization_unlock ();
282 if (vtable->init_failed) {
283 mono_type_initialization_unlock ();
285 /* The type initialization already failed once, rethrow the same exception */
287 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
288 return get_type_init_exception_for_vtable (vtable);
290 lock = g_hash_table_lookup (type_initialization_hash, vtable);
292 /* This thread will get to do the initialization */
293 if (mono_domain_get () != domain) {
294 /* Transfer into the target domain */
295 last_domain = mono_domain_get ();
296 if (!mono_domain_set (domain, FALSE)) {
297 vtable->initialized = 1;
298 mono_type_initialization_unlock ();
300 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
301 return mono_get_exception_appdomain_unloaded ();
304 lock = g_malloc (sizeof(TypeInitializationLock));
305 InitializeCriticalSection (&lock->initialization_section);
306 lock->initializing_tid = tid;
307 lock->waiting_count = 1;
309 /* grab the vtable lock while this thread still owns type_initialization_section */
310 EnterCriticalSection (&lock->initialization_section);
311 g_hash_table_insert (type_initialization_hash, vtable, lock);
312 do_initialization = 1;
315 TypeInitializationLock *pending_lock;
317 if (lock->initializing_tid == tid || lock->done) {
318 mono_type_initialization_unlock ();
321 /* see if the thread doing the initialization is already blocked on this thread */
322 blocked = GUINT_TO_POINTER (lock->initializing_tid);
323 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
324 if (pending_lock->initializing_tid == tid) {
325 if (!pending_lock->done) {
326 mono_type_initialization_unlock ();
329 /* the thread doing the initialization is blocked on this thread,
330 but on a lock that has already been freed. It just hasn't got
335 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
337 ++lock->waiting_count;
338 /* record the fact that we are waiting on the initializing thread */
339 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
341 mono_type_initialization_unlock ();
343 if (do_initialization) {
344 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
346 /* If the initialization failed, mark the class as unusable. */
347 /* Avoid infinite loops */
349 (klass->image == mono_defaults.corlib &&
350 !strcmp (klass->name_space, "System") &&
351 !strcmp (klass->name, "TypeInitializationException")))) {
352 vtable->init_failed = 1;
354 if (klass->name_space && *klass->name_space)
355 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
357 full_name = g_strdup (klass->name);
358 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
362 * Store the exception object so it could be thrown on subsequent
365 mono_domain_lock (domain);
366 if (!domain->type_init_exception_hash)
367 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
368 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
369 mono_domain_unlock (domain);
373 mono_domain_set (last_domain, TRUE);
375 LeaveCriticalSection (&lock->initialization_section);
377 /* this just blocks until the initializing thread is done */
378 EnterCriticalSection (&lock->initialization_section);
379 LeaveCriticalSection (&lock->initialization_section);
382 mono_type_initialization_lock ();
383 if (lock->initializing_tid != tid)
384 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
385 --lock->waiting_count;
386 if (lock->waiting_count == 0) {
387 DeleteCriticalSection (&lock->initialization_section);
388 g_hash_table_remove (type_initialization_hash, vtable);
391 if (!vtable->init_failed)
392 vtable->initialized = 1;
393 mono_type_initialization_unlock ();
395 if (vtable->init_failed) {
396 /* Either we were the initializing thread or we waited for the initialization */
398 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
399 return get_type_init_exception_for_vtable (vtable);
402 vtable->initialized = 1;
409 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
411 MonoVTable *vtable = (MonoVTable*)key;
413 TypeInitializationLock *lock = (TypeInitializationLock*) value;
414 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
417 * Have to set this since it cannot be set by the normal code in
418 * mono_runtime_class_init (). In this case, the exception object is not stored,
419 * and get_type_init_exception_for_class () needs to be aware of this.
421 vtable->init_failed = 1;
422 LeaveCriticalSection (&lock->initialization_section);
423 --lock->waiting_count;
424 if (lock->waiting_count == 0) {
425 DeleteCriticalSection (&lock->initialization_section);
434 mono_release_type_locks (MonoThread *thread)
436 mono_type_initialization_lock ();
437 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
438 mono_type_initialization_unlock ();
442 default_trampoline (MonoMethod *method)
448 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
450 g_assert_not_reached ();
456 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
458 g_error ("remoting not installed");
463 default_delegate_trampoline (MonoClass *klass)
465 g_assert_not_reached ();
469 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
470 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
471 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
472 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
473 static MonoImtThunkBuilder imt_thunk_builder = NULL;
474 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
475 #if (MONO_IMT_SIZE > 32)
476 #error "MONO_IMT_SIZE cannot be larger than 32"
480 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
482 memcpy (&callbacks, cbs, sizeof (*cbs));
486 mono_install_trampoline (MonoTrampoline func)
488 arch_create_jit_trampoline = func? func: default_trampoline;
492 mono_install_jump_trampoline (MonoJumpTrampoline func)
494 arch_create_jump_trampoline = func? func: default_jump_trampoline;
498 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
500 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
504 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
506 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
510 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
511 imt_thunk_builder = func;
514 static MonoCompileFunc default_mono_compile_method = NULL;
517 * mono_install_compile_method:
518 * @func: function to install
520 * This is a VM internal routine
523 mono_install_compile_method (MonoCompileFunc func)
525 default_mono_compile_method = func;
529 * mono_compile_method:
530 * @method: The method to compile.
532 * This JIT-compiles the method, and returns the pointer to the native code
536 mono_compile_method (MonoMethod *method)
538 if (!default_mono_compile_method) {
539 g_error ("compile method called on uninitialized runtime");
542 return default_mono_compile_method (method);
546 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
548 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
552 mono_runtime_create_delegate_trampoline (MonoClass *klass)
554 return arch_create_delegate_trampoline (klass);
557 static MonoFreeMethodFunc default_mono_free_method = NULL;
560 * mono_install_free_method:
561 * @func: pointer to the MonoFreeMethodFunc used to release a method
563 * This is an internal VM routine, it is used for the engines to
564 * register a handler to release the resources associated with a method.
566 * Methods are freed when no more references to the delegate that holds
570 mono_install_free_method (MonoFreeMethodFunc func)
572 default_mono_free_method = func;
576 * mono_runtime_free_method:
577 * @domain; domain where the method is hosted
578 * @method: method to release
580 * This routine is invoked to free the resources associated with
581 * a method that has been JIT compiled. This is used to discard
582 * methods that were used only temporarily (for example, used in marshalling)
586 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
588 if (default_mono_free_method != NULL)
589 default_mono_free_method (domain, method);
591 mono_method_clear_object (domain, method);
593 mono_free_method (method);
597 * The vtables in the root appdomain are assumed to be reachable by other
598 * roots, and we don't use typed allocation in the other domains.
601 /* The sync block is no longer a GC pointer */
602 #define GC_HEADER_BITMAP (0)
604 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
607 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
609 MonoClassField *field;
615 max_size = mono_class_data_size (class) / sizeof (gpointer);
617 max_size = class->instance_size / sizeof (gpointer);
618 if (max_size >= size) {
619 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
622 for (p = class; p != NULL; p = p->parent) {
623 gpointer iter = NULL;
624 while ((field = mono_class_get_fields (p, &iter))) {
628 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
630 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
633 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
636 /* FIXME: should not happen, flag as type load error */
637 if (field->type->byref)
640 if (static_fields && field->offset == -1)
644 pos = field->offset / sizeof (gpointer);
647 type = mono_type_get_underlying_type (field->type);
648 switch (type->type) {
651 case MONO_TYPE_FNPTR:
653 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
658 if (class->image != mono_defaults.corlib)
661 case MONO_TYPE_STRING:
662 case MONO_TYPE_SZARRAY:
663 case MONO_TYPE_CLASS:
664 case MONO_TYPE_OBJECT:
665 case MONO_TYPE_ARRAY:
666 g_assert ((field->offset % sizeof(gpointer)) == 0);
668 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
669 *max_set = MAX (*max_set, pos);
671 case MONO_TYPE_GENERICINST:
672 if (!mono_type_generic_inst_is_valuetype (type)) {
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);
681 case MONO_TYPE_VALUETYPE: {
682 MonoClass *fclass = mono_class_from_mono_type (field->type);
683 if (fclass->has_references) {
684 /* remove the object header */
685 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
699 case MONO_TYPE_BOOLEAN:
703 g_assert_not_reached ();
715 * similar to the above, but sets the bits in the bitmap for any non-ref field
716 * and ignores static fields
719 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
721 MonoClassField *field;
726 max_size = class->instance_size / sizeof (gpointer);
727 if (max_size >= size) {
728 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
731 for (p = class; p != NULL; p = p->parent) {
732 gpointer iter = NULL;
733 while ((field = mono_class_get_fields (p, &iter))) {
736 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
738 /* FIXME: should not happen, flag as type load error */
739 if (field->type->byref)
742 pos = field->offset / sizeof (gpointer);
745 type = mono_type_get_underlying_type (field->type);
746 switch (type->type) {
747 #if SIZEOF_VOID_P == 8
751 case MONO_TYPE_FNPTR:
756 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
757 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
758 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
761 #if SIZEOF_VOID_P == 4
765 case MONO_TYPE_FNPTR:
770 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
771 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
772 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
778 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
779 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
780 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
783 case MONO_TYPE_BOOLEAN:
786 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
788 case MONO_TYPE_STRING:
789 case MONO_TYPE_SZARRAY:
790 case MONO_TYPE_CLASS:
791 case MONO_TYPE_OBJECT:
792 case MONO_TYPE_ARRAY:
794 case MONO_TYPE_GENERICINST:
795 if (!mono_type_generic_inst_is_valuetype (type)) {
800 case MONO_TYPE_VALUETYPE: {
801 MonoClass *fclass = mono_class_from_mono_type (field->type);
802 /* remove the object header */
803 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
807 g_assert_not_reached ();
816 * mono_class_insecure_overlapping:
817 * check if a class with explicit layout has references and non-references
818 * fields overlapping.
820 * Returns: TRUE if it is insecure to load the type.
823 mono_class_insecure_overlapping (MonoClass *klass)
827 gsize default_bitmap [4] = {0};
829 gsize default_nrbitmap [4] = {0};
830 int i, insecure = FALSE;
833 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
834 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
836 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
837 int idx = i % (sizeof (bitmap [0]) * 8);
838 if (bitmap [idx] & nrbitmap [idx]) {
843 if (bitmap != default_bitmap)
845 if (nrbitmap != default_nrbitmap)
848 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
856 mono_string_alloc (int length)
858 return mono_string_new_size (mono_domain_get (), length);
862 mono_class_compute_gc_descriptor (MonoClass *class)
866 gsize default_bitmap [4] = {0};
867 static gboolean gcj_inited = FALSE;
872 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
873 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
874 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
875 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
877 #ifdef HAVE_GC_GCJ_MALLOC
879 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
883 #ifdef GC_REDIRECT_TO_LOCAL
884 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
885 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
887 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
888 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
893 mono_loader_unlock ();
897 mono_class_init (class);
899 if (class->gc_descr_inited)
902 class->gc_descr_inited = TRUE;
903 class->gc_descr = GC_NO_DESCRIPTOR;
905 bitmap = default_bitmap;
906 if (class == mono_defaults.string_class) {
907 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
908 } else if (class->rank) {
909 mono_class_compute_gc_descriptor (class->element_class);
910 if (!class->element_class->valuetype) {
912 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
913 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
914 class->name_space, class->name);*/
916 /* remove the object header */
917 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
918 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
919 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
920 class->name_space, class->name);*/
921 if (bitmap != default_bitmap)
925 /*static int count = 0;
928 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
929 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
931 if (class->gc_descr == GC_NO_DESCRIPTOR)
932 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
934 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
935 if (bitmap != default_bitmap)
941 * field_is_special_static:
942 * @fklass: The MonoClass to look up.
943 * @field: The MonoClassField describing the field.
945 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
946 * SPECIAL_STATIC_NONE otherwise.
949 field_is_special_static (MonoClass *fklass, MonoClassField *field)
951 MonoCustomAttrInfo *ainfo;
953 ainfo = mono_custom_attrs_from_field (fklass, field);
956 for (i = 0; i < ainfo->num_attrs; ++i) {
957 MonoClass *klass = ainfo->attrs [i].ctor->klass;
958 if (klass->image == mono_defaults.corlib) {
959 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
960 mono_custom_attrs_free (ainfo);
961 return SPECIAL_STATIC_THREAD;
963 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
964 mono_custom_attrs_free (ainfo);
965 return SPECIAL_STATIC_CONTEXT;
969 mono_custom_attrs_free (ainfo);
970 return SPECIAL_STATIC_NONE;
973 static gpointer imt_trampoline = NULL;
976 mono_install_imt_trampoline (gpointer tramp_code)
978 imt_trampoline = tramp_code;
981 static gpointer vtable_trampoline = NULL;
984 mono_install_vtable_trampoline (gpointer tramp_code)
986 vtable_trampoline = tramp_code;
989 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
990 #define mix(a,b,c) { \
991 a -= c; a ^= rot(c, 4); c += b; \
992 b -= a; b ^= rot(a, 6); a += c; \
993 c -= b; c ^= rot(b, 8); b += a; \
994 a -= c; a ^= rot(c,16); c += b; \
995 b -= a; b ^= rot(a,19); a += c; \
996 c -= b; c ^= rot(b, 4); b += a; \
998 #define final(a,b,c) { \
999 c ^= b; c -= rot(b,14); \
1000 a ^= c; a -= rot(c,11); \
1001 b ^= a; b -= rot(a,25); \
1002 c ^= b; c -= rot(b,16); \
1003 a ^= c; a -= rot(c,4); \
1004 b ^= a; b -= rot(a,14); \
1005 c ^= b; c -= rot(b,24); \
1009 mono_method_get_imt_slot (MonoMethod *method)
1011 MonoMethodSignature *sig;
1013 guint32 *hashes_start, *hashes;
1017 /* This can be used to stress tests the collision code */
1021 * We do this to simplify generic sharing. It will hurt
1022 * performance in cases where a class implements two different
1023 * instantiations of the same generic interface.
1024 * The code in build_imt_slots () depends on this.
1026 if (method->is_inflated)
1027 method = ((MonoMethodInflated*)method)->declaring;
1029 sig = mono_method_signature (method);
1030 hashes_count = sig->param_count + 4;
1031 hashes_start = malloc (hashes_count * sizeof (guint32));
1032 hashes = hashes_start;
1034 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1035 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1036 method->klass->name_space, method->klass->name, method->name);
1037 g_assert_not_reached ();
1040 /* Initialize hashes */
1041 hashes [0] = g_str_hash (method->klass->name);
1042 hashes [1] = g_str_hash (method->klass->name_space);
1043 hashes [2] = g_str_hash (method->name);
1044 hashes [3] = mono_metadata_type_hash (sig->ret);
1045 for (i = 0; i < sig->param_count; i++) {
1046 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1049 /* Setup internal state */
1050 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1052 /* Handle most of the hashes */
1053 while (hashes_count > 3) {
1062 /* Handle the last 3 hashes (all the case statements fall through) */
1063 switch (hashes_count) {
1064 case 3 : c += hashes [2];
1065 case 2 : b += hashes [1];
1066 case 1 : a += hashes [0];
1068 case 0: /* nothing left to add */
1072 free (hashes_start);
1073 /* Report the result */
1074 return c % MONO_IMT_SIZE;
1083 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1084 guint32 imt_slot = mono_method_get_imt_slot (method);
1085 MonoImtBuilderEntry *entry;
1087 if (slot_num >= 0 && imt_slot != slot_num) {
1088 /* we build just a single imt slot and this is not it */
1092 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1093 entry->key = method;
1094 entry->value.vtable_slot = vtable_slot;
1095 entry->next = imt_builder [imt_slot];
1096 if (imt_builder [imt_slot] != NULL) {
1097 entry->children = imt_builder [imt_slot]->children + 1;
1098 if (entry->children == 1) {
1099 mono_stats.imt_slots_with_collisions++;
1100 *imt_collisions_bitmap |= (1 << imt_slot);
1103 entry->children = 0;
1104 mono_stats.imt_used_slots++;
1106 imt_builder [imt_slot] = entry;
1108 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1109 method, method->klass->name_space, method->klass->name,
1110 method->name, imt_slot, vtable_slot, entry->children);
1116 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1118 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1122 e->method->klass->name_space,
1123 e->method->klass->name,
1126 printf (" * %s: NULL\n", message);
1132 compare_imt_builder_entries (const void *p1, const void *p2) {
1133 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1134 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1136 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1140 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1142 int count = end - start;
1143 int chunk_start = out_array->len;
1146 for (i = start; i < end; ++i) {
1147 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1148 item->key = sorted_array [i]->key;
1149 item->value = sorted_array [i]->value;
1150 item->has_target_code = sorted_array [i]->has_target_code;
1151 item->is_equals = TRUE;
1153 item->check_target_idx = out_array->len + 1;
1155 item->check_target_idx = 0;
1156 g_ptr_array_add (out_array, item);
1159 int middle = start + count / 2;
1160 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1162 item->key = sorted_array [middle]->key;
1163 item->is_equals = FALSE;
1164 g_ptr_array_add (out_array, item);
1165 imt_emit_ir (sorted_array, start, middle, out_array);
1166 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1172 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1173 int number_of_entries = entries->children + 1;
1174 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1175 GPtrArray *result = g_ptr_array_new ();
1176 MonoImtBuilderEntry *current_entry;
1179 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1180 sorted_array [i] = current_entry;
1182 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1184 /*for (i = 0; i < number_of_entries; i++) {
1185 print_imt_entry (" sorted array:", sorted_array [i], i);
1188 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1190 free (sorted_array);
1195 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1197 if (imt_builder_entry != NULL) {
1198 if (imt_builder_entry->children == 0 && !fail_tramp) {
1199 /* No collision, return the vtable slot contents */
1200 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1202 /* Collision, build the thunk */
1203 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1206 result = imt_thunk_builder (vtable, domain,
1207 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1208 for (i = 0; i < imt_ir->len; ++i)
1209 g_free (g_ptr_array_index (imt_ir, i));
1210 g_ptr_array_free (imt_ir, TRUE);
1222 static MonoImtBuilderEntry*
1223 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1226 * LOCKING: requires the loader and domain locks.
1230 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1234 guint32 imt_collisions_bitmap = 0;
1235 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1236 int method_count = 0;
1237 gboolean record_method_count_for_max_collisions = FALSE;
1238 gboolean has_generic_virtual = FALSE;
1241 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1243 for (i = 0; i < klass->interface_offsets_count; ++i) {
1244 MonoClass *iface = klass->interfaces_packed [i];
1245 int interface_offset = klass->interface_offsets_packed [i];
1246 int method_slot_in_interface;
1247 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1250 if (slot_num >= 0 && iface->is_inflated) {
1252 * The imt slot of the method is the same as for its declaring method,
1253 * see the comment in mono_method_get_imt_slot (), so we can
1254 * avoid inflating methods which will be discarded by
1255 * add_imt_builder_entry anyway.
1257 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1258 if (mono_method_get_imt_slot (method) != slot_num)
1261 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1262 if (method->is_generic) {
1263 has_generic_virtual = TRUE;
1266 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1269 if (extra_interfaces) {
1270 int interface_offset = klass->vtable_size;
1272 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1273 MonoClass* iface = list_item->data;
1274 int method_slot_in_interface;
1275 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1276 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1277 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1279 interface_offset += iface->method.count;
1282 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1283 /* overwrite the imt slot only if we're building all the entries or if
1284 * we're building this specific one
1286 if (slot_num < 0 || i == slot_num) {
1287 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1290 if (imt_builder [i]) {
1291 MonoImtBuilderEntry *entry;
1293 /* Link entries with imt_builder [i] */
1294 for (entry = entries; entry->next; entry = entry->next)
1296 entry->next = imt_builder [i];
1297 entries->children += imt_builder [i]->children + 1;
1299 imt_builder [i] = entries;
1302 if (has_generic_virtual) {
1304 * There might be collisions later when the the thunk is expanded.
1306 imt_collisions_bitmap |= (1 << i);
1309 * The IMT thunk might be called with an instance of one of the
1310 * generic virtual methods, so has to fallback to the IMT trampoline.
1312 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1314 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1318 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1320 if (imt_builder [i] != NULL) {
1321 int methods_in_slot = imt_builder [i]->children + 1;
1322 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1323 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1324 record_method_count_for_max_collisions = TRUE;
1326 method_count += methods_in_slot;
1330 mono_stats.imt_number_of_methods += method_count;
1331 if (record_method_count_for_max_collisions) {
1332 mono_stats.imt_method_count_when_max_collisions = method_count;
1335 for (i = 0; i < MONO_IMT_SIZE; i++) {
1336 MonoImtBuilderEntry* entry = imt_builder [i];
1337 while (entry != NULL) {
1338 MonoImtBuilderEntry* next = entry->next;
1344 /* we OR the bitmap since we may build just a single imt slot at a time */
1345 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1349 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1350 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1354 * mono_vtable_build_imt_slot:
1355 * @vtable: virtual object table struct
1356 * @imt_slot: slot in the IMT table
1358 * Fill the given @imt_slot in the IMT table of @vtable with
1359 * a trampoline or a thunk for the case of collisions.
1360 * This is part of the internal mono API.
1362 * LOCKING: Take the domain lock.
1365 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1367 gpointer *imt = (gpointer*)vtable;
1368 imt -= MONO_IMT_SIZE;
1369 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1371 /* no support for extra interfaces: the proxy objects will need
1372 * to build the complete IMT
1373 * Update and heck needs to ahppen inside the proper domain lock, as all
1374 * the changes made to a MonoVTable.
1376 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1377 mono_domain_lock (vtable->domain);
1378 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1379 if (imt [imt_slot] == imt_trampoline)
1380 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1381 mono_domain_unlock (vtable->domain);
1382 mono_loader_unlock ();
1387 * The first two free list entries both belong to the wait list: The
1388 * first entry is the pointer to the head of the list and the second
1389 * entry points to the last element. That way appending and removing
1390 * the first element are both O(1) operations.
1392 #define NUM_FREE_LISTS 12
1393 #define FIRST_FREE_LIST_SIZE 64
1394 #define MAX_WAIT_LENGTH 50
1395 #define THUNK_THRESHOLD 10
1398 * LOCKING: The domain lock must be held.
1401 init_thunk_free_lists (MonoDomain *domain)
1403 if (domain->thunk_free_lists)
1405 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1409 list_index_for_size (int item_size)
1412 int size = FIRST_FREE_LIST_SIZE;
1414 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1423 * mono_method_alloc_generic_virtual_thunk:
1425 * @size: size in bytes
1427 * Allocs size bytes to be used for the code of a generic virtual
1428 * thunk. It's either allocated from the domain's code manager or
1429 * reused from a previously invalidated piece.
1431 * LOCKING: The domain lock must be held.
1434 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1436 static gboolean inited = FALSE;
1437 static int generic_virtual_thunks_size = 0;
1441 MonoThunkFreeList **l;
1443 init_thunk_free_lists (domain);
1445 size += sizeof (guint32);
1446 if (size < sizeof (MonoThunkFreeList))
1447 size = sizeof (MonoThunkFreeList);
1449 i = list_index_for_size (size);
1450 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1451 if ((*l)->size >= size) {
1452 MonoThunkFreeList *item = *l;
1454 return ((guint32*)item) + 1;
1458 /* no suitable item found - search lists of larger sizes */
1459 while (++i < NUM_FREE_LISTS) {
1460 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1463 g_assert (item->size > size);
1464 domain->thunk_free_lists [i] = item->next;
1465 return ((guint32*)item) + 1;
1468 /* still nothing found - allocate it */
1470 mono_counters_register ("Generic virtual thunk bytes",
1471 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1474 generic_virtual_thunks_size += size;
1476 p = mono_domain_code_reserve (domain, size);
1483 * LOCKING: The domain lock must be held.
1486 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1489 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1491 init_thunk_free_lists (domain);
1493 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1494 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1495 int length = item->length;
1498 /* unlink the first item from the wait list */
1499 domain->thunk_free_lists [0] = item->next;
1500 domain->thunk_free_lists [0]->length = length - 1;
1502 i = list_index_for_size (item->size);
1504 /* put it in the free list */
1505 item->next = domain->thunk_free_lists [i];
1506 domain->thunk_free_lists [i] = item;
1510 if (domain->thunk_free_lists [1]) {
1511 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1512 domain->thunk_free_lists [0]->length++;
1514 g_assert (!domain->thunk_free_lists [0]);
1516 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1517 domain->thunk_free_lists [0]->length = 1;
1521 typedef struct _GenericVirtualCase {
1525 struct _GenericVirtualCase *next;
1526 } GenericVirtualCase;
1529 * get_generic_virtual_entries:
1531 * Return IMT entries for the generic virtual method instances for vtable slot
1534 static MonoImtBuilderEntry*
1535 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1537 GenericVirtualCase *list;
1538 MonoImtBuilderEntry *entries;
1540 mono_domain_lock (domain);
1541 if (!domain->generic_virtual_cases)
1542 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1544 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1547 for (; list; list = list->next) {
1548 MonoImtBuilderEntry *entry;
1550 if (list->count < THUNK_THRESHOLD)
1553 entry = g_new0 (MonoImtBuilderEntry, 1);
1554 entry->key = list->method;
1555 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1556 entry->has_target_code = 1;
1558 entry->children = entries->children + 1;
1559 entry->next = entries;
1563 mono_domain_unlock (domain);
1565 /* FIXME: Leaking memory ? */
1570 * mono_method_add_generic_virtual_invocation:
1572 * @vtable_slot: pointer to the vtable slot
1573 * @method: the inflated generic virtual method
1574 * @code: the method's code
1576 * Registers a call via unmanaged code to a generic virtual method
1577 * instantiation. If the number of calls reaches a threshold
1578 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1579 * virtual method thunk.
1582 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1583 gpointer *vtable_slot,
1584 MonoMethod *method, gpointer code)
1586 static gboolean inited = FALSE;
1587 static int num_added = 0;
1589 GenericVirtualCase *gvc, *list;
1590 MonoImtBuilderEntry *entries;
1594 mono_domain_lock (domain);
1595 if (!domain->generic_virtual_cases)
1596 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1598 /* Check whether the case was already added */
1599 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1602 if (gvc->method == method)
1607 /* If not found, make a new one */
1609 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1610 gvc->method = method;
1613 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1615 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1618 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1624 if (++gvc->count == THUNK_THRESHOLD) {
1625 gpointer *old_thunk = *vtable_slot;
1627 if ((gpointer)vtable_slot < (gpointer)vtable)
1628 /* Force the rebuild of the thunk at the next call */
1629 *vtable_slot = imt_trampoline;
1631 entries = get_generic_virtual_entries (domain, vtable_slot);
1633 sorted = imt_sort_slot_entries (entries);
1635 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1639 MonoImtBuilderEntry *next = entries->next;
1644 for (i = 0; i < sorted->len; ++i)
1645 g_free (g_ptr_array_index (sorted, i));
1646 g_ptr_array_free (sorted, TRUE);
1649 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1650 invalidate_generic_virtual_thunk (domain, old_thunk);
1653 mono_domain_unlock (domain);
1656 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1659 * mono_class_vtable:
1660 * @domain: the application domain
1661 * @class: the class to initialize
1663 * VTables are domain specific because we create domain specific code, and
1664 * they contain the domain specific static class data.
1665 * On failure, NULL is returned, and class->exception_type is set.
1668 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1670 MonoClassRuntimeInfo *runtime_info;
1674 /* this check can be inlined in jitted code, too */
1675 runtime_info = class->runtime_info;
1676 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1677 return runtime_info->domain_vtables [domain->domain_id];
1678 if (class->exception_type)
1680 return mono_class_create_runtime_vtable (domain, class);
1684 * mono_class_try_get_vtable:
1685 * @domain: the application domain
1686 * @class: the class to initialize
1688 * This function tries to get the associated vtable from @class if
1689 * it was already created.
1692 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1694 MonoClassRuntimeInfo *runtime_info;
1698 runtime_info = class->runtime_info;
1699 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1700 return runtime_info->domain_vtables [domain->domain_id];
1705 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1708 MonoClassRuntimeInfo *runtime_info, *old_info;
1709 MonoClassField *field;
1712 int imt_table_bytes = 0;
1713 guint32 vtable_size, class_size;
1716 gpointer *interface_offsets;
1718 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1719 mono_domain_lock (domain);
1720 runtime_info = class->runtime_info;
1721 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1722 mono_domain_unlock (domain);
1723 mono_loader_unlock ();
1724 return runtime_info->domain_vtables [domain->domain_id];
1726 if (!class->inited || class->exception_type) {
1727 if (!mono_class_init (class) || class->exception_type){
1729 mono_domain_unlock (domain);
1730 mono_loader_unlock ();
1731 exc = mono_class_get_exception_for_failure (class);
1733 mono_raise_exception (exc);
1737 mono_class_init (class);
1740 * For some classes, mono_class_init () already computed class->vtable_size, and
1741 * that is all that is needed because of the vtable trampolines.
1743 if (!class->vtable_size)
1744 mono_class_setup_vtable (class);
1746 if (class->exception_type) {
1747 mono_domain_unlock (domain);
1748 mono_loader_unlock ();
1753 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1754 if (class->interface_offsets_count) {
1755 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1756 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1757 mono_stats.imt_number_of_tables++;
1758 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1761 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1762 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1765 mono_stats.used_class_count++;
1766 mono_stats.class_vtable_size += vtable_size;
1767 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1770 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1772 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1774 vt->rank = class->rank;
1775 vt->domain = domain;
1777 mono_class_compute_gc_descriptor (class);
1779 * We can't use typed allocation in the non-root domains, since the
1780 * collector needs the GC descriptor stored in the vtable even after
1781 * the mempool containing the vtable is destroyed when the domain is
1782 * unloaded. An alternative might be to allocate vtables in the GC
1783 * heap, but this does not seem to work (it leads to crashes inside
1784 * libgc). If that approach is tried, two gc descriptors need to be
1785 * allocated for each class: one for the root domain, and one for all
1786 * other domains. The second descriptor should contain a bit for the
1787 * vtable field in MonoObject, since we can no longer assume the
1788 * vtable is reachable by other roots after the appdomain is unloaded.
1790 #ifdef HAVE_BOEHM_GC
1791 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1792 vt->gc_descr = GC_NO_DESCRIPTOR;
1795 vt->gc_descr = class->gc_descr;
1797 if ((class_size = mono_class_data_size (class))) {
1798 if (class->has_static_refs) {
1799 gpointer statics_gc_descr;
1801 gsize default_bitmap [4] = {0};
1804 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1805 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1806 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1807 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1808 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1809 if (bitmap != default_bitmap)
1812 vt->data = mono_domain_alloc0 (domain, class_size);
1814 mono_stats.class_static_data_size += class_size;
1819 while ((field = mono_class_get_fields (class, &iter))) {
1820 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1822 if (mono_field_is_deleted (field))
1824 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1825 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1826 if (special_static != SPECIAL_STATIC_NONE) {
1827 guint32 size, offset;
1829 size = mono_type_size (field->type, &align);
1830 offset = mono_alloc_special_static_data (special_static, size, align);
1831 if (!domain->special_static_fields)
1832 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1833 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1835 * This marks the field as special static to speed up the
1836 * checks in mono_field_static_get/set_value ().
1842 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1843 MonoClass *fklass = mono_class_from_mono_type (field->type);
1844 const char *data = mono_field_get_data (field);
1846 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1847 t = (char*)vt->data + field->offset;
1848 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1851 if (fklass->valuetype) {
1852 memcpy (t, data, mono_class_value_size (fklass, NULL));
1854 /* it's a pointer type: add check */
1855 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1862 vt->max_interface_id = class->max_interface_id;
1863 vt->interface_bitmap = class->interface_bitmap;
1865 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1866 // class->name, class->interface_offsets_count);
1868 if (! ARCH_USE_IMT) {
1869 /* initialize interface offsets */
1870 for (i = 0; i < class->interface_offsets_count; ++i) {
1871 int interface_id = class->interfaces_packed [i]->interface_id;
1872 int slot = class->interface_offsets_packed [i];
1873 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1877 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1878 * as we change the code in appdomain.c to invalidate vtables by
1879 * looking at the possible MonoClasses created for the domain.
1881 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1882 /* class->runtime_info is protected by the loader lock, both when
1883 * it it enlarged and when it is stored info.
1886 old_info = class->runtime_info;
1887 if (old_info && old_info->max_domain >= domain->domain_id) {
1888 /* someone already created a large enough runtime info */
1889 mono_memory_barrier ();
1890 old_info->domain_vtables [domain->domain_id] = vt;
1892 int new_size = domain->domain_id;
1894 new_size = MAX (new_size, old_info->max_domain);
1896 /* make the new size a power of two */
1898 while (new_size > i)
1901 /* this is a bounded memory retention issue: may want to
1902 * handle it differently when we'll have a rcu-like system.
1904 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1905 runtime_info->max_domain = new_size - 1;
1906 /* copy the stuff from the older info */
1908 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1910 runtime_info->domain_vtables [domain->domain_id] = vt;
1912 mono_memory_barrier ();
1913 class->runtime_info = runtime_info;
1916 /* Initialize vtable */
1917 if (vtable_trampoline) {
1918 // This also covers the AOT case
1919 for (i = 0; i < class->vtable_size; ++i) {
1920 vt->vtable [i] = vtable_trampoline;
1923 mono_class_setup_vtable (class);
1925 for (i = 0; i < class->vtable_size; ++i) {
1928 if ((cm = class->vtable [i]))
1929 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1933 if (ARCH_USE_IMT && imt_table_bytes) {
1934 /* Now that the vtable is full, we can actually fill up the IMT */
1935 if (imt_trampoline) {
1936 /* lazy construction of the IMT entries enabled */
1937 for (i = 0; i < MONO_IMT_SIZE; ++i)
1938 interface_offsets [i] = imt_trampoline;
1940 build_imt (class, vt, domain, interface_offsets, NULL);
1944 mono_domain_unlock (domain);
1945 mono_loader_unlock ();
1947 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1948 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1949 MonoException *exc = mono_class_get_exception_for_failure (class);
1951 mono_raise_exception (exc);
1954 /* make sure the parent is initialized */
1956 mono_class_vtable (domain, class->parent);
1958 vt->type = mono_type_get_object (domain, &class->byval_arg);
1959 if (class->contextbound)
1968 * mono_class_proxy_vtable:
1969 * @domain: the application domain
1970 * @remove_class: the remote class
1972 * Creates a vtable for transparent proxies. It is basically
1973 * a copy of the real vtable of the class wrapped in @remote_class,
1974 * but all function pointers invoke the remoting functions, and
1975 * vtable->klass points to the transparent proxy class, and not to @class.
1978 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1980 MonoVTable *vt, *pvt;
1981 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1983 GSList *extra_interfaces = NULL;
1984 MonoClass *class = remote_class->proxy_class;
1985 gpointer *interface_offsets;
1987 vt = mono_class_vtable (domain, class);
1988 max_interface_id = vt->max_interface_id;
1990 /* Calculate vtable space for extra interfaces */
1991 for (j = 0; j < remote_class->interface_count; j++) {
1992 MonoClass* iclass = remote_class->interfaces[j];
1996 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1997 continue; /* interface implemented by the class */
1998 if (g_slist_find (extra_interfaces, iclass))
2001 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2003 method_count = mono_class_num_methods (iclass);
2005 ifaces = mono_class_get_implemented_interfaces (iclass);
2007 for (i = 0; i < ifaces->len; ++i) {
2008 MonoClass *ic = g_ptr_array_index (ifaces, i);
2009 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2010 continue; /* interface implemented by the class */
2011 if (g_slist_find (extra_interfaces, ic))
2013 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2014 method_count += mono_class_num_methods (ic);
2016 g_ptr_array_free (ifaces, TRUE);
2019 extra_interface_vtsize += method_count * sizeof (gpointer);
2020 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2024 mono_stats.imt_number_of_tables++;
2025 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2026 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2027 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2029 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2030 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2033 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2035 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2037 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2039 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2040 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2042 pvt->klass = mono_defaults.transparent_proxy_class;
2043 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2044 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2046 /* initialize vtable */
2047 mono_class_setup_vtable (class);
2048 for (i = 0; i < class->vtable_size; ++i) {
2051 if ((cm = class->vtable [i]))
2052 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2054 pvt->vtable [i] = NULL;
2057 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2058 /* create trampolines for abstract methods */
2059 for (k = class; k; k = k->parent) {
2061 gpointer iter = NULL;
2062 while ((m = mono_class_get_methods (k, &iter)))
2063 if (!pvt->vtable [m->slot])
2064 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2068 pvt->max_interface_id = max_interface_id;
2069 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2071 if (! ARCH_USE_IMT) {
2072 /* initialize interface offsets */
2073 for (i = 0; i < class->interface_offsets_count; ++i) {
2074 int interface_id = class->interfaces_packed [i]->interface_id;
2075 int slot = class->interface_offsets_packed [i];
2076 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2079 for (i = 0; i < class->interface_offsets_count; ++i) {
2080 int interface_id = class->interfaces_packed [i]->interface_id;
2081 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2084 if (extra_interfaces) {
2085 int slot = class->vtable_size;
2091 /* Create trampolines for the methods of the interfaces */
2092 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2093 interf = list_item->data;
2095 if (! ARCH_USE_IMT) {
2096 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2098 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2102 while ((cm = mono_class_get_methods (interf, &iter)))
2103 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2105 slot += mono_class_num_methods (interf);
2107 if (! ARCH_USE_IMT) {
2108 g_slist_free (extra_interfaces);
2113 /* Now that the vtable is full, we can actually fill up the IMT */
2114 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2115 if (extra_interfaces) {
2116 g_slist_free (extra_interfaces);
2124 * mono_class_field_is_special_static:
2126 * Returns whether @field is a thread/context static field.
2129 mono_class_field_is_special_static (MonoClassField *field)
2131 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2133 if (mono_field_is_deleted (field))
2135 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2136 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2143 * mono_class_has_special_static_fields:
2145 * Returns whenever @klass has any thread/context static fields.
2148 mono_class_has_special_static_fields (MonoClass *klass)
2150 MonoClassField *field;
2154 while ((field = mono_class_get_fields (klass, &iter))) {
2155 g_assert (field->parent == klass);
2156 if (mono_class_field_is_special_static (field))
2164 * create_remote_class_key:
2165 * Creates an array of pointers that can be used as a hash key for a remote class.
2166 * The first element of the array is the number of pointers.
2169 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2174 if (remote_class == NULL) {
2175 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2176 key = g_malloc (sizeof(gpointer) * 3);
2177 key [0] = GINT_TO_POINTER (2);
2178 key [1] = mono_defaults.marshalbyrefobject_class;
2179 key [2] = extra_class;
2181 key = g_malloc (sizeof(gpointer) * 2);
2182 key [0] = GINT_TO_POINTER (1);
2183 key [1] = extra_class;
2186 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2187 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2188 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2189 key [1] = remote_class->proxy_class;
2191 // Keep the list of interfaces sorted
2192 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2193 if (extra_class && remote_class->interfaces [i] > extra_class) {
2194 key [j++] = extra_class;
2197 key [j] = remote_class->interfaces [i];
2200 key [j] = extra_class;
2202 // Replace the old class. The interface list is the same
2203 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2204 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2205 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2206 for (i = 0; i < remote_class->interface_count; i++)
2207 key [2 + i] = remote_class->interfaces [i];
2215 * copy_remote_class_key:
2217 * Make a copy of KEY in the domain and return the copy.
2220 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2222 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2223 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2225 memcpy (mp_key, key, key_size);
2231 * mono_remote_class:
2232 * @domain: the application domain
2233 * @class_name: name of the remote class
2235 * Creates and initializes a MonoRemoteClass object for a remote type.
2239 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2241 MonoRemoteClass *rc;
2242 gpointer* key, *mp_key;
2244 key = create_remote_class_key (NULL, proxy_class);
2246 mono_domain_lock (domain);
2247 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2251 mono_domain_unlock (domain);
2255 mp_key = copy_remote_class_key (domain, key);
2259 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2260 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2261 rc->interface_count = 1;
2262 rc->interfaces [0] = proxy_class;
2263 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2265 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2266 rc->interface_count = 0;
2267 rc->proxy_class = proxy_class;
2270 rc->default_vtable = NULL;
2271 rc->xdomain_vtable = NULL;
2272 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2273 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2275 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2277 mono_domain_unlock (domain);
2282 * clone_remote_class:
2283 * Creates a copy of the remote_class, adding the provided class or interface
2285 static MonoRemoteClass*
2286 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2288 MonoRemoteClass *rc;
2289 gpointer* key, *mp_key;
2291 key = create_remote_class_key (remote_class, extra_class);
2292 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2298 mp_key = copy_remote_class_key (domain, key);
2302 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2304 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2305 rc->proxy_class = remote_class->proxy_class;
2306 rc->interface_count = remote_class->interface_count + 1;
2308 // Keep the list of interfaces sorted, since the hash key of
2309 // the remote class depends on this
2310 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2311 if (remote_class->interfaces [i] > extra_class && i == j)
2312 rc->interfaces [j++] = extra_class;
2313 rc->interfaces [j] = remote_class->interfaces [i];
2316 rc->interfaces [j] = extra_class;
2318 // Replace the old class. The interface array is the same
2319 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2320 rc->proxy_class = extra_class;
2321 rc->interface_count = remote_class->interface_count;
2322 if (rc->interface_count > 0)
2323 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2326 rc->default_vtable = NULL;
2327 rc->xdomain_vtable = NULL;
2328 rc->proxy_class_name = remote_class->proxy_class_name;
2330 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2336 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2338 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2339 mono_domain_lock (domain);
2340 if (rp->target_domain_id != -1) {
2341 if (remote_class->xdomain_vtable == NULL)
2342 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2343 mono_domain_unlock (domain);
2344 mono_loader_unlock ();
2345 return remote_class->xdomain_vtable;
2347 if (remote_class->default_vtable == NULL) {
2350 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2351 klass = mono_class_from_mono_type (type);
2352 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2353 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2355 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2358 mono_domain_unlock (domain);
2359 mono_loader_unlock ();
2360 return remote_class->default_vtable;
2364 * mono_upgrade_remote_class:
2365 * @domain: the application domain
2366 * @tproxy: the proxy whose remote class has to be upgraded.
2367 * @klass: class to which the remote class can be casted.
2369 * Updates the vtable of the remote class by adding the necessary method slots
2370 * and interface offsets so it can be safely casted to klass. klass can be a
2371 * class or an interface.
2374 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2376 MonoTransparentProxy *tproxy;
2377 MonoRemoteClass *remote_class;
2378 gboolean redo_vtable;
2380 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2381 mono_domain_lock (domain);
2383 tproxy = (MonoTransparentProxy*) proxy_object;
2384 remote_class = tproxy->remote_class;
2386 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2389 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2390 if (remote_class->interfaces [i] == klass)
2391 redo_vtable = FALSE;
2394 redo_vtable = (remote_class->proxy_class != klass);
2398 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2399 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2402 mono_domain_unlock (domain);
2403 mono_loader_unlock ();
2408 * mono_object_get_virtual_method:
2409 * @obj: object to operate on.
2412 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2413 * the instance of a callvirt of method.
2416 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2419 MonoMethod **vtable;
2421 MonoMethod *res = NULL;
2423 klass = mono_object_class (obj);
2424 if (klass == mono_defaults.transparent_proxy_class) {
2425 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2431 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2434 mono_class_setup_vtable (klass);
2435 vtable = klass->vtable;
2437 if (method->slot == -1) {
2438 /* method->slot might not be set for instances of generic methods */
2439 if (method->is_inflated) {
2440 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2441 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2444 g_assert_not_reached ();
2448 /* check method->slot is a valid index: perform isinstance? */
2449 if (method->slot != -1) {
2450 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2452 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2454 res = vtable [method->slot];
2459 /* It may be an interface, abstract class method or generic method */
2460 if (!res || mono_method_signature (res)->generic_param_count)
2463 /* generic methods demand invoke_with_check */
2464 if (mono_method_signature (res)->generic_param_count)
2465 res = mono_marshal_get_remoting_invoke_with_check (res);
2467 res = mono_marshal_get_remoting_invoke (res);
2469 if (method->is_inflated) {
2470 /* Have to inflate the result */
2471 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2481 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2483 g_error ("runtime invoke called on uninitialized runtime");
2487 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2490 * mono_runtime_invoke:
2491 * @method: method to invoke
2492 * @obJ: object instance
2493 * @params: arguments to the method
2494 * @exc: exception information.
2496 * Invokes the method represented by @method on the object @obj.
2498 * obj is the 'this' pointer, it should be NULL for static
2499 * methods, a MonoObject* for object instances and a pointer to
2500 * the value type for value types.
2502 * The params array contains the arguments to the method with the
2503 * same convention: MonoObject* pointers for object instances and
2504 * pointers to the value type otherwise.
2506 * From unmanaged code you'll usually use the
2507 * mono_runtime_invoke() variant.
2509 * Note that this function doesn't handle virtual methods for
2510 * you, it will exec the exact method you pass: we still need to
2511 * expose a function to lookup the derived class implementation
2512 * of a virtual method (there are examples of this in the code,
2515 * You can pass NULL as the exc argument if you don't want to
2516 * catch exceptions, otherwise, *exc will be set to the exception
2517 * thrown, if any. if an exception is thrown, you can't use the
2518 * MonoObject* result from the function.
2520 * If the method returns a value type, it is boxed in an object
2524 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2526 if (mono_runtime_get_no_exec ())
2527 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2529 return default_mono_runtime_invoke (method, obj, params, exc);
2533 * mono_method_get_unmanaged_thunk:
2534 * @method: method to generate a thunk for.
2536 * Returns an unmanaged->managed thunk that can be used to call
2537 * a managed method directly from C.
2539 * The thunk's C signature closely matches the managed signature:
2541 * C#: public bool Equals (object obj);
2542 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2543 * MonoObject*, MonoException**);
2545 * The 1st ("this") parameter must not be used with static methods:
2547 * C#: public static bool ReferenceEquals (object a, object b);
2548 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2551 * The last argument must be a non-null pointer of a MonoException* pointer.
2552 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2553 * exception has been thrown in managed code. Otherwise it will point
2554 * to the MonoException* caught by the thunk. In this case, the result of
2555 * the thunk is undefined:
2557 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2558 * MonoException *ex = NULL;
2559 * Equals func = mono_method_get_unmanaged_thunk (method);
2560 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2562 * // handle exception
2565 * The calling convention of the thunk matches the platform's default
2566 * convention. This means that under Windows, C declarations must
2567 * contain the __stdcall attribute:
2569 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2570 * MonoObject*, MonoException**);
2574 * Value type arguments and return values are treated as they were objects:
2576 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2577 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2579 * Arguments must be properly boxed upon trunk's invocation, while return
2580 * values must be unboxed.
2583 mono_method_get_unmanaged_thunk (MonoMethod *method)
2585 method = mono_marshal_get_thunk_invoke_wrapper (method);
2586 return mono_compile_method (method);
2590 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2594 /* object fields cannot be byref, so we don't need a
2596 gpointer *p = (gpointer*)dest;
2603 case MONO_TYPE_BOOLEAN:
2605 case MONO_TYPE_U1: {
2606 guint8 *p = (guint8*)dest;
2607 *p = value ? *(guint8*)value : 0;
2612 case MONO_TYPE_CHAR: {
2613 guint16 *p = (guint16*)dest;
2614 *p = value ? *(guint16*)value : 0;
2617 #if SIZEOF_VOID_P == 4
2622 case MONO_TYPE_U4: {
2623 gint32 *p = (gint32*)dest;
2624 *p = value ? *(gint32*)value : 0;
2627 #if SIZEOF_VOID_P == 8
2632 case MONO_TYPE_U8: {
2633 gint64 *p = (gint64*)dest;
2634 *p = value ? *(gint64*)value : 0;
2637 case MONO_TYPE_R4: {
2638 float *p = (float*)dest;
2639 *p = value ? *(float*)value : 0;
2642 case MONO_TYPE_R8: {
2643 double *p = (double*)dest;
2644 *p = value ? *(double*)value : 0;
2647 case MONO_TYPE_STRING:
2648 case MONO_TYPE_SZARRAY:
2649 case MONO_TYPE_CLASS:
2650 case MONO_TYPE_OBJECT:
2651 case MONO_TYPE_ARRAY:
2652 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2654 case MONO_TYPE_FNPTR:
2655 case MONO_TYPE_PTR: {
2656 gpointer *p = (gpointer*)dest;
2657 *p = deref_pointer? *(gpointer*)value: value;
2660 case MONO_TYPE_VALUETYPE:
2661 /* note that 't' and 'type->type' can be different */
2662 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2663 t = mono_class_enum_basetype (type->data.klass)->type;
2666 MonoClass *class = mono_class_from_mono_type (type);
2667 int size = mono_class_value_size (class, NULL);
2668 if (value == NULL) {
2669 memset (dest, 0, size);
2671 memcpy (dest, value, size);
2672 mono_gc_wbarrier_value_copy (dest, value, size, class);
2676 case MONO_TYPE_GENERICINST:
2677 t = type->data.generic_class->container_class->byval_arg.type;
2680 g_warning ("got type %x", type->type);
2681 g_assert_not_reached ();
2686 * mono_field_set_value:
2687 * @obj: Instance object
2688 * @field: MonoClassField describing the field to set
2689 * @value: The value to be set
2691 * Sets the value of the field described by @field in the object instance @obj
2692 * to the value passed in @value. This method should only be used for instance
2693 * fields. For static fields, use mono_field_static_set_value.
2695 * The value must be on the native format of the field type.
2698 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2702 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2704 dest = (char*)obj + field->offset;
2705 set_value (field->type, dest, value, FALSE);
2709 * mono_field_static_set_value:
2710 * @field: MonoClassField describing the field to set
2711 * @value: The value to be set
2713 * Sets the value of the static field described by @field
2714 * to the value passed in @value.
2716 * The value must be on the native format of the field type.
2719 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2723 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2724 /* you cant set a constant! */
2725 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2727 if (field->offset == -1) {
2728 /* Special static */
2729 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2730 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2732 dest = (char*)vt->data + field->offset;
2734 set_value (field->type, dest, value, FALSE);
2737 /* Used by the debugger */
2739 mono_vtable_get_static_field_data (MonoVTable *vt)
2745 * mono_field_get_value:
2746 * @obj: Object instance
2747 * @field: MonoClassField describing the field to fetch information from
2748 * @value: pointer to the location where the value will be stored
2750 * Use this routine to get the value of the field @field in the object
2753 * The pointer provided by value must be of the field type, for reference
2754 * types this is a MonoObject*, for value types its the actual pointer to
2759 * mono_field_get_value (obj, int_field, &i);
2762 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2766 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2768 src = (char*)obj + field->offset;
2769 set_value (field->type, value, src, TRUE);
2773 * mono_field_get_value_object:
2774 * @domain: domain where the object will be created (if boxing)
2775 * @field: MonoClassField describing the field to fetch information from
2776 * @obj: The object instance for the field.
2778 * Returns: a new MonoObject with the value from the given field. If the
2779 * field represents a value type, the value is boxed.
2783 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2787 MonoVTable *vtable = NULL;
2789 gboolean is_static = FALSE;
2790 gboolean is_ref = FALSE;
2792 switch (field->type->type) {
2793 case MONO_TYPE_STRING:
2794 case MONO_TYPE_OBJECT:
2795 case MONO_TYPE_CLASS:
2796 case MONO_TYPE_ARRAY:
2797 case MONO_TYPE_SZARRAY:
2802 case MONO_TYPE_BOOLEAN:
2805 case MONO_TYPE_CHAR:
2814 case MONO_TYPE_VALUETYPE:
2815 is_ref = field->type->byref;
2817 case MONO_TYPE_GENERICINST:
2818 is_ref = !field->type->data.generic_class->container_class->valuetype;
2821 g_error ("type 0x%x not handled in "
2822 "mono_field_get_value_object", field->type->type);
2826 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2828 vtable = mono_class_vtable (domain, field->parent);
2829 if (!vtable->initialized)
2830 mono_runtime_class_init (vtable);
2835 mono_field_static_get_value (vtable, field, &o);
2837 mono_field_get_value (obj, field, &o);
2842 /* boxed value type */
2843 klass = mono_class_from_mono_type (field->type);
2844 o = mono_object_new (domain, klass);
2845 v = ((gchar *) o) + sizeof (MonoObject);
2847 mono_field_static_get_value (vtable, field, v);
2849 mono_field_get_value (obj, field, v);
2856 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2859 const char *p = blob;
2860 mono_metadata_decode_blob_size (p, &p);
2863 case MONO_TYPE_BOOLEAN:
2866 *(guint8 *) value = *p;
2868 case MONO_TYPE_CHAR:
2871 *(guint16*) value = read16 (p);
2875 *(guint32*) value = read32 (p);
2879 *(guint64*) value = read64 (p);
2882 readr4 (p, (float*) value);
2885 readr8 (p, (double*) value);
2887 case MONO_TYPE_STRING:
2888 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2890 case MONO_TYPE_CLASS:
2891 *(gpointer*) value = NULL;
2895 g_warning ("type 0x%02x should not be in constant table", type);
2901 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2903 MonoTypeEnum def_type;
2906 data = mono_class_get_field_default_value (field, &def_type);
2907 mono_get_constant_value_from_blob (domain, def_type, data, value);
2911 * mono_field_static_get_value:
2912 * @vt: vtable to the object
2913 * @field: MonoClassField describing the field to fetch information from
2914 * @value: where the value is returned
2916 * Use this routine to get the value of the static field @field value.
2918 * The pointer provided by value must be of the field type, for reference
2919 * types this is a MonoObject*, for value types its the actual pointer to
2924 * mono_field_static_get_value (vt, int_field, &i);
2927 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2931 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2933 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2934 get_default_field_value (vt->domain, field, value);
2938 if (field->offset == -1) {
2939 /* Special static */
2940 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2941 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2943 src = (char*)vt->data + field->offset;
2945 set_value (field->type, value, src, TRUE);
2949 * mono_property_set_value:
2950 * @prop: MonoProperty to set
2951 * @obj: instance object on which to act
2952 * @params: parameters to pass to the propery
2953 * @exc: optional exception
2955 * Invokes the property's set method with the given arguments on the
2956 * object instance obj (or NULL for static properties).
2958 * You can pass NULL as the exc argument if you don't want to
2959 * catch exceptions, otherwise, *exc will be set to the exception
2960 * thrown, if any. if an exception is thrown, you can't use the
2961 * MonoObject* result from the function.
2964 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2966 default_mono_runtime_invoke (prop->set, obj, params, exc);
2970 * mono_property_get_value:
2971 * @prop: MonoProperty to fetch
2972 * @obj: instance object on which to act
2973 * @params: parameters to pass to the propery
2974 * @exc: optional exception
2976 * Invokes the property's get method with the given arguments on the
2977 * object instance obj (or NULL for static properties).
2979 * You can pass NULL as the exc argument if you don't want to
2980 * catch exceptions, otherwise, *exc will be set to the exception
2981 * thrown, if any. if an exception is thrown, you can't use the
2982 * MonoObject* result from the function.
2984 * Returns: the value from invoking the get method on the property.
2987 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2989 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2993 * mono_nullable_init:
2994 * @buf: The nullable structure to initialize.
2995 * @value: the value to initialize from
2996 * @klass: the type for the object
2998 * Initialize the nullable structure pointed to by @buf from @value which
2999 * should be a boxed value type. The size of @buf should be able to hold
3000 * as much data as the @klass->instance_size (which is the number of bytes
3001 * that will be copies).
3003 * Since Nullables have variable structure, we can not define a C
3004 * structure for them.
3007 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3009 MonoClass *param_class = klass->cast_class;
3011 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3012 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3014 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3016 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3018 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3022 * mono_nullable_box:
3023 * @buf: The buffer representing the data to be boxed
3024 * @klass: the type to box it as.
3026 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3030 mono_nullable_box (guint8 *buf, MonoClass *klass)
3032 MonoClass *param_class = klass->cast_class;
3034 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3035 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3037 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3038 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3039 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3047 * mono_get_delegate_invoke:
3048 * @klass: The delegate class
3050 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3053 mono_get_delegate_invoke (MonoClass *klass)
3057 /* This is called at runtime, so avoid the slower search in metadata */
3058 mono_class_setup_methods (klass);
3060 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3067 * mono_runtime_delegate_invoke:
3068 * @delegate: pointer to a delegate object.
3069 * @params: parameters for the delegate.
3070 * @exc: Pointer to the exception result.
3072 * Invokes the delegate method @delegate with the parameters provided.
3074 * You can pass NULL as the exc argument if you don't want to
3075 * catch exceptions, otherwise, *exc will be set to the exception
3076 * thrown, if any. if an exception is thrown, you can't use the
3077 * MonoObject* result from the function.
3080 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3084 im = mono_get_delegate_invoke (delegate->vtable->klass);
3087 return mono_runtime_invoke (im, delegate, params, exc);
3090 static char **main_args = NULL;
3091 static int num_main_args;
3094 * mono_runtime_get_main_args:
3096 * Returns: a MonoArray with the arguments passed to the main program
3099 mono_runtime_get_main_args (void)
3103 MonoDomain *domain = mono_domain_get ();
3108 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3110 for (i = 0; i < num_main_args; ++i)
3111 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3117 fire_process_exit_event (void)
3119 MonoClassField *field;
3120 MonoDomain *domain = mono_domain_get ();
3122 MonoObject *delegate, *exc;
3124 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3127 if (domain != mono_get_root_domain ())
3130 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3131 if (delegate == NULL)
3136 mono_runtime_delegate_invoke (delegate, pa, &exc);
3140 * mono_runtime_run_main:
3141 * @method: the method to start the application with (usually Main)
3142 * @argc: number of arguments from the command line
3143 * @argv: array of strings from the command line
3144 * @exc: excetption results
3146 * Execute a standard Main() method (argc/argv contains the
3147 * executable name). This method also sets the command line argument value
3148 * needed by System.Environment.
3153 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3157 MonoArray *args = NULL;
3158 MonoDomain *domain = mono_domain_get ();
3159 gchar *utf8_fullpath;
3162 g_assert (method != NULL);
3164 mono_thread_set_main (mono_thread_current ());
3166 main_args = g_new0 (char*, argc);
3167 num_main_args = argc;
3169 if (!g_path_is_absolute (argv [0])) {
3170 gchar *basename = g_path_get_basename (argv [0]);
3171 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3175 utf8_fullpath = mono_utf8_from_external (fullpath);
3176 if(utf8_fullpath == NULL) {
3177 /* Printing the arg text will cause glib to
3178 * whinge about "Invalid UTF-8", but at least
3179 * its relevant, and shows the problem text
3182 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3183 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3190 utf8_fullpath = mono_utf8_from_external (argv[0]);
3191 if(utf8_fullpath == NULL) {
3192 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3193 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3198 main_args [0] = utf8_fullpath;
3200 for (i = 1; i < argc; ++i) {
3203 utf8_arg=mono_utf8_from_external (argv[i]);
3204 if(utf8_arg==NULL) {
3205 /* Ditto the comment about Invalid UTF-8 here */
3206 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3207 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3211 main_args [i] = utf8_arg;
3215 if (mono_method_signature (method)->param_count) {
3216 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3217 for (i = 0; i < argc; ++i) {
3218 /* The encodings should all work, given that
3219 * we've checked all these args for the
3222 gchar *str = mono_utf8_from_external (argv [i]);
3223 MonoString *arg = mono_string_new (domain, str);
3224 mono_array_setref (args, i, arg);
3228 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3231 mono_assembly_set_main (method->klass->image->assembly);
3233 result = mono_runtime_exec_main (method, args, exc);
3234 fire_process_exit_event ();
3238 /* Used in call_unhandled_exception_delegate */
3240 create_unhandled_exception_eventargs (MonoObject *exc)
3244 MonoMethod *method = NULL;
3245 MonoBoolean is_terminating = TRUE;
3248 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3251 mono_class_init (klass);
3253 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3254 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3258 args [1] = &is_terminating;
3260 obj = mono_object_new (mono_domain_get (), klass);
3261 mono_runtime_invoke (method, obj, args, NULL);
3266 /* Used in mono_unhandled_exception */
3268 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3269 MonoObject *e = NULL;
3272 pa [0] = domain->domain;
3273 pa [1] = create_unhandled_exception_eventargs (exc);
3274 mono_runtime_delegate_invoke (delegate, pa, &e);
3277 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3278 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3283 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3286 * mono_runtime_unhandled_exception_policy_set:
3287 * @policy: the new policy
3289 * This is a VM internal routine.
3291 * Sets the runtime policy for handling unhandled exceptions.
3294 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3295 runtime_unhandled_exception_policy = policy;
3299 * mono_runtime_unhandled_exception_policy_get:
3301 * This is a VM internal routine.
3303 * Gets the runtime policy for handling unhandled exceptions.
3305 MonoRuntimeUnhandledExceptionPolicy
3306 mono_runtime_unhandled_exception_policy_get (void) {
3307 return runtime_unhandled_exception_policy;
3311 * mono_unhandled_exception:
3312 * @exc: exception thrown
3314 * This is a VM internal routine.
3316 * We call this function when we detect an unhandled exception
3317 * in the default domain.
3319 * It invokes the * UnhandledException event in AppDomain or prints
3320 * a warning to the console
3323 mono_unhandled_exception (MonoObject *exc)
3325 MonoDomain *current_domain = mono_domain_get ();
3326 MonoDomain *root_domain = mono_get_root_domain ();
3327 MonoClassField *field;
3328 MonoObject *current_appdomain_delegate;
3329 MonoObject *root_appdomain_delegate;
3331 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3332 "UnhandledException");
3335 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3336 gboolean abort_process = (mono_thread_current () == main_thread) ||
3337 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3338 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3339 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3340 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3342 current_appdomain_delegate = NULL;
3345 /* set exitcode only if we will abort the process */
3347 mono_environment_exitcode_set (1);
3348 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3349 mono_print_unhandled_exception (exc);
3351 if (root_appdomain_delegate) {
3352 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3354 if (current_appdomain_delegate) {
3355 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3362 * Launch a new thread to execute a function
3364 * main_func is called back from the thread with main_args as the
3365 * parameter. The callback function is expected to start Main()
3366 * eventually. This function then waits for all managed threads to
3368 * It is not necesseray anymore to execute managed code in a subthread,
3369 * so this function should not be used anymore by default: just
3370 * execute the code and then call mono_thread_manage ().
3373 mono_runtime_exec_managed_code (MonoDomain *domain,
3374 MonoMainThreadFunc main_func,
3377 mono_thread_create (domain, main_func, main_args);
3379 mono_thread_manage ();
3383 * Execute a standard Main() method (args doesn't contain the
3387 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3392 MonoCustomAttrInfo* cinfo;
3393 gboolean has_stathread_attribute;
3394 MonoThread* thread = mono_thread_current ();
3400 domain = mono_object_domain (args);
3401 if (!domain->entry_assembly) {
3403 MonoAssembly *assembly;
3405 assembly = method->klass->image->assembly;
3406 domain->entry_assembly = assembly;
3407 /* Domains created from another domain already have application_base and configuration_file set */
3408 if (domain->setup->application_base == NULL) {
3409 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3412 if (domain->setup->configuration_file == NULL) {
3413 str = g_strconcat (assembly->image->name, ".config", NULL);
3414 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3416 mono_set_private_bin_path_from_config (domain);
3420 cinfo = mono_custom_attrs_from_method (method);
3422 static MonoClass *stathread_attribute = NULL;
3423 if (!stathread_attribute)
3424 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3425 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3427 mono_custom_attrs_free (cinfo);
3429 has_stathread_attribute = FALSE;
3431 if (has_stathread_attribute) {
3432 thread->apartment_state = ThreadApartmentState_STA;
3433 } else if (mono_framework_version () == 1) {
3434 thread->apartment_state = ThreadApartmentState_Unknown;
3436 thread->apartment_state = ThreadApartmentState_MTA;
3438 mono_thread_init_apartment_state ();
3440 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3442 /* FIXME: check signature of method */
3443 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3445 res = mono_runtime_invoke (method, NULL, pa, exc);
3447 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3451 mono_environment_exitcode_set (rval);
3453 mono_runtime_invoke (method, NULL, pa, exc);
3457 /* If the return type of Main is void, only
3458 * set the exitcode if an exception was thrown
3459 * (we don't want to blow away an
3460 * explicitly-set exit code)
3463 mono_environment_exitcode_set (rval);
3467 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3473 * mono_install_runtime_invoke:
3474 * @func: Function to install
3476 * This is a VM internal routine
3479 mono_install_runtime_invoke (MonoInvokeFunc func)
3481 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3486 * mono_runtime_invoke_array:
3487 * @method: method to invoke
3488 * @obJ: object instance
3489 * @params: arguments to the method
3490 * @exc: exception information.
3492 * Invokes the method represented by @method on the object @obj.
3494 * obj is the 'this' pointer, it should be NULL for static
3495 * methods, a MonoObject* for object instances and a pointer to
3496 * the value type for value types.
3498 * The params array contains the arguments to the method with the
3499 * same convention: MonoObject* pointers for object instances and
3500 * pointers to the value type otherwise. The _invoke_array
3501 * variant takes a C# object[] as the params argument (MonoArray
3502 * *params): in this case the value types are boxed inside the
3503 * respective reference representation.
3505 * From unmanaged code you'll usually use the
3506 * mono_runtime_invoke() variant.
3508 * Note that this function doesn't handle virtual methods for
3509 * you, it will exec the exact method you pass: we still need to
3510 * expose a function to lookup the derived class implementation
3511 * of a virtual method (there are examples of this in the code,
3514 * You can pass NULL as the exc argument if you don't want to
3515 * catch exceptions, otherwise, *exc will be set to the exception
3516 * thrown, if any. if an exception is thrown, you can't use the
3517 * MonoObject* result from the function.
3519 * If the method returns a value type, it is boxed in an object
3523 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3526 MonoMethodSignature *sig = mono_method_signature (method);
3527 gpointer *pa = NULL;
3530 gboolean has_byref_nullables = FALSE;
3532 if (NULL != params) {
3533 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3534 for (i = 0; i < mono_array_length (params); i++) {
3535 MonoType *t = sig->params [i];
3541 case MONO_TYPE_BOOLEAN:
3544 case MONO_TYPE_CHAR:
3553 case MONO_TYPE_VALUETYPE:
3554 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3555 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3556 pa [i] = mono_array_get (params, MonoObject*, i);
3558 has_byref_nullables = TRUE;
3560 /* MS seems to create the objects if a null is passed in */
3561 if (!mono_array_get (params, MonoObject*, i))
3562 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3566 * We can't pass the unboxed vtype byref to the callee, since
3567 * that would mean the callee would be able to modify boxed
3568 * primitive types. So we (and MS) make a copy of the boxed
3569 * object, pass that to the callee, and replace the original
3570 * boxed object in the arg array with the copy.
3572 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3573 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3574 mono_array_setref (params, i, copy);
3577 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3580 case MONO_TYPE_STRING:
3581 case MONO_TYPE_OBJECT:
3582 case MONO_TYPE_CLASS:
3583 case MONO_TYPE_ARRAY:
3584 case MONO_TYPE_SZARRAY:
3586 pa [i] = mono_array_addr (params, MonoObject*, i);
3587 // FIXME: I need to check this code path
3589 pa [i] = mono_array_get (params, MonoObject*, i);
3591 case MONO_TYPE_GENERICINST:
3593 t = &t->data.generic_class->container_class->this_arg;
3595 t = &t->data.generic_class->container_class->byval_arg;
3597 case MONO_TYPE_PTR: {
3600 /* The argument should be an IntPtr */
3601 arg = mono_array_get (params, MonoObject*, i);
3605 g_assert (arg->vtable->klass == mono_defaults.int_class);
3606 pa [i] = ((MonoIntPtr*)arg)->m_value;
3611 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3616 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3619 if (mono_class_is_nullable (method->klass)) {
3620 /* Need to create a boxed vtype instead */
3626 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3630 obj = mono_object_new (mono_domain_get (), method->klass);
3631 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3632 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3634 if (method->klass->valuetype)
3635 o = mono_object_unbox (obj);
3638 } else if (method->klass->valuetype) {
3639 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3642 mono_runtime_invoke (method, o, pa, exc);
3645 if (mono_class_is_nullable (method->klass)) {
3646 MonoObject *nullable;
3648 /* Convert the unboxed vtype into a Nullable structure */
3649 nullable = mono_object_new (mono_domain_get (), method->klass);
3651 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3652 obj = mono_object_unbox (nullable);
3655 /* obj must be already unboxed if needed */
3656 res = mono_runtime_invoke (method, obj, pa, exc);
3658 if (sig->ret->type == MONO_TYPE_PTR) {
3659 MonoClass *pointer_class;
3660 static MonoMethod *box_method;
3662 MonoObject *box_exc;
3665 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3666 * convert it to a Pointer object.
3668 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3670 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3672 g_assert (res->vtable->klass == mono_defaults.int_class);
3673 box_args [0] = ((MonoIntPtr*)res)->m_value;
3674 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3675 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3676 g_assert (!box_exc);
3679 if (has_byref_nullables) {
3681 * The runtime invoke wrapper already converted byref nullables back,
3682 * and stored them in pa, we just need to copy them back to the
3685 for (i = 0; i < mono_array_length (params); i++) {
3686 MonoType *t = sig->params [i];
3688 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3689 mono_array_setref (params, i, pa [i]);
3698 arith_overflow (void)
3700 mono_raise_exception (mono_get_exception_overflow ());
3704 * mono_object_allocate:
3705 * @size: number of bytes to allocate
3707 * This is a very simplistic routine until we have our GC-aware
3710 * Returns: an allocated object of size @size, or NULL on failure.
3712 static inline void *
3713 mono_object_allocate (size_t size, MonoVTable *vtable)
3716 mono_stats.new_object_count++;
3717 ALLOC_OBJECT (o, vtable, size);
3723 * mono_object_allocate_ptrfree:
3724 * @size: number of bytes to allocate
3726 * Note that the memory allocated is not zeroed.
3727 * Returns: an allocated object of size @size, or NULL on failure.
3729 static inline void *
3730 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3733 mono_stats.new_object_count++;
3734 ALLOC_PTRFREE (o, vtable, size);
3738 static inline void *
3739 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3742 ALLOC_TYPED (o, size, vtable);
3743 mono_stats.new_object_count++;
3750 * @klass: the class of the object that we want to create
3752 * Returns: a newly created object whose definition is
3753 * looked up using @klass. This will not invoke any constructors,
3754 * so the consumer of this routine has to invoke any constructors on
3755 * its own to initialize the object.
3758 mono_object_new (MonoDomain *domain, MonoClass *klass)
3760 MONO_ARCH_SAVE_REGS;
3761 return mono_object_new_specific (mono_class_vtable (domain, klass));
3765 * mono_object_new_specific:
3766 * @vtable: the vtable of the object that we want to create
3768 * Returns: A newly created object with class and domain specified
3772 mono_object_new_specific (MonoVTable *vtable)
3776 MONO_ARCH_SAVE_REGS;
3778 /* check for is_com_object for COM Interop */
3779 if (vtable->remote || vtable->klass->is_com_object)
3782 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3785 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3788 mono_class_init (klass);
3790 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3792 vtable->domain->create_proxy_for_type_method = im;
3795 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3797 o = mono_runtime_invoke (im, NULL, pa, NULL);
3798 if (o != NULL) return o;
3801 return mono_object_new_alloc_specific (vtable);
3805 mono_object_new_alloc_specific (MonoVTable *vtable)
3809 if (!vtable->klass->has_references) {
3810 o = mono_object_new_ptrfree (vtable);
3811 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3812 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3814 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3815 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3817 if (G_UNLIKELY (vtable->klass->has_finalize))
3818 mono_object_register_finalizer (o);
3820 if (G_UNLIKELY (profile_allocs))
3821 mono_profiler_allocation (o, vtable->klass);
3826 mono_object_new_fast (MonoVTable *vtable)
3829 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3834 mono_object_new_ptrfree (MonoVTable *vtable)
3837 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3838 #if NEED_TO_ZERO_PTRFREE
3839 /* an inline memset is much faster for the common vcase of small objects
3840 * note we assume the allocated size is a multiple of sizeof (void*).
3842 if (vtable->klass->instance_size < 128) {
3844 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3845 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3851 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3858 mono_object_new_ptrfree_box (MonoVTable *vtable)
3861 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3862 /* the object will be boxed right away, no need to memzero it */
3867 * mono_class_get_allocation_ftn:
3869 * @for_box: the object will be used for boxing
3870 * @pass_size_in_words:
3872 * Return the allocation function appropriate for the given class.
3876 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3878 *pass_size_in_words = FALSE;
3880 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3881 profile_allocs = FALSE;
3883 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3884 return mono_object_new_specific;
3886 if (!vtable->klass->has_references) {
3887 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3889 return mono_object_new_ptrfree_box;
3890 return mono_object_new_ptrfree;
3893 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3895 return mono_object_new_fast;
3898 * FIXME: This is actually slower than mono_object_new_fast, because
3899 * of the overhead of parameter passing.
3902 *pass_size_in_words = TRUE;
3903 #ifdef GC_REDIRECT_TO_LOCAL
3904 return GC_local_gcj_fast_malloc;
3906 return GC_gcj_fast_malloc;
3911 return mono_object_new_specific;
3915 * mono_object_new_from_token:
3916 * @image: Context where the type_token is hosted
3917 * @token: a token of the type that we want to create
3919 * Returns: A newly created object whose definition is
3920 * looked up using @token in the @image image
3923 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3927 class = mono_class_get (image, token);
3929 return mono_object_new (domain, class);
3934 * mono_object_clone:
3935 * @obj: the object to clone
3937 * Returns: A newly created object who is a shallow copy of @obj
3940 mono_object_clone (MonoObject *obj)
3945 size = obj->vtable->klass->instance_size;
3946 o = mono_object_allocate (size, obj->vtable);
3947 /* do not copy the sync state */
3948 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3951 if (obj->vtable->klass->has_references)
3952 mono_gc_wbarrier_object (o);
3954 if (G_UNLIKELY (profile_allocs))
3955 mono_profiler_allocation (o, obj->vtable->klass);
3957 if (obj->vtable->klass->has_finalize)
3958 mono_object_register_finalizer (o);
3963 * mono_array_full_copy:
3964 * @src: source array to copy
3965 * @dest: destination array
3967 * Copies the content of one array to another with exactly the same type and size.
3970 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3972 mono_array_size_t size;
3973 MonoClass *klass = src->obj.vtable->klass;
3975 MONO_ARCH_SAVE_REGS;
3977 g_assert (klass == dest->obj.vtable->klass);
3979 size = mono_array_length (src);
3980 g_assert (size == mono_array_length (dest));
3981 size *= mono_array_element_size (klass);
3983 if (klass->element_class->valuetype) {
3984 if (klass->element_class->has_references)
3985 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
3987 memcpy (&dest->vector, &src->vector, size);
3989 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3992 memcpy (&dest->vector, &src->vector, size);
3997 * mono_array_clone_in_domain:
3998 * @domain: the domain in which the array will be cloned into
3999 * @array: the array to clone
4001 * This routine returns a copy of the array that is hosted on the
4002 * specified MonoDomain.
4005 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4008 mono_array_size_t size, i;
4009 mono_array_size_t *sizes;
4010 MonoClass *klass = array->obj.vtable->klass;
4012 MONO_ARCH_SAVE_REGS;
4014 if (array->bounds == NULL) {
4015 size = mono_array_length (array);
4016 o = mono_array_new_full (domain, klass, &size, NULL);
4018 size *= mono_array_element_size (klass);
4020 if (klass->element_class->valuetype) {
4021 if (klass->element_class->has_references)
4022 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4024 memcpy (&o->vector, &array->vector, size);
4026 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4029 memcpy (&o->vector, &array->vector, size);
4034 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4035 size = mono_array_element_size (klass);
4036 for (i = 0; i < klass->rank; ++i) {
4037 sizes [i] = array->bounds [i].length;
4038 size *= array->bounds [i].length;
4039 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4041 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4043 if (klass->element_class->valuetype) {
4044 if (klass->element_class->has_references)
4045 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4047 memcpy (&o->vector, &array->vector, size);
4049 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4052 memcpy (&o->vector, &array->vector, size);
4060 * @array: the array to clone
4062 * Returns: A newly created array who is a shallow copy of @array
4065 mono_array_clone (MonoArray *array)
4067 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4070 /* helper macros to check for overflow when calculating the size of arrays */
4071 #ifdef MONO_BIG_ARRAYS
4072 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4073 #define MYGUINT_MAX MYGUINT64_MAX
4074 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4075 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4076 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4077 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4078 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4080 #define MYGUINT32_MAX 4294967295U
4081 #define MYGUINT_MAX MYGUINT32_MAX
4082 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4083 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4084 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4085 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4086 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4090 * mono_array_new_full:
4091 * @domain: domain where the object is created
4092 * @array_class: array class
4093 * @lengths: lengths for each dimension in the array
4094 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4096 * This routine creates a new array objects with the given dimensions,
4097 * lower bounds and type.
4100 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4102 mono_array_size_t byte_len, len, bounds_size;
4108 if (!array_class->inited)
4109 mono_class_init (array_class);
4111 byte_len = mono_array_element_size (array_class);
4114 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4115 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4117 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4121 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4123 for (i = 0; i < array_class->rank; ++i) {
4124 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4126 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4127 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4132 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4133 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4135 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4136 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4137 byte_len += sizeof (MonoArray);
4140 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4141 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4142 byte_len = (byte_len + 3) & ~3;
4143 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4144 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4145 byte_len += bounds_size;
4148 * Following three lines almost taken from mono_object_new ():
4149 * they need to be kept in sync.
4151 vtable = mono_class_vtable (domain, array_class);
4152 if (!array_class->has_references) {
4153 o = mono_object_allocate_ptrfree (byte_len, vtable);
4154 #if NEED_TO_ZERO_PTRFREE
4155 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4157 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4158 o = mono_object_allocate_spec (byte_len, vtable);
4160 o = mono_object_allocate (byte_len, vtable);
4163 array = (MonoArray*)o;
4164 array->max_length = len;
4167 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4168 array->bounds = bounds;
4169 for (i = 0; i < array_class->rank; ++i) {
4170 bounds [i].length = lengths [i];
4172 bounds [i].lower_bound = lower_bounds [i];
4176 if (G_UNLIKELY (profile_allocs))
4177 mono_profiler_allocation (o, array_class);
4184 * @domain: domain where the object is created
4185 * @eclass: element class
4186 * @n: number of array elements
4188 * This routine creates a new szarray with @n elements of type @eclass.
4191 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4195 MONO_ARCH_SAVE_REGS;
4197 ac = mono_array_class_get (eclass, 1);
4200 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4204 * mono_array_new_specific:
4205 * @vtable: a vtable in the appropriate domain for an initialized class
4206 * @n: number of array elements
4208 * This routine is a fast alternative to mono_array_new() for code which
4209 * can be sure about the domain it operates in.
4212 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4216 guint32 byte_len, elem_size;
4218 MONO_ARCH_SAVE_REGS;
4220 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4225 elem_size = mono_array_element_size (vtable->klass);
4226 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4227 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4230 byte_len = n * elem_size;
4231 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4232 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4235 byte_len += sizeof (MonoArray);
4236 if (!vtable->klass->has_references) {
4237 o = mono_object_allocate_ptrfree (byte_len, vtable);
4238 #if NEED_TO_ZERO_PTRFREE
4239 ((MonoArray*)o)->bounds = NULL;
4240 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4242 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4243 o = mono_object_allocate_spec (byte_len, vtable);
4245 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4246 o = mono_object_allocate (byte_len, vtable);
4249 ao = (MonoArray *)o;
4251 if (G_UNLIKELY (profile_allocs))
4252 mono_profiler_allocation (o, vtable->klass);
4258 * mono_string_new_utf16:
4259 * @text: a pointer to an utf16 string
4260 * @len: the length of the string
4262 * Returns: A newly created string object which contains @text.
4265 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4269 s = mono_string_new_size (domain, len);
4270 g_assert (s != NULL);
4272 memcpy (mono_string_chars (s), text, len * 2);
4278 * mono_string_new_size:
4279 * @text: a pointer to an utf16 string
4280 * @len: the length of the string
4282 * Returns: A newly created string object of @len
4285 mono_string_new_size (MonoDomain *domain, gint32 len)
4289 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4291 /* overflow ? can't fit it, can't allocate it! */
4293 mono_gc_out_of_memory (-1);
4295 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4297 s = mono_object_allocate_ptrfree (size, vtable);
4300 #if NEED_TO_ZERO_PTRFREE
4303 if (G_UNLIKELY (profile_allocs))
4304 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4310 * mono_string_new_len:
4311 * @text: a pointer to an utf8 string
4312 * @length: number of bytes in @text to consider
4314 * Returns: A newly created string object which contains @text.
4317 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4319 GError *error = NULL;
4320 MonoString *o = NULL;
4322 glong items_written;
4324 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4327 o = mono_string_new_utf16 (domain, ut, items_written);
4329 g_error_free (error);
4338 * @text: a pointer to an utf8 string
4340 * Returns: A newly created string object which contains @text.
4343 mono_string_new (MonoDomain *domain, const char *text)
4345 GError *error = NULL;
4346 MonoString *o = NULL;
4348 glong items_written;
4353 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4356 o = mono_string_new_utf16 (domain, ut, items_written);
4358 g_error_free (error);
4361 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4366 MonoString *o = NULL;
4368 if (!g_utf8_validate (text, -1, &end))
4371 len = g_utf8_strlen (text, -1);
4372 o = mono_string_new_size (domain, len);
4373 str = mono_string_chars (o);
4375 while (text < end) {
4376 *str++ = g_utf8_get_char (text);
4377 text = g_utf8_next_char (text);
4384 * mono_string_new_wrapper:
4385 * @text: pointer to utf8 characters.
4387 * Helper function to create a string object from @text in the current domain.
4390 mono_string_new_wrapper (const char *text)
4392 MonoDomain *domain = mono_domain_get ();
4394 MONO_ARCH_SAVE_REGS;
4397 return mono_string_new (domain, text);
4404 * @class: the class of the value
4405 * @value: a pointer to the unboxed data
4407 * Returns: A newly created object which contains @value.
4410 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4416 g_assert (class->valuetype);
4417 if (mono_class_is_nullable (class))
4418 return mono_nullable_box (value, class);
4420 vtable = mono_class_vtable (domain, class);
4421 size = mono_class_instance_size (class);
4422 res = mono_object_new_alloc_specific (vtable);
4423 if (G_UNLIKELY (profile_allocs))
4424 mono_profiler_allocation (res, class);
4426 size = size - sizeof (MonoObject);
4429 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4432 #if NO_UNALIGNED_ACCESS
4433 memcpy ((char *)res + sizeof (MonoObject), value, size);
4437 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4440 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4443 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4446 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4449 memcpy ((char *)res + sizeof (MonoObject), value, size);
4452 if (class->has_finalize)
4453 mono_object_register_finalizer (res);
4459 * @dest: destination pointer
4460 * @src: source pointer
4461 * @klass: a valuetype class
4463 * Copy a valuetype from @src to @dest. This function must be used
4464 * when @klass contains references fields.
4467 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4469 int size = mono_class_value_size (klass, NULL);
4470 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4471 memcpy (dest, src, size);
4475 * mono_value_copy_array:
4476 * @dest: destination array
4477 * @dest_idx: index in the @dest array
4478 * @src: source pointer
4479 * @count: number of items
4481 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4482 * This function must be used when @klass contains references fields.
4483 * Overlap is handled.
4486 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4488 int size = mono_array_element_size (dest->obj.vtable->klass);
4489 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4490 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4491 memmove (d, src, size * count);
4495 * mono_object_get_domain:
4496 * @obj: object to query
4498 * Returns: the MonoDomain where the object is hosted
4501 mono_object_get_domain (MonoObject *obj)
4503 return mono_object_domain (obj);
4507 * mono_object_get_class:
4508 * @obj: object to query
4510 * Returns: the MonOClass of the object.
4513 mono_object_get_class (MonoObject *obj)
4515 return mono_object_class (obj);
4518 * mono_object_get_size:
4519 * @o: object to query
4521 * Returns: the size, in bytes, of @o
4524 mono_object_get_size (MonoObject* o)
4526 MonoClass* klass = mono_object_class (o);
4527 if (klass == mono_defaults.string_class) {
4528 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4529 } else if (o->vtable->rank) {
4530 MonoArray *array = (MonoArray*)o;
4531 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4532 if (array->bounds) {
4535 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4539 return mono_class_instance_size (klass);
4544 * mono_object_unbox:
4545 * @obj: object to unbox
4547 * Returns: a pointer to the start of the valuetype boxed in this
4550 * This method will assert if the object passed is not a valuetype.
4553 mono_object_unbox (MonoObject *obj)
4555 /* add assert for valuetypes? */
4556 g_assert (obj->vtable->klass->valuetype);
4557 return ((char*)obj) + sizeof (MonoObject);
4561 * mono_object_isinst:
4563 * @klass: a pointer to a class
4565 * Returns: @obj if @obj is derived from @klass
4568 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4571 mono_class_init (klass);
4573 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4574 return mono_object_isinst_mbyref (obj, klass);
4579 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4583 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4592 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4593 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4597 MonoClass *oklass = vt->klass;
4598 if ((oklass == mono_defaults.transparent_proxy_class))
4599 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4601 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4605 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4607 MonoDomain *domain = mono_domain_get ();
4609 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4610 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4611 MonoMethod *im = NULL;
4614 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4615 im = mono_object_get_virtual_method (rp, im);
4618 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4621 res = mono_runtime_invoke (im, rp, pa, NULL);
4623 if (*(MonoBoolean *) mono_object_unbox(res)) {
4624 /* Update the vtable of the remote type, so it can safely cast to this new type */
4625 mono_upgrade_remote_class (domain, obj, klass);
4634 * mono_object_castclass_mbyref:
4636 * @klass: a pointer to a class
4638 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4641 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4643 if (!obj) return NULL;
4644 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4646 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4648 "InvalidCastException"));
4653 MonoDomain *orig_domain;
4659 str_lookup (MonoDomain *domain, gpointer user_data)
4661 LDStrInfo *info = user_data;
4662 if (info->res || domain == info->orig_domain)
4664 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4670 mono_string_get_pinned (MonoString *str)
4674 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4675 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4676 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4677 news->length = mono_string_length (str);
4682 #define mono_string_get_pinned(str) (str)
4686 mono_string_is_interned_lookup (MonoString *str, int insert)
4688 MonoGHashTable *ldstr_table;
4692 domain = ((MonoObject *)str)->vtable->domain;
4693 ldstr_table = domain->ldstr_table;
4695 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4700 str = mono_string_get_pinned (str);
4701 mono_g_hash_table_insert (ldstr_table, str, str);
4705 LDStrInfo ldstr_info;
4706 ldstr_info.orig_domain = domain;
4707 ldstr_info.ins = str;
4708 ldstr_info.res = NULL;
4710 mono_domain_foreach (str_lookup, &ldstr_info);
4711 if (ldstr_info.res) {
4713 * the string was already interned in some other domain:
4714 * intern it in the current one as well.
4716 mono_g_hash_table_insert (ldstr_table, str, str);
4726 * mono_string_is_interned:
4727 * @o: String to probe
4729 * Returns whether the string has been interned.
4732 mono_string_is_interned (MonoString *o)
4734 return mono_string_is_interned_lookup (o, FALSE);
4738 * mono_string_intern:
4739 * @o: String to intern
4741 * Interns the string passed.
4742 * Returns: The interned string.
4745 mono_string_intern (MonoString *str)
4747 return mono_string_is_interned_lookup (str, TRUE);
4752 * @domain: the domain where the string will be used.
4753 * @image: a metadata context
4754 * @idx: index into the user string table.
4756 * Implementation for the ldstr opcode.
4757 * Returns: a loaded string from the @image/@idx combination.
4760 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4762 MONO_ARCH_SAVE_REGS;
4765 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4767 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4771 * mono_ldstr_metadata_sig
4772 * @domain: the domain for the string
4773 * @sig: the signature of a metadata string
4775 * Returns: a MonoString for a string stored in the metadata
4778 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4780 const char *str = sig;
4781 MonoString *o, *interned;
4784 len2 = mono_metadata_decode_blob_size (str, &str);
4787 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4788 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4791 guint16 *p2 = (guint16*)mono_string_chars (o);
4792 for (i = 0; i < len2; ++i) {
4793 *p2 = GUINT16_FROM_LE (*p2);
4799 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4801 /* o will get garbage collected */
4805 o = mono_string_get_pinned (o);
4806 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4813 * mono_string_to_utf8:
4814 * @s: a System.String
4816 * Return the UTF8 representation for @s.
4817 * the resulting buffer nedds to be freed with g_free().
4820 mono_string_to_utf8 (MonoString *s)
4824 GError *error = NULL;
4830 return g_strdup ("");
4832 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4834 MonoException *exc = mono_get_exception_argument ("string", error->message);
4835 g_error_free (error);
4836 mono_raise_exception(exc);
4838 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4839 if (s->length > written) {
4840 /* allocate the total length and copy the part of the string that has been converted */
4841 char *as2 = g_malloc0 (s->length);
4842 memcpy (as2, as, written);
4851 * mono_string_to_utf16:
4854 * Return an null-terminated array of the utf-16 chars
4855 * contained in @s. The result must be freed with g_free().
4856 * This is a temporary helper until our string implementation
4857 * is reworked to always include the null terminating char.
4860 mono_string_to_utf16 (MonoString *s)
4867 as = g_malloc ((s->length * 2) + 2);
4868 as [(s->length * 2)] = '\0';
4869 as [(s->length * 2) + 1] = '\0';
4872 return (gunichar2 *)(as);
4875 memcpy (as, mono_string_chars(s), s->length * 2);
4876 return (gunichar2 *)(as);
4880 * mono_string_from_utf16:
4881 * @data: the UTF16 string (LPWSTR) to convert
4883 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4885 * Returns: a MonoString.
4888 mono_string_from_utf16 (gunichar2 *data)
4890 MonoDomain *domain = mono_domain_get ();
4896 while (data [len]) len++;
4898 return mono_string_new_utf16 (domain, data, len);
4903 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4910 return mono_string_to_utf8 (s);
4912 r = mono_string_to_utf8 (s);
4916 len = strlen (r) + 1;
4918 mp_s = mono_mempool_alloc (mp, len);
4920 mp_s = mono_image_alloc (image, len);
4922 memcpy (mp_s, r, len);
4930 * mono_string_to_utf8_image:
4931 * @s: a System.String
4933 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4936 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4938 return mono_string_to_utf8_internal (NULL, image, s);
4942 * mono_string_to_utf8_mp:
4943 * @s: a System.String
4945 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4948 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4950 return mono_string_to_utf8_internal (mp, NULL, s);
4954 default_ex_handler (MonoException *ex)
4956 MonoObject *o = (MonoObject*)ex;
4957 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4961 static MonoExceptionFunc ex_handler = default_ex_handler;
4964 * mono_install_handler:
4965 * @func: exception handler
4967 * This is an internal JIT routine used to install the handler for exceptions
4971 mono_install_handler (MonoExceptionFunc func)
4973 ex_handler = func? func: default_ex_handler;
4977 * mono_raise_exception:
4978 * @ex: exception object
4980 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4983 mono_raise_exception (MonoException *ex)
4986 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4987 * that will cause gcc to omit the function epilog, causing problems when
4988 * the JIT tries to walk the stack, since the return address on the stack
4989 * will point into the next function in the executable, not this one.
4992 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
4993 MonoThread *thread = mono_thread_current ();
4994 g_assert (ex->object.vtable->domain == mono_domain_get ());
4995 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5002 * mono_wait_handle_new:
5003 * @domain: Domain where the object will be created
5004 * @handle: Handle for the wait handle
5006 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5009 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5011 MonoWaitHandle *res;
5012 gpointer params [1];
5013 static MonoMethod *handle_set;
5015 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
5017 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5019 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
5021 params [0] = &handle;
5022 mono_runtime_invoke (handle_set, res, params, NULL);
5028 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5030 static MonoClassField *f_os_handle;
5031 static MonoClassField *f_safe_handle;
5033 if (!f_os_handle && !f_safe_handle) {
5034 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
5035 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
5040 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5044 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5051 mono_runtime_capture_context (MonoDomain *domain)
5053 RuntimeInvokeFunction runtime_invoke;
5055 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5056 MonoMethod *method = mono_get_context_capture_method ();
5057 MonoMethod *wrapper;
5060 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5061 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5062 domain->capture_context_method = mono_compile_method (method);
5065 runtime_invoke = domain->capture_context_runtime_invoke;
5067 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5070 * mono_async_result_new:
5071 * @domain:domain where the object will be created.
5072 * @handle: wait handle.
5073 * @state: state to pass to AsyncResult
5074 * @data: C closure data.
5076 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5077 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5081 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5083 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5084 MonoObject *context = mono_runtime_capture_context (domain);
5085 /* we must capture the execution context from the original thread */
5087 MONO_OBJECT_SETREF (res, execution_context, context);
5088 /* note: result may be null if the flow is suppressed */
5092 MONO_OBJECT_SETREF (res, object_data, object_data);
5093 MONO_OBJECT_SETREF (res, async_state, state);
5095 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5097 res->sync_completed = FALSE;
5098 res->completed = FALSE;
5104 mono_message_init (MonoDomain *domain,
5105 MonoMethodMessage *this,
5106 MonoReflectionMethod *method,
5107 MonoArray *out_args)
5109 static MonoClass *object_array_klass;
5110 static MonoClass *byte_array_klass;
5111 static MonoClass *string_array_klass;
5112 MonoMethodSignature *sig = mono_method_signature (method->method);
5118 if (!object_array_klass) {
5121 klass = mono_array_class_get (mono_defaults.object_class, 1);
5124 mono_memory_barrier ();
5125 object_array_klass = klass;
5127 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5130 mono_memory_barrier ();
5131 byte_array_klass = klass;
5133 klass = mono_array_class_get (mono_defaults.string_class, 1);
5136 mono_memory_barrier ();
5137 string_array_klass = klass;
5140 MONO_OBJECT_SETREF (this, method, method);
5142 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5143 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5144 this->async_result = NULL;
5145 this->call_type = CallType_Sync;
5147 names = g_new (char *, sig->param_count);
5148 mono_method_get_param_names (method->method, (const char **) names);
5149 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5151 for (i = 0; i < sig->param_count; i++) {
5152 name = mono_string_new (domain, names [i]);
5153 mono_array_setref (this->names, i, name);
5157 for (i = 0, j = 0; i < sig->param_count; i++) {
5158 if (sig->params [i]->byref) {
5160 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5161 mono_array_setref (this->args, i, arg);
5165 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5169 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5172 mono_array_set (this->arg_types, guint8, i, arg_type);
5177 * mono_remoting_invoke:
5178 * @real_proxy: pointer to a RealProxy object
5179 * @msg: The MonoMethodMessage to execute
5180 * @exc: used to store exceptions
5181 * @out_args: used to store output arguments
5183 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5184 * IMessage interface and it is not trivial to extract results from there. So
5185 * we call an helper method PrivateInvoke instead of calling
5186 * RealProxy::Invoke() directly.
5188 * Returns: the result object.
5191 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5192 MonoObject **exc, MonoArray **out_args)
5194 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5197 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5200 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5202 real_proxy->vtable->domain->private_invoke_method = im;
5205 pa [0] = real_proxy;
5210 return mono_runtime_invoke (im, NULL, pa, exc);
5214 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5215 MonoObject **exc, MonoArray **out_args)
5217 static MonoClass *object_array_klass;
5220 MonoMethodSignature *sig;
5222 int i, j, outarg_count = 0;
5224 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5226 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5227 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5228 target = tp->rp->unwrapped_server;
5230 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5234 domain = mono_domain_get ();
5235 method = msg->method->method;
5236 sig = mono_method_signature (method);
5238 for (i = 0; i < sig->param_count; i++) {
5239 if (sig->params [i]->byref)
5243 if (!object_array_klass) {
5246 klass = mono_array_class_get (mono_defaults.object_class, 1);
5249 mono_memory_barrier ();
5250 object_array_klass = klass;
5253 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5254 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5257 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5259 for (i = 0, j = 0; i < sig->param_count; i++) {
5260 if (sig->params [i]->byref) {
5262 arg = mono_array_get (msg->args, gpointer, i);
5263 mono_array_setref (*out_args, j, arg);
5272 * mono_print_unhandled_exception:
5273 * @exc: The exception
5275 * Prints the unhandled exception.
5278 mono_print_unhandled_exception (MonoObject *exc)
5280 char *message = (char *) "";
5284 gboolean free_message = FALSE;
5286 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5287 klass = exc->vtable->klass;
5289 while (klass && method == NULL) {
5290 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5292 klass = klass->parent;
5297 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5299 message = mono_string_to_utf8 (str);
5300 free_message = TRUE;
5305 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5306 * exc->vtable->klass->name, message);
5308 g_printerr ("\nUnhandled Exception: %s\n", message);
5315 * mono_delegate_ctor:
5316 * @this: pointer to an uninitialized delegate object
5317 * @target: target object
5318 * @addr: pointer to native code
5321 * Initialize a delegate and sets a specific method, not the one
5322 * associated with addr. This is useful when sharing generic code.
5323 * In that case addr will most probably not be associated with the
5324 * correct instantiation of the method.
5327 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5329 MonoDelegate *delegate = (MonoDelegate *)this;
5336 delegate->method = method;
5338 class = this->vtable->klass;
5339 mono_stats.delegate_creations++;
5341 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5343 method = mono_marshal_get_remoting_invoke (method);
5344 delegate->method_ptr = mono_compile_method (method);
5345 MONO_OBJECT_SETREF (delegate, target, target);
5346 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5347 method = mono_marshal_get_unbox_wrapper (method);
5348 delegate->method_ptr = mono_compile_method (method);
5349 MONO_OBJECT_SETREF (delegate, target, target);
5351 delegate->method_ptr = addr;
5352 MONO_OBJECT_SETREF (delegate, target, target);
5355 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5359 * mono_delegate_ctor:
5360 * @this: pointer to an uninitialized delegate object
5361 * @target: target object
5362 * @addr: pointer to native code
5364 * This is used to initialize a delegate.
5367 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5369 MonoDomain *domain = mono_domain_get ();
5371 MonoMethod *method = NULL;
5375 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5376 method = ji->method;
5377 g_assert (!method->klass->generic_container);
5380 mono_delegate_ctor_with_method (this, target, addr, method);
5384 * mono_method_call_message_new:
5385 * @method: method to encapsulate
5386 * @params: parameters to the method
5387 * @invoke: optional, delegate invoke.
5388 * @cb: async callback delegate.
5389 * @state: state passed to the async callback.
5391 * Translates arguments pointers into a MonoMethodMessage.
5394 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5395 MonoDelegate **cb, MonoObject **state)
5397 MonoDomain *domain = mono_domain_get ();
5398 MonoMethodSignature *sig = mono_method_signature (method);
5399 MonoMethodMessage *msg;
5402 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5405 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5406 count = sig->param_count - 2;
5408 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5409 count = sig->param_count;
5412 for (i = 0; i < count; i++) {
5417 if (sig->params [i]->byref)
5418 vpos = *((gpointer *)params [i]);
5422 type = sig->params [i]->type;
5423 class = mono_class_from_mono_type (sig->params [i]);
5425 if (class->valuetype)
5426 arg = mono_value_box (domain, class, vpos);
5428 arg = *((MonoObject **)vpos);
5430 mono_array_setref (msg->args, i, arg);
5433 if (cb != NULL && state != NULL) {
5434 *cb = *((MonoDelegate **)params [i]);
5436 *state = *((MonoObject **)params [i]);
5443 * mono_method_return_message_restore:
5445 * Restore results from message based processing back to arguments pointers
5448 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5450 MonoMethodSignature *sig = mono_method_signature (method);
5451 int i, j, type, size, out_len;
5453 if (out_args == NULL)
5455 out_len = mono_array_length (out_args);
5459 for (i = 0, j = 0; i < sig->param_count; i++) {
5460 MonoType *pt = sig->params [i];
5465 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5467 arg = mono_array_get (out_args, gpointer, j);
5471 case MONO_TYPE_VOID:
5472 g_assert_not_reached ();
5476 case MONO_TYPE_BOOLEAN:
5479 case MONO_TYPE_CHAR:
5486 case MONO_TYPE_VALUETYPE: {
5488 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5489 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5492 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5493 memset (*((gpointer *)params [i]), 0, size);
5497 case MONO_TYPE_STRING:
5498 case MONO_TYPE_CLASS:
5499 case MONO_TYPE_ARRAY:
5500 case MONO_TYPE_SZARRAY:
5501 case MONO_TYPE_OBJECT:
5502 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5505 g_assert_not_reached ();
5514 * mono_load_remote_field:
5515 * @this: pointer to an object
5516 * @klass: klass of the object containing @field
5517 * @field: the field to load
5518 * @res: a storage to store the result
5520 * This method is called by the runtime on attempts to load fields of
5521 * transparent proxy objects. @this points to such TP, @klass is the class of
5522 * the object containing @field. @res is a storage location which can be
5523 * used to store the result.
5525 * Returns: an address pointing to the value of field.
5528 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5530 static MonoMethod *getter = NULL;
5531 MonoDomain *domain = mono_domain_get ();
5532 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5533 MonoClass *field_class;
5534 MonoMethodMessage *msg;
5535 MonoArray *out_args;
5539 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5540 g_assert (res != NULL);
5542 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5543 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5548 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5552 field_class = mono_class_from_mono_type (field->type);
5554 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5555 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5556 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5558 full_name = mono_type_get_full_name (klass);
5559 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5560 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5563 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5565 if (exc) mono_raise_exception ((MonoException *)exc);
5567 if (mono_array_length (out_args) == 0)
5570 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5572 if (field_class->valuetype) {
5573 return ((char *)*res) + sizeof (MonoObject);
5579 * mono_load_remote_field_new:
5584 * Missing documentation.
5587 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5589 static MonoMethod *getter = NULL;
5590 MonoDomain *domain = mono_domain_get ();
5591 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5592 MonoClass *field_class;
5593 MonoMethodMessage *msg;
5594 MonoArray *out_args;
5595 MonoObject *exc, *res;
5598 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5600 field_class = mono_class_from_mono_type (field->type);
5602 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5604 if (field_class->valuetype) {
5605 res = mono_object_new (domain, field_class);
5606 val = ((gchar *) res) + sizeof (MonoObject);
5610 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5615 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5619 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5620 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5622 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5624 full_name = mono_type_get_full_name (klass);
5625 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5626 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5629 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5631 if (exc) mono_raise_exception ((MonoException *)exc);
5633 if (mono_array_length (out_args) == 0)
5636 res = mono_array_get (out_args, MonoObject *, 0);
5642 * mono_store_remote_field:
5643 * @this: pointer to an object
5644 * @klass: klass of the object containing @field
5645 * @field: the field to load
5646 * @val: the value/object to store
5648 * This method is called by the runtime on attempts to store fields of
5649 * transparent proxy objects. @this points to such TP, @klass is the class of
5650 * the object containing @field. @val is the new value to store in @field.
5653 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5655 static MonoMethod *setter = NULL;
5656 MonoDomain *domain = mono_domain_get ();
5657 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5658 MonoClass *field_class;
5659 MonoMethodMessage *msg;
5660 MonoArray *out_args;
5665 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5667 field_class = mono_class_from_mono_type (field->type);
5669 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5670 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5671 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5676 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5680 if (field_class->valuetype)
5681 arg = mono_value_box (domain, field_class, val);
5683 arg = *((MonoObject **)val);
5686 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5687 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5689 full_name = mono_type_get_full_name (klass);
5690 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5691 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5692 mono_array_setref (msg->args, 2, arg);
5695 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5697 if (exc) mono_raise_exception ((MonoException *)exc);
5701 * mono_store_remote_field_new:
5707 * Missing documentation
5710 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5712 static MonoMethod *setter = NULL;
5713 MonoDomain *domain = mono_domain_get ();
5714 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5715 MonoClass *field_class;
5716 MonoMethodMessage *msg;
5717 MonoArray *out_args;
5721 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5723 field_class = mono_class_from_mono_type (field->type);
5725 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5726 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5727 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5732 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5736 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5737 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5739 full_name = mono_type_get_full_name (klass);
5740 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5741 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5742 mono_array_setref (msg->args, 2, arg);
5745 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5747 if (exc) mono_raise_exception ((MonoException *)exc);
5751 * mono_create_ftnptr:
5753 * Given a function address, create a function descriptor for it.
5754 * This is only needed on some platforms.
5757 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5759 return callbacks.create_ftnptr (domain, addr);
5763 * mono_get_addr_from_ftnptr:
5765 * Given a pointer to a function descriptor, return the function address.
5766 * This is only needed on some platforms.
5769 mono_get_addr_from_ftnptr (gpointer descr)
5771 return callbacks.get_addr_from_ftnptr (descr);
5776 * mono_string_chars:
5779 * Returns a pointer to the UCS16 characters stored in the MonoString
5782 mono_string_chars(MonoString *s)
5784 /* This method is here only for documentation extraction, this is a macro */
5788 * mono_string_length:
5791 * Returns the lenght in characters of the string
5794 mono_string_length (MonoString *s)
5796 /* This method is here only for documentation extraction, this is a macro */