2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include "cominterop.h"
46 #define NEED_TO_ZERO_PTRFREE 1
47 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
48 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
49 #ifdef HAVE_GC_GCJ_MALLOC
50 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
51 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
53 #define GC_NO_DESCRIPTOR (NULL)
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
58 #define GC_NO_DESCRIPTOR (NULL)
59 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
61 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
63 #define NEED_TO_ZERO_PTRFREE 1
64 #define GC_NO_DESCRIPTOR (NULL)
65 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
66 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
67 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
71 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
72 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
75 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
78 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
80 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
81 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
82 static CRITICAL_SECTION ldstr_section;
84 static gboolean profile_allocs = TRUE;
87 mono_runtime_object_init (MonoObject *this)
89 MonoMethod *method = NULL;
90 MonoClass *klass = this->vtable->klass;
92 method = mono_class_get_method_from_name (klass, ".ctor", 0);
95 if (method->klass->valuetype)
96 this = mono_object_unbox (this);
97 mono_runtime_invoke (method, this, NULL, NULL);
100 /* The pseudo algorithm for type initialization from the spec
101 Note it doesn't say anything about domains - only threads.
103 2. If the type is initialized you are done.
104 2.1. If the type is not yet initialized, try to take an
106 2.2. If successful, record this thread as responsible for
107 initializing the type and proceed to step 2.3.
108 2.2.1. If not, see whether this thread or any thread
109 waiting for this thread to complete already holds the lock.
110 2.2.2. If so, return since blocking would create a deadlock. This thread
111 will now see an incompletely initialized state for the type,
112 but no deadlock will arise.
113 2.2.3 If not, block until the type is initialized then return.
114 2.3 Initialize the parent type and then all interfaces implemented
116 2.4 Execute the type initialization code for this type.
117 2.5 Mark the type as initialized, release the initialization lock,
118 awaken any threads waiting for this type to be initialized,
125 guint32 initializing_tid;
126 guint32 waiting_count;
128 CRITICAL_SECTION initialization_section;
129 } TypeInitializationLock;
131 /* for locking access to type_initialization_hash and blocked_thread_hash */
132 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
133 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
134 static CRITICAL_SECTION type_initialization_section;
136 /* from vtable to lock */
137 static GHashTable *type_initialization_hash;
139 /* from thread id to thread id being waited on */
140 static GHashTable *blocked_thread_hash;
143 static MonoThread *main_thread;
145 /* Functions supplied by the runtime */
146 static MonoRuntimeCallbacks callbacks;
149 * mono_thread_set_main:
150 * @thread: thread to set as the main thread
152 * This function can be used to instruct the runtime to treat @thread
153 * as the main thread, ie, the thread that would normally execute the Main()
154 * method. This basically means that at the end of @thread, the runtime will
155 * wait for the existing foreground threads to quit and other such details.
158 mono_thread_set_main (MonoThread *thread)
160 main_thread = thread;
164 mono_thread_get_main (void)
170 mono_type_initialization_init (void)
172 InitializeCriticalSection (&type_initialization_section);
173 type_initialization_hash = g_hash_table_new (NULL, NULL);
174 blocked_thread_hash = g_hash_table_new (NULL, NULL);
175 InitializeCriticalSection (&ldstr_section);
179 mono_type_initialization_cleanup (void)
182 /* This is causing race conditions with
183 * mono_release_type_locks
185 DeleteCriticalSection (&type_initialization_section);
187 DeleteCriticalSection (&ldstr_section);
191 * get_type_init_exception_for_vtable:
193 * Return the stored type initialization exception for VTABLE.
195 static MonoException*
196 get_type_init_exception_for_vtable (MonoVTable *vtable)
198 MonoDomain *domain = vtable->domain;
199 MonoClass *klass = vtable->klass;
203 g_assert (vtable->init_failed);
206 * If the initializing thread was rudely aborted, the exception is not stored
210 mono_domain_lock (domain);
211 if (domain->type_init_exception_hash)
212 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
213 mono_domain_unlock (domain);
216 if (klass->name_space && *klass->name_space)
217 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
219 full_name = g_strdup (klass->name);
220 ex = mono_get_exception_type_initialization (full_name, NULL);
227 * mono_runtime_class_init:
228 * @vtable: vtable that needs to be initialized
230 * This routine calls the class constructor for @vtable.
233 mono_runtime_class_init (MonoVTable *vtable)
235 mono_runtime_class_init_full (vtable, TRUE);
239 * mono_runtime_class_init_full:
240 * @vtable that neeeds to be initialized
241 * @raise_exception is TRUE, exceptions are raised intead of returned
245 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
248 MonoException *exc_to_throw;
249 MonoMethod *method = NULL;
255 if (vtable->initialized)
259 klass = vtable->klass;
261 if (!klass->image->checked_module_cctor) {
262 mono_image_check_for_module_cctor (klass->image);
263 if (klass->image->has_module_cctor) {
264 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
265 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
268 method = mono_class_get_cctor (klass);
271 MonoDomain *domain = vtable->domain;
272 TypeInitializationLock *lock;
273 guint32 tid = GetCurrentThreadId();
274 int do_initialization = 0;
275 MonoDomain *last_domain = NULL;
277 mono_type_initialization_lock ();
278 /* double check... */
279 if (vtable->initialized) {
280 mono_type_initialization_unlock ();
283 if (vtable->init_failed) {
284 mono_type_initialization_unlock ();
286 /* The type initialization already failed once, rethrow the same exception */
288 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
289 return get_type_init_exception_for_vtable (vtable);
291 lock = g_hash_table_lookup (type_initialization_hash, vtable);
293 /* This thread will get to do the initialization */
294 if (mono_domain_get () != domain) {
295 /* Transfer into the target domain */
296 last_domain = mono_domain_get ();
297 if (!mono_domain_set (domain, FALSE)) {
298 vtable->initialized = 1;
299 mono_type_initialization_unlock ();
301 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
302 return mono_get_exception_appdomain_unloaded ();
305 lock = g_malloc (sizeof(TypeInitializationLock));
306 InitializeCriticalSection (&lock->initialization_section);
307 lock->initializing_tid = tid;
308 lock->waiting_count = 1;
310 /* grab the vtable lock while this thread still owns type_initialization_section */
311 EnterCriticalSection (&lock->initialization_section);
312 g_hash_table_insert (type_initialization_hash, vtable, lock);
313 do_initialization = 1;
316 TypeInitializationLock *pending_lock;
318 if (lock->initializing_tid == tid || lock->done) {
319 mono_type_initialization_unlock ();
322 /* see if the thread doing the initialization is already blocked on this thread */
323 blocked = GUINT_TO_POINTER (lock->initializing_tid);
324 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
325 if (pending_lock->initializing_tid == tid) {
326 if (!pending_lock->done) {
327 mono_type_initialization_unlock ();
330 /* the thread doing the initialization is blocked on this thread,
331 but on a lock that has already been freed. It just hasn't got
336 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
338 ++lock->waiting_count;
339 /* record the fact that we are waiting on the initializing thread */
340 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
342 mono_type_initialization_unlock ();
344 if (do_initialization) {
345 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
347 /* If the initialization failed, mark the class as unusable. */
348 /* Avoid infinite loops */
350 (klass->image == mono_defaults.corlib &&
351 !strcmp (klass->name_space, "System") &&
352 !strcmp (klass->name, "TypeInitializationException")))) {
353 vtable->init_failed = 1;
355 if (klass->name_space && *klass->name_space)
356 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
358 full_name = g_strdup (klass->name);
359 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
363 * Store the exception object so it could be thrown on subsequent
366 mono_domain_lock (domain);
367 if (!domain->type_init_exception_hash)
368 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
369 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
370 mono_domain_unlock (domain);
374 mono_domain_set (last_domain, TRUE);
376 LeaveCriticalSection (&lock->initialization_section);
378 /* this just blocks until the initializing thread is done */
379 EnterCriticalSection (&lock->initialization_section);
380 LeaveCriticalSection (&lock->initialization_section);
383 mono_type_initialization_lock ();
384 if (lock->initializing_tid != tid)
385 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
386 --lock->waiting_count;
387 if (lock->waiting_count == 0) {
388 DeleteCriticalSection (&lock->initialization_section);
389 g_hash_table_remove (type_initialization_hash, vtable);
392 if (!vtable->init_failed)
393 vtable->initialized = 1;
394 mono_type_initialization_unlock ();
396 if (vtable->init_failed) {
397 /* Either we were the initializing thread or we waited for the initialization */
399 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
400 return get_type_init_exception_for_vtable (vtable);
403 vtable->initialized = 1;
410 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
412 MonoVTable *vtable = (MonoVTable*)key;
414 TypeInitializationLock *lock = (TypeInitializationLock*) value;
415 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
418 * Have to set this since it cannot be set by the normal code in
419 * mono_runtime_class_init (). In this case, the exception object is not stored,
420 * and get_type_init_exception_for_class () needs to be aware of this.
422 vtable->init_failed = 1;
423 LeaveCriticalSection (&lock->initialization_section);
424 --lock->waiting_count;
425 if (lock->waiting_count == 0) {
426 DeleteCriticalSection (&lock->initialization_section);
435 mono_release_type_locks (MonoThread *thread)
437 mono_type_initialization_lock ();
438 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
439 mono_type_initialization_unlock ();
443 default_trampoline (MonoMethod *method)
449 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
451 g_assert_not_reached ();
457 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
459 g_error ("remoting not installed");
464 default_delegate_trampoline (MonoClass *klass)
466 g_assert_not_reached ();
470 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
471 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
472 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
473 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
474 static MonoImtThunkBuilder imt_thunk_builder = NULL;
475 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
476 #if (MONO_IMT_SIZE > 32)
477 #error "MONO_IMT_SIZE cannot be larger than 32"
481 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
483 memcpy (&callbacks, cbs, sizeof (*cbs));
486 MonoRuntimeCallbacks*
487 mono_get_runtime_callbacks (void)
493 mono_install_trampoline (MonoTrampoline func)
495 arch_create_jit_trampoline = func? func: default_trampoline;
499 mono_install_jump_trampoline (MonoJumpTrampoline func)
501 arch_create_jump_trampoline = func? func: default_jump_trampoline;
505 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
507 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
511 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
513 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
517 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
518 imt_thunk_builder = func;
521 static MonoCompileFunc default_mono_compile_method = NULL;
524 * mono_install_compile_method:
525 * @func: function to install
527 * This is a VM internal routine
530 mono_install_compile_method (MonoCompileFunc func)
532 default_mono_compile_method = func;
536 * mono_compile_method:
537 * @method: The method to compile.
539 * This JIT-compiles the method, and returns the pointer to the native code
543 mono_compile_method (MonoMethod *method)
545 if (!default_mono_compile_method) {
546 g_error ("compile method called on uninitialized runtime");
549 return default_mono_compile_method (method);
553 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
555 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
559 mono_runtime_create_delegate_trampoline (MonoClass *klass)
561 return arch_create_delegate_trampoline (klass);
564 static MonoFreeMethodFunc default_mono_free_method = NULL;
567 * mono_install_free_method:
568 * @func: pointer to the MonoFreeMethodFunc used to release a method
570 * This is an internal VM routine, it is used for the engines to
571 * register a handler to release the resources associated with a method.
573 * Methods are freed when no more references to the delegate that holds
577 mono_install_free_method (MonoFreeMethodFunc func)
579 default_mono_free_method = func;
583 * mono_runtime_free_method:
584 * @domain; domain where the method is hosted
585 * @method: method to release
587 * This routine is invoked to free the resources associated with
588 * a method that has been JIT compiled. This is used to discard
589 * methods that were used only temporarily (for example, used in marshalling)
593 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
595 if (default_mono_free_method != NULL)
596 default_mono_free_method (domain, method);
598 mono_method_clear_object (domain, method);
600 mono_free_method (method);
604 * The vtables in the root appdomain are assumed to be reachable by other
605 * roots, and we don't use typed allocation in the other domains.
608 /* The sync block is no longer a GC pointer */
609 #define GC_HEADER_BITMAP (0)
611 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
614 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
616 MonoClassField *field;
622 max_size = mono_class_data_size (class) / sizeof (gpointer);
624 max_size = class->instance_size / sizeof (gpointer);
625 if (max_size >= size) {
626 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
629 for (p = class; p != NULL; p = p->parent) {
630 gpointer iter = NULL;
631 while ((field = mono_class_get_fields (p, &iter))) {
635 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
637 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
640 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
643 /* FIXME: should not happen, flag as type load error */
644 if (field->type->byref)
647 if (static_fields && field->offset == -1)
651 pos = field->offset / sizeof (gpointer);
654 type = mono_type_get_underlying_type (field->type);
655 switch (type->type) {
658 case MONO_TYPE_FNPTR:
660 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
665 if (class->image != mono_defaults.corlib)
668 case MONO_TYPE_STRING:
669 case MONO_TYPE_SZARRAY:
670 case MONO_TYPE_CLASS:
671 case MONO_TYPE_OBJECT:
672 case MONO_TYPE_ARRAY:
673 g_assert ((field->offset % sizeof(gpointer)) == 0);
675 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
676 *max_set = MAX (*max_set, pos);
678 case MONO_TYPE_GENERICINST:
679 if (!mono_type_generic_inst_is_valuetype (type)) {
680 g_assert ((field->offset % sizeof(gpointer)) == 0);
682 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
683 *max_set = MAX (*max_set, pos);
688 case MONO_TYPE_VALUETYPE: {
689 MonoClass *fclass = mono_class_from_mono_type (field->type);
690 if (fclass->has_references) {
691 /* remove the object header */
692 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
706 case MONO_TYPE_BOOLEAN:
710 g_assert_not_reached ();
722 * similar to the above, but sets the bits in the bitmap for any non-ref field
723 * and ignores static fields
726 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
728 MonoClassField *field;
733 max_size = class->instance_size / sizeof (gpointer);
734 if (max_size >= size) {
735 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
738 for (p = class; p != NULL; p = p->parent) {
739 gpointer iter = NULL;
740 while ((field = mono_class_get_fields (p, &iter))) {
743 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
745 /* FIXME: should not happen, flag as type load error */
746 if (field->type->byref)
749 pos = field->offset / sizeof (gpointer);
752 type = mono_type_get_underlying_type (field->type);
753 switch (type->type) {
754 #if SIZEOF_VOID_P == 8
758 case MONO_TYPE_FNPTR:
763 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
764 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
765 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
768 #if SIZEOF_VOID_P == 4
772 case MONO_TYPE_FNPTR:
777 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
778 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
779 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
785 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
786 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
787 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
790 case MONO_TYPE_BOOLEAN:
793 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795 case MONO_TYPE_STRING:
796 case MONO_TYPE_SZARRAY:
797 case MONO_TYPE_CLASS:
798 case MONO_TYPE_OBJECT:
799 case MONO_TYPE_ARRAY:
801 case MONO_TYPE_GENERICINST:
802 if (!mono_type_generic_inst_is_valuetype (type)) {
807 case MONO_TYPE_VALUETYPE: {
808 MonoClass *fclass = mono_class_from_mono_type (field->type);
809 /* remove the object header */
810 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
814 g_assert_not_reached ();
823 * mono_class_insecure_overlapping:
824 * check if a class with explicit layout has references and non-references
825 * fields overlapping.
827 * Returns: TRUE if it is insecure to load the type.
830 mono_class_insecure_overlapping (MonoClass *klass)
834 gsize default_bitmap [4] = {0};
836 gsize default_nrbitmap [4] = {0};
837 int i, insecure = FALSE;
840 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
841 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
843 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
844 int idx = i % (sizeof (bitmap [0]) * 8);
845 if (bitmap [idx] & nrbitmap [idx]) {
850 if (bitmap != default_bitmap)
852 if (nrbitmap != default_nrbitmap)
855 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
863 mono_string_alloc (int length)
865 return mono_string_new_size (mono_domain_get (), length);
869 mono_class_compute_gc_descriptor (MonoClass *class)
873 gsize default_bitmap [4] = {0};
874 static gboolean gcj_inited = FALSE;
879 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
880 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
881 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
882 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
884 #ifdef HAVE_GC_GCJ_MALLOC
886 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
890 #ifdef GC_REDIRECT_TO_LOCAL
891 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
892 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
894 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
895 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
900 mono_loader_unlock ();
904 mono_class_init (class);
906 if (class->gc_descr_inited)
909 class->gc_descr_inited = TRUE;
910 class->gc_descr = GC_NO_DESCRIPTOR;
912 bitmap = default_bitmap;
913 if (class == mono_defaults.string_class) {
914 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
915 } else if (class->rank) {
916 mono_class_compute_gc_descriptor (class->element_class);
917 if (!class->element_class->valuetype) {
919 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
920 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
921 class->name_space, class->name);*/
923 /* remove the object header */
924 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
925 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
926 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
927 class->name_space, class->name);*/
928 if (bitmap != default_bitmap)
932 /*static int count = 0;
935 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
936 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
938 if (class->gc_descr == GC_NO_DESCRIPTOR)
939 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
941 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
942 if (bitmap != default_bitmap)
948 * field_is_special_static:
949 * @fklass: The MonoClass to look up.
950 * @field: The MonoClassField describing the field.
952 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
953 * SPECIAL_STATIC_NONE otherwise.
956 field_is_special_static (MonoClass *fklass, MonoClassField *field)
958 MonoCustomAttrInfo *ainfo;
960 ainfo = mono_custom_attrs_from_field (fklass, field);
963 for (i = 0; i < ainfo->num_attrs; ++i) {
964 MonoClass *klass = ainfo->attrs [i].ctor->klass;
965 if (klass->image == mono_defaults.corlib) {
966 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
967 mono_custom_attrs_free (ainfo);
968 return SPECIAL_STATIC_THREAD;
970 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
971 mono_custom_attrs_free (ainfo);
972 return SPECIAL_STATIC_CONTEXT;
976 mono_custom_attrs_free (ainfo);
977 return SPECIAL_STATIC_NONE;
980 static gpointer imt_trampoline = NULL;
983 mono_install_imt_trampoline (gpointer tramp_code)
985 imt_trampoline = tramp_code;
988 static gpointer vtable_trampoline = NULL;
991 mono_install_vtable_trampoline (gpointer tramp_code)
993 vtable_trampoline = tramp_code;
996 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
997 #define mix(a,b,c) { \
998 a -= c; a ^= rot(c, 4); c += b; \
999 b -= a; b ^= rot(a, 6); a += c; \
1000 c -= b; c ^= rot(b, 8); b += a; \
1001 a -= c; a ^= rot(c,16); c += b; \
1002 b -= a; b ^= rot(a,19); a += c; \
1003 c -= b; c ^= rot(b, 4); b += a; \
1005 #define final(a,b,c) { \
1006 c ^= b; c -= rot(b,14); \
1007 a ^= c; a -= rot(c,11); \
1008 b ^= a; b -= rot(a,25); \
1009 c ^= b; c -= rot(b,16); \
1010 a ^= c; a -= rot(c,4); \
1011 b ^= a; b -= rot(a,14); \
1012 c ^= b; c -= rot(b,24); \
1016 mono_method_get_imt_slot (MonoMethod *method)
1018 MonoMethodSignature *sig;
1020 guint32 *hashes_start, *hashes;
1024 /* This can be used to stress tests the collision code */
1028 * We do this to simplify generic sharing. It will hurt
1029 * performance in cases where a class implements two different
1030 * instantiations of the same generic interface.
1031 * The code in build_imt_slots () depends on this.
1033 if (method->is_inflated)
1034 method = ((MonoMethodInflated*)method)->declaring;
1036 sig = mono_method_signature (method);
1037 hashes_count = sig->param_count + 4;
1038 hashes_start = malloc (hashes_count * sizeof (guint32));
1039 hashes = hashes_start;
1041 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1042 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1043 method->klass->name_space, method->klass->name, method->name);
1044 g_assert_not_reached ();
1047 /* Initialize hashes */
1048 hashes [0] = g_str_hash (method->klass->name);
1049 hashes [1] = g_str_hash (method->klass->name_space);
1050 hashes [2] = g_str_hash (method->name);
1051 hashes [3] = mono_metadata_type_hash (sig->ret);
1052 for (i = 0; i < sig->param_count; i++) {
1053 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1056 /* Setup internal state */
1057 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1059 /* Handle most of the hashes */
1060 while (hashes_count > 3) {
1069 /* Handle the last 3 hashes (all the case statements fall through) */
1070 switch (hashes_count) {
1071 case 3 : c += hashes [2];
1072 case 2 : b += hashes [1];
1073 case 1 : a += hashes [0];
1075 case 0: /* nothing left to add */
1079 free (hashes_start);
1080 /* Report the result */
1081 return c % MONO_IMT_SIZE;
1090 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1091 guint32 imt_slot = mono_method_get_imt_slot (method);
1092 MonoImtBuilderEntry *entry;
1094 if (slot_num >= 0 && imt_slot != slot_num) {
1095 /* we build just a single imt slot and this is not it */
1099 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1100 entry->key = method;
1101 entry->value.vtable_slot = vtable_slot;
1102 entry->next = imt_builder [imt_slot];
1103 if (imt_builder [imt_slot] != NULL) {
1104 entry->children = imt_builder [imt_slot]->children + 1;
1105 if (entry->children == 1) {
1106 mono_stats.imt_slots_with_collisions++;
1107 *imt_collisions_bitmap |= (1 << imt_slot);
1110 entry->children = 0;
1111 mono_stats.imt_used_slots++;
1113 imt_builder [imt_slot] = entry;
1115 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1116 method, method->klass->name_space, method->klass->name,
1117 method->name, imt_slot, vtable_slot, entry->children);
1123 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1125 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1129 e->method->klass->name_space,
1130 e->method->klass->name,
1133 printf (" * %s: NULL\n", message);
1139 compare_imt_builder_entries (const void *p1, const void *p2) {
1140 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1141 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1143 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1147 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1149 int count = end - start;
1150 int chunk_start = out_array->len;
1153 for (i = start; i < end; ++i) {
1154 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1155 item->key = sorted_array [i]->key;
1156 item->value = sorted_array [i]->value;
1157 item->has_target_code = sorted_array [i]->has_target_code;
1158 item->is_equals = TRUE;
1160 item->check_target_idx = out_array->len + 1;
1162 item->check_target_idx = 0;
1163 g_ptr_array_add (out_array, item);
1166 int middle = start + count / 2;
1167 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1169 item->key = sorted_array [middle]->key;
1170 item->is_equals = FALSE;
1171 g_ptr_array_add (out_array, item);
1172 imt_emit_ir (sorted_array, start, middle, out_array);
1173 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1179 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1180 int number_of_entries = entries->children + 1;
1181 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1182 GPtrArray *result = g_ptr_array_new ();
1183 MonoImtBuilderEntry *current_entry;
1186 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1187 sorted_array [i] = current_entry;
1189 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1191 /*for (i = 0; i < number_of_entries; i++) {
1192 print_imt_entry (" sorted array:", sorted_array [i], i);
1195 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1197 free (sorted_array);
1202 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1204 if (imt_builder_entry != NULL) {
1205 if (imt_builder_entry->children == 0 && !fail_tramp) {
1206 /* No collision, return the vtable slot contents */
1207 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1209 /* Collision, build the thunk */
1210 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1213 result = imt_thunk_builder (vtable, domain,
1214 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1215 for (i = 0; i < imt_ir->len; ++i)
1216 g_free (g_ptr_array_index (imt_ir, i));
1217 g_ptr_array_free (imt_ir, TRUE);
1229 static MonoImtBuilderEntry*
1230 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1233 * LOCKING: requires the loader and domain locks.
1237 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1241 guint32 imt_collisions_bitmap = 0;
1242 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1243 int method_count = 0;
1244 gboolean record_method_count_for_max_collisions = FALSE;
1245 gboolean has_generic_virtual = FALSE;
1248 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1250 for (i = 0; i < klass->interface_offsets_count; ++i) {
1251 MonoClass *iface = klass->interfaces_packed [i];
1252 int interface_offset = klass->interface_offsets_packed [i];
1253 int method_slot_in_interface;
1254 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1257 if (slot_num >= 0 && iface->is_inflated) {
1259 * The imt slot of the method is the same as for its declaring method,
1260 * see the comment in mono_method_get_imt_slot (), so we can
1261 * avoid inflating methods which will be discarded by
1262 * add_imt_builder_entry anyway.
1264 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1265 if (mono_method_get_imt_slot (method) != slot_num)
1268 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1269 if (method->is_generic) {
1270 has_generic_virtual = TRUE;
1273 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1276 if (extra_interfaces) {
1277 int interface_offset = klass->vtable_size;
1279 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1280 MonoClass* iface = list_item->data;
1281 int method_slot_in_interface;
1282 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1283 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1284 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1286 interface_offset += iface->method.count;
1289 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1290 /* overwrite the imt slot only if we're building all the entries or if
1291 * we're building this specific one
1293 if (slot_num < 0 || i == slot_num) {
1294 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1297 if (imt_builder [i]) {
1298 MonoImtBuilderEntry *entry;
1300 /* Link entries with imt_builder [i] */
1301 for (entry = entries; entry->next; entry = entry->next)
1303 entry->next = imt_builder [i];
1304 entries->children += imt_builder [i]->children + 1;
1306 imt_builder [i] = entries;
1309 if (has_generic_virtual) {
1311 * There might be collisions later when the the thunk is expanded.
1313 imt_collisions_bitmap |= (1 << i);
1316 * The IMT thunk might be called with an instance of one of the
1317 * generic virtual methods, so has to fallback to the IMT trampoline.
1319 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1321 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1325 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1327 if (imt_builder [i] != NULL) {
1328 int methods_in_slot = imt_builder [i]->children + 1;
1329 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1330 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1331 record_method_count_for_max_collisions = TRUE;
1333 method_count += methods_in_slot;
1337 mono_stats.imt_number_of_methods += method_count;
1338 if (record_method_count_for_max_collisions) {
1339 mono_stats.imt_method_count_when_max_collisions = method_count;
1342 for (i = 0; i < MONO_IMT_SIZE; i++) {
1343 MonoImtBuilderEntry* entry = imt_builder [i];
1344 while (entry != NULL) {
1345 MonoImtBuilderEntry* next = entry->next;
1351 /* we OR the bitmap since we may build just a single imt slot at a time */
1352 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1356 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1357 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1361 * mono_vtable_build_imt_slot:
1362 * @vtable: virtual object table struct
1363 * @imt_slot: slot in the IMT table
1365 * Fill the given @imt_slot in the IMT table of @vtable with
1366 * a trampoline or a thunk for the case of collisions.
1367 * This is part of the internal mono API.
1369 * LOCKING: Take the domain lock.
1372 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1374 gpointer *imt = (gpointer*)vtable;
1375 imt -= MONO_IMT_SIZE;
1376 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1378 /* no support for extra interfaces: the proxy objects will need
1379 * to build the complete IMT
1380 * Update and heck needs to ahppen inside the proper domain lock, as all
1381 * the changes made to a MonoVTable.
1383 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1384 mono_domain_lock (vtable->domain);
1385 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1386 if (imt [imt_slot] == imt_trampoline)
1387 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1388 mono_domain_unlock (vtable->domain);
1389 mono_loader_unlock ();
1394 * The first two free list entries both belong to the wait list: The
1395 * first entry is the pointer to the head of the list and the second
1396 * entry points to the last element. That way appending and removing
1397 * the first element are both O(1) operations.
1399 #define NUM_FREE_LISTS 12
1400 #define FIRST_FREE_LIST_SIZE 64
1401 #define MAX_WAIT_LENGTH 50
1402 #define THUNK_THRESHOLD 10
1405 * LOCKING: The domain lock must be held.
1408 init_thunk_free_lists (MonoDomain *domain)
1410 if (domain->thunk_free_lists)
1412 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1416 list_index_for_size (int item_size)
1419 int size = FIRST_FREE_LIST_SIZE;
1421 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1430 * mono_method_alloc_generic_virtual_thunk:
1432 * @size: size in bytes
1434 * Allocs size bytes to be used for the code of a generic virtual
1435 * thunk. It's either allocated from the domain's code manager or
1436 * reused from a previously invalidated piece.
1438 * LOCKING: The domain lock must be held.
1441 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1443 static gboolean inited = FALSE;
1444 static int generic_virtual_thunks_size = 0;
1448 MonoThunkFreeList **l;
1450 init_thunk_free_lists (domain);
1452 size += sizeof (guint32);
1453 if (size < sizeof (MonoThunkFreeList))
1454 size = sizeof (MonoThunkFreeList);
1456 i = list_index_for_size (size);
1457 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1458 if ((*l)->size >= size) {
1459 MonoThunkFreeList *item = *l;
1461 return ((guint32*)item) + 1;
1465 /* no suitable item found - search lists of larger sizes */
1466 while (++i < NUM_FREE_LISTS) {
1467 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1470 g_assert (item->size > size);
1471 domain->thunk_free_lists [i] = item->next;
1472 return ((guint32*)item) + 1;
1475 /* still nothing found - allocate it */
1477 mono_counters_register ("Generic virtual thunk bytes",
1478 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1481 generic_virtual_thunks_size += size;
1483 p = mono_domain_code_reserve (domain, size);
1490 * LOCKING: The domain lock must be held.
1493 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1496 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1498 init_thunk_free_lists (domain);
1500 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1501 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1502 int length = item->length;
1505 /* unlink the first item from the wait list */
1506 domain->thunk_free_lists [0] = item->next;
1507 domain->thunk_free_lists [0]->length = length - 1;
1509 i = list_index_for_size (item->size);
1511 /* put it in the free list */
1512 item->next = domain->thunk_free_lists [i];
1513 domain->thunk_free_lists [i] = item;
1517 if (domain->thunk_free_lists [1]) {
1518 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1519 domain->thunk_free_lists [0]->length++;
1521 g_assert (!domain->thunk_free_lists [0]);
1523 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1524 domain->thunk_free_lists [0]->length = 1;
1528 typedef struct _GenericVirtualCase {
1532 struct _GenericVirtualCase *next;
1533 } GenericVirtualCase;
1536 * get_generic_virtual_entries:
1538 * Return IMT entries for the generic virtual method instances for vtable slot
1541 static MonoImtBuilderEntry*
1542 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1544 GenericVirtualCase *list;
1545 MonoImtBuilderEntry *entries;
1547 mono_domain_lock (domain);
1548 if (!domain->generic_virtual_cases)
1549 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1551 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1554 for (; list; list = list->next) {
1555 MonoImtBuilderEntry *entry;
1557 if (list->count < THUNK_THRESHOLD)
1560 entry = g_new0 (MonoImtBuilderEntry, 1);
1561 entry->key = list->method;
1562 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1563 entry->has_target_code = 1;
1565 entry->children = entries->children + 1;
1566 entry->next = entries;
1570 mono_domain_unlock (domain);
1572 /* FIXME: Leaking memory ? */
1577 * mono_method_add_generic_virtual_invocation:
1579 * @vtable_slot: pointer to the vtable slot
1580 * @method: the inflated generic virtual method
1581 * @code: the method's code
1583 * Registers a call via unmanaged code to a generic virtual method
1584 * instantiation. If the number of calls reaches a threshold
1585 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1586 * virtual method thunk.
1589 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1590 gpointer *vtable_slot,
1591 MonoMethod *method, gpointer code)
1593 static gboolean inited = FALSE;
1594 static int num_added = 0;
1596 GenericVirtualCase *gvc, *list;
1597 MonoImtBuilderEntry *entries;
1601 mono_domain_lock (domain);
1602 if (!domain->generic_virtual_cases)
1603 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1605 /* Check whether the case was already added */
1606 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1609 if (gvc->method == method)
1614 /* If not found, make a new one */
1616 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1617 gvc->method = method;
1620 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1622 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1625 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1631 if (++gvc->count == THUNK_THRESHOLD) {
1632 gpointer *old_thunk = *vtable_slot;
1634 if ((gpointer)vtable_slot < (gpointer)vtable)
1635 /* Force the rebuild of the thunk at the next call */
1636 *vtable_slot = imt_trampoline;
1638 entries = get_generic_virtual_entries (domain, vtable_slot);
1640 sorted = imt_sort_slot_entries (entries);
1642 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1646 MonoImtBuilderEntry *next = entries->next;
1651 for (i = 0; i < sorted->len; ++i)
1652 g_free (g_ptr_array_index (sorted, i));
1653 g_ptr_array_free (sorted, TRUE);
1656 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1657 invalidate_generic_virtual_thunk (domain, old_thunk);
1660 mono_domain_unlock (domain);
1663 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1666 * mono_class_vtable:
1667 * @domain: the application domain
1668 * @class: the class to initialize
1670 * VTables are domain specific because we create domain specific code, and
1671 * they contain the domain specific static class data.
1672 * On failure, NULL is returned, and class->exception_type is set.
1675 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1677 MonoClassRuntimeInfo *runtime_info;
1681 /* this check can be inlined in jitted code, too */
1682 runtime_info = class->runtime_info;
1683 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1684 return runtime_info->domain_vtables [domain->domain_id];
1685 if (class->exception_type)
1687 return mono_class_create_runtime_vtable (domain, class);
1691 * mono_class_try_get_vtable:
1692 * @domain: the application domain
1693 * @class: the class to initialize
1695 * This function tries to get the associated vtable from @class if
1696 * it was already created.
1699 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1701 MonoClassRuntimeInfo *runtime_info;
1705 runtime_info = class->runtime_info;
1706 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1707 return runtime_info->domain_vtables [domain->domain_id];
1712 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1715 MonoClassRuntimeInfo *runtime_info, *old_info;
1716 MonoClassField *field;
1719 int imt_table_bytes = 0;
1720 guint32 vtable_size, class_size;
1723 gpointer *interface_offsets;
1725 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1726 mono_domain_lock (domain);
1727 runtime_info = class->runtime_info;
1728 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1729 mono_domain_unlock (domain);
1730 mono_loader_unlock ();
1731 return runtime_info->domain_vtables [domain->domain_id];
1733 if (!class->inited || class->exception_type) {
1734 if (!mono_class_init (class) || class->exception_type){
1736 mono_domain_unlock (domain);
1737 mono_loader_unlock ();
1738 exc = mono_class_get_exception_for_failure (class);
1740 mono_raise_exception (exc);
1744 mono_class_init (class);
1747 * For some classes, mono_class_init () already computed class->vtable_size, and
1748 * that is all that is needed because of the vtable trampolines.
1750 if (!class->vtable_size)
1751 mono_class_setup_vtable (class);
1753 if (class->exception_type) {
1754 mono_domain_unlock (domain);
1755 mono_loader_unlock ();
1760 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1761 if (class->interface_offsets_count) {
1762 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1763 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1764 mono_stats.imt_number_of_tables++;
1765 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1768 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1769 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1772 mono_stats.used_class_count++;
1773 mono_stats.class_vtable_size += vtable_size;
1774 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1777 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1779 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1781 vt->rank = class->rank;
1782 vt->domain = domain;
1784 mono_class_compute_gc_descriptor (class);
1786 * We can't use typed allocation in the non-root domains, since the
1787 * collector needs the GC descriptor stored in the vtable even after
1788 * the mempool containing the vtable is destroyed when the domain is
1789 * unloaded. An alternative might be to allocate vtables in the GC
1790 * heap, but this does not seem to work (it leads to crashes inside
1791 * libgc). If that approach is tried, two gc descriptors need to be
1792 * allocated for each class: one for the root domain, and one for all
1793 * other domains. The second descriptor should contain a bit for the
1794 * vtable field in MonoObject, since we can no longer assume the
1795 * vtable is reachable by other roots after the appdomain is unloaded.
1797 #ifdef HAVE_BOEHM_GC
1798 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1799 vt->gc_descr = GC_NO_DESCRIPTOR;
1802 vt->gc_descr = class->gc_descr;
1804 if ((class_size = mono_class_data_size (class))) {
1805 if (class->has_static_refs) {
1806 gpointer statics_gc_descr;
1808 gsize default_bitmap [4] = {0};
1811 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1812 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1813 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1814 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1815 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1816 if (bitmap != default_bitmap)
1819 vt->data = mono_domain_alloc0 (domain, class_size);
1821 mono_stats.class_static_data_size += class_size;
1826 while ((field = mono_class_get_fields (class, &iter))) {
1827 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1829 if (mono_field_is_deleted (field))
1831 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1832 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1833 if (special_static != SPECIAL_STATIC_NONE) {
1834 guint32 size, offset;
1836 size = mono_type_size (field->type, &align);
1837 offset = mono_alloc_special_static_data (special_static, size, align);
1838 if (!domain->special_static_fields)
1839 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1840 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1842 * This marks the field as special static to speed up the
1843 * checks in mono_field_static_get/set_value ().
1849 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1850 MonoClass *fklass = mono_class_from_mono_type (field->type);
1851 const char *data = mono_field_get_data (field);
1853 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1854 t = (char*)vt->data + field->offset;
1855 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1858 if (fklass->valuetype) {
1859 memcpy (t, data, mono_class_value_size (fklass, NULL));
1861 /* it's a pointer type: add check */
1862 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1869 vt->max_interface_id = class->max_interface_id;
1870 vt->interface_bitmap = class->interface_bitmap;
1872 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1873 // class->name, class->interface_offsets_count);
1875 if (! ARCH_USE_IMT) {
1876 /* initialize interface offsets */
1877 for (i = 0; i < class->interface_offsets_count; ++i) {
1878 int interface_id = class->interfaces_packed [i]->interface_id;
1879 int slot = class->interface_offsets_packed [i];
1880 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1884 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1885 * as we change the code in appdomain.c to invalidate vtables by
1886 * looking at the possible MonoClasses created for the domain.
1888 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1889 /* class->runtime_info is protected by the loader lock, both when
1890 * it it enlarged and when it is stored info.
1893 old_info = class->runtime_info;
1894 if (old_info && old_info->max_domain >= domain->domain_id) {
1895 /* someone already created a large enough runtime info */
1896 mono_memory_barrier ();
1897 old_info->domain_vtables [domain->domain_id] = vt;
1899 int new_size = domain->domain_id;
1901 new_size = MAX (new_size, old_info->max_domain);
1903 /* make the new size a power of two */
1905 while (new_size > i)
1908 /* this is a bounded memory retention issue: may want to
1909 * handle it differently when we'll have a rcu-like system.
1911 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1912 runtime_info->max_domain = new_size - 1;
1913 /* copy the stuff from the older info */
1915 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1917 runtime_info->domain_vtables [domain->domain_id] = vt;
1919 mono_memory_barrier ();
1920 class->runtime_info = runtime_info;
1923 /* Initialize vtable */
1924 if (vtable_trampoline) {
1925 // This also covers the AOT case
1926 for (i = 0; i < class->vtable_size; ++i) {
1927 vt->vtable [i] = vtable_trampoline;
1930 mono_class_setup_vtable (class);
1932 for (i = 0; i < class->vtable_size; ++i) {
1935 if ((cm = class->vtable [i]))
1936 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1940 if (ARCH_USE_IMT && imt_table_bytes) {
1941 /* Now that the vtable is full, we can actually fill up the IMT */
1942 if (imt_trampoline) {
1943 /* lazy construction of the IMT entries enabled */
1944 for (i = 0; i < MONO_IMT_SIZE; ++i)
1945 interface_offsets [i] = imt_trampoline;
1947 build_imt (class, vt, domain, interface_offsets, NULL);
1951 mono_domain_unlock (domain);
1952 mono_loader_unlock ();
1954 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1955 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1956 MonoException *exc = mono_class_get_exception_for_failure (class);
1958 mono_raise_exception (exc);
1961 /* make sure the parent is initialized */
1963 mono_class_vtable (domain, class->parent);
1965 vt->type = mono_type_get_object (domain, &class->byval_arg);
1966 if (class->contextbound)
1975 * mono_class_proxy_vtable:
1976 * @domain: the application domain
1977 * @remove_class: the remote class
1979 * Creates a vtable for transparent proxies. It is basically
1980 * a copy of the real vtable of the class wrapped in @remote_class,
1981 * but all function pointers invoke the remoting functions, and
1982 * vtable->klass points to the transparent proxy class, and not to @class.
1985 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1987 MonoVTable *vt, *pvt;
1988 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1990 GSList *extra_interfaces = NULL;
1991 MonoClass *class = remote_class->proxy_class;
1992 gpointer *interface_offsets;
1994 vt = mono_class_vtable (domain, class);
1995 max_interface_id = vt->max_interface_id;
1997 /* Calculate vtable space for extra interfaces */
1998 for (j = 0; j < remote_class->interface_count; j++) {
1999 MonoClass* iclass = remote_class->interfaces[j];
2003 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2004 continue; /* interface implemented by the class */
2005 if (g_slist_find (extra_interfaces, iclass))
2008 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2010 method_count = mono_class_num_methods (iclass);
2012 ifaces = mono_class_get_implemented_interfaces (iclass);
2014 for (i = 0; i < ifaces->len; ++i) {
2015 MonoClass *ic = g_ptr_array_index (ifaces, i);
2016 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2017 continue; /* interface implemented by the class */
2018 if (g_slist_find (extra_interfaces, ic))
2020 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2021 method_count += mono_class_num_methods (ic);
2023 g_ptr_array_free (ifaces, TRUE);
2026 extra_interface_vtsize += method_count * sizeof (gpointer);
2027 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2031 mono_stats.imt_number_of_tables++;
2032 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2033 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2034 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2036 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2037 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2040 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2042 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2044 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2046 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2047 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2049 pvt->klass = mono_defaults.transparent_proxy_class;
2050 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2051 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2053 /* initialize vtable */
2054 mono_class_setup_vtable (class);
2055 for (i = 0; i < class->vtable_size; ++i) {
2058 if ((cm = class->vtable [i]))
2059 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2061 pvt->vtable [i] = NULL;
2064 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2065 /* create trampolines for abstract methods */
2066 for (k = class; k; k = k->parent) {
2068 gpointer iter = NULL;
2069 while ((m = mono_class_get_methods (k, &iter)))
2070 if (!pvt->vtable [m->slot])
2071 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2075 pvt->max_interface_id = max_interface_id;
2076 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2078 if (! ARCH_USE_IMT) {
2079 /* initialize interface offsets */
2080 for (i = 0; i < class->interface_offsets_count; ++i) {
2081 int interface_id = class->interfaces_packed [i]->interface_id;
2082 int slot = class->interface_offsets_packed [i];
2083 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2086 for (i = 0; i < class->interface_offsets_count; ++i) {
2087 int interface_id = class->interfaces_packed [i]->interface_id;
2088 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2091 if (extra_interfaces) {
2092 int slot = class->vtable_size;
2098 /* Create trampolines for the methods of the interfaces */
2099 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2100 interf = list_item->data;
2102 if (! ARCH_USE_IMT) {
2103 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2105 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2109 while ((cm = mono_class_get_methods (interf, &iter)))
2110 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2112 slot += mono_class_num_methods (interf);
2114 if (! ARCH_USE_IMT) {
2115 g_slist_free (extra_interfaces);
2120 /* Now that the vtable is full, we can actually fill up the IMT */
2121 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2122 if (extra_interfaces) {
2123 g_slist_free (extra_interfaces);
2131 * mono_class_field_is_special_static:
2133 * Returns whether @field is a thread/context static field.
2136 mono_class_field_is_special_static (MonoClassField *field)
2138 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2140 if (mono_field_is_deleted (field))
2142 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2143 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2150 * mono_class_has_special_static_fields:
2152 * Returns whenever @klass has any thread/context static fields.
2155 mono_class_has_special_static_fields (MonoClass *klass)
2157 MonoClassField *field;
2161 while ((field = mono_class_get_fields (klass, &iter))) {
2162 g_assert (field->parent == klass);
2163 if (mono_class_field_is_special_static (field))
2171 * create_remote_class_key:
2172 * Creates an array of pointers that can be used as a hash key for a remote class.
2173 * The first element of the array is the number of pointers.
2176 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2181 if (remote_class == NULL) {
2182 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2183 key = g_malloc (sizeof(gpointer) * 3);
2184 key [0] = GINT_TO_POINTER (2);
2185 key [1] = mono_defaults.marshalbyrefobject_class;
2186 key [2] = extra_class;
2188 key = g_malloc (sizeof(gpointer) * 2);
2189 key [0] = GINT_TO_POINTER (1);
2190 key [1] = extra_class;
2193 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2194 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2195 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2196 key [1] = remote_class->proxy_class;
2198 // Keep the list of interfaces sorted
2199 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2200 if (extra_class && remote_class->interfaces [i] > extra_class) {
2201 key [j++] = extra_class;
2204 key [j] = remote_class->interfaces [i];
2207 key [j] = extra_class;
2209 // Replace the old class. The interface list is the same
2210 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2211 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2212 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2213 for (i = 0; i < remote_class->interface_count; i++)
2214 key [2 + i] = remote_class->interfaces [i];
2222 * copy_remote_class_key:
2224 * Make a copy of KEY in the domain and return the copy.
2227 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2229 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2230 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2232 memcpy (mp_key, key, key_size);
2238 * mono_remote_class:
2239 * @domain: the application domain
2240 * @class_name: name of the remote class
2242 * Creates and initializes a MonoRemoteClass object for a remote type.
2246 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2248 MonoRemoteClass *rc;
2249 gpointer* key, *mp_key;
2251 key = create_remote_class_key (NULL, proxy_class);
2253 mono_domain_lock (domain);
2254 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2258 mono_domain_unlock (domain);
2262 mp_key = copy_remote_class_key (domain, key);
2266 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2267 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2268 rc->interface_count = 1;
2269 rc->interfaces [0] = proxy_class;
2270 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2272 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2273 rc->interface_count = 0;
2274 rc->proxy_class = proxy_class;
2277 rc->default_vtable = NULL;
2278 rc->xdomain_vtable = NULL;
2279 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2280 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2282 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2284 mono_domain_unlock (domain);
2289 * clone_remote_class:
2290 * Creates a copy of the remote_class, adding the provided class or interface
2292 static MonoRemoteClass*
2293 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2295 MonoRemoteClass *rc;
2296 gpointer* key, *mp_key;
2298 key = create_remote_class_key (remote_class, extra_class);
2299 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2305 mp_key = copy_remote_class_key (domain, key);
2309 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2311 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2312 rc->proxy_class = remote_class->proxy_class;
2313 rc->interface_count = remote_class->interface_count + 1;
2315 // Keep the list of interfaces sorted, since the hash key of
2316 // the remote class depends on this
2317 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2318 if (remote_class->interfaces [i] > extra_class && i == j)
2319 rc->interfaces [j++] = extra_class;
2320 rc->interfaces [j] = remote_class->interfaces [i];
2323 rc->interfaces [j] = extra_class;
2325 // Replace the old class. The interface array is the same
2326 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2327 rc->proxy_class = extra_class;
2328 rc->interface_count = remote_class->interface_count;
2329 if (rc->interface_count > 0)
2330 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2333 rc->default_vtable = NULL;
2334 rc->xdomain_vtable = NULL;
2335 rc->proxy_class_name = remote_class->proxy_class_name;
2337 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2343 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2345 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2346 mono_domain_lock (domain);
2347 if (rp->target_domain_id != -1) {
2348 if (remote_class->xdomain_vtable == NULL)
2349 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2350 mono_domain_unlock (domain);
2351 mono_loader_unlock ();
2352 return remote_class->xdomain_vtable;
2354 if (remote_class->default_vtable == NULL) {
2357 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2358 klass = mono_class_from_mono_type (type);
2359 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2360 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2362 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2365 mono_domain_unlock (domain);
2366 mono_loader_unlock ();
2367 return remote_class->default_vtable;
2371 * mono_upgrade_remote_class:
2372 * @domain: the application domain
2373 * @tproxy: the proxy whose remote class has to be upgraded.
2374 * @klass: class to which the remote class can be casted.
2376 * Updates the vtable of the remote class by adding the necessary method slots
2377 * and interface offsets so it can be safely casted to klass. klass can be a
2378 * class or an interface.
2381 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2383 MonoTransparentProxy *tproxy;
2384 MonoRemoteClass *remote_class;
2385 gboolean redo_vtable;
2387 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2388 mono_domain_lock (domain);
2390 tproxy = (MonoTransparentProxy*) proxy_object;
2391 remote_class = tproxy->remote_class;
2393 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2396 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2397 if (remote_class->interfaces [i] == klass)
2398 redo_vtable = FALSE;
2401 redo_vtable = (remote_class->proxy_class != klass);
2405 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2406 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2409 mono_domain_unlock (domain);
2410 mono_loader_unlock ();
2415 * mono_object_get_virtual_method:
2416 * @obj: object to operate on.
2419 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2420 * the instance of a callvirt of method.
2423 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2426 MonoMethod **vtable;
2428 MonoMethod *res = NULL;
2430 klass = mono_object_class (obj);
2431 if (klass == mono_defaults.transparent_proxy_class) {
2432 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2438 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2441 mono_class_setup_vtable (klass);
2442 vtable = klass->vtable;
2444 if (method->slot == -1) {
2445 /* method->slot might not be set for instances of generic methods */
2446 if (method->is_inflated) {
2447 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2448 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2451 g_assert_not_reached ();
2455 /* check method->slot is a valid index: perform isinstance? */
2456 if (method->slot != -1) {
2457 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2459 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2461 res = vtable [method->slot];
2466 /* It may be an interface, abstract class method or generic method */
2467 if (!res || mono_method_signature (res)->generic_param_count)
2470 /* generic methods demand invoke_with_check */
2471 if (mono_method_signature (res)->generic_param_count)
2472 res = mono_marshal_get_remoting_invoke_with_check (res);
2475 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2476 res = mono_cominterop_get_invoke (res);
2479 res = mono_marshal_get_remoting_invoke (res);
2482 if (method->is_inflated) {
2483 /* Have to inflate the result */
2484 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2494 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2496 g_error ("runtime invoke called on uninitialized runtime");
2500 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2503 * mono_runtime_invoke:
2504 * @method: method to invoke
2505 * @obJ: object instance
2506 * @params: arguments to the method
2507 * @exc: exception information.
2509 * Invokes the method represented by @method on the object @obj.
2511 * obj is the 'this' pointer, it should be NULL for static
2512 * methods, a MonoObject* for object instances and a pointer to
2513 * the value type for value types.
2515 * The params array contains the arguments to the method with the
2516 * same convention: MonoObject* pointers for object instances and
2517 * pointers to the value type otherwise.
2519 * From unmanaged code you'll usually use the
2520 * mono_runtime_invoke() variant.
2522 * Note that this function doesn't handle virtual methods for
2523 * you, it will exec the exact method you pass: we still need to
2524 * expose a function to lookup the derived class implementation
2525 * of a virtual method (there are examples of this in the code,
2528 * You can pass NULL as the exc argument if you don't want to
2529 * catch exceptions, otherwise, *exc will be set to the exception
2530 * thrown, if any. if an exception is thrown, you can't use the
2531 * MonoObject* result from the function.
2533 * If the method returns a value type, it is boxed in an object
2537 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2539 if (mono_runtime_get_no_exec ())
2540 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2542 return default_mono_runtime_invoke (method, obj, params, exc);
2546 * mono_method_get_unmanaged_thunk:
2547 * @method: method to generate a thunk for.
2549 * Returns an unmanaged->managed thunk that can be used to call
2550 * a managed method directly from C.
2552 * The thunk's C signature closely matches the managed signature:
2554 * C#: public bool Equals (object obj);
2555 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2556 * MonoObject*, MonoException**);
2558 * The 1st ("this") parameter must not be used with static methods:
2560 * C#: public static bool ReferenceEquals (object a, object b);
2561 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2564 * The last argument must be a non-null pointer of a MonoException* pointer.
2565 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2566 * exception has been thrown in managed code. Otherwise it will point
2567 * to the MonoException* caught by the thunk. In this case, the result of
2568 * the thunk is undefined:
2570 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2571 * MonoException *ex = NULL;
2572 * Equals func = mono_method_get_unmanaged_thunk (method);
2573 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2575 * // handle exception
2578 * The calling convention of the thunk matches the platform's default
2579 * convention. This means that under Windows, C declarations must
2580 * contain the __stdcall attribute:
2582 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2583 * MonoObject*, MonoException**);
2587 * Value type arguments and return values are treated as they were objects:
2589 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2590 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2592 * Arguments must be properly boxed upon trunk's invocation, while return
2593 * values must be unboxed.
2596 mono_method_get_unmanaged_thunk (MonoMethod *method)
2598 method = mono_marshal_get_thunk_invoke_wrapper (method);
2599 return mono_compile_method (method);
2603 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2607 /* object fields cannot be byref, so we don't need a
2609 gpointer *p = (gpointer*)dest;
2616 case MONO_TYPE_BOOLEAN:
2618 case MONO_TYPE_U1: {
2619 guint8 *p = (guint8*)dest;
2620 *p = value ? *(guint8*)value : 0;
2625 case MONO_TYPE_CHAR: {
2626 guint16 *p = (guint16*)dest;
2627 *p = value ? *(guint16*)value : 0;
2630 #if SIZEOF_VOID_P == 4
2635 case MONO_TYPE_U4: {
2636 gint32 *p = (gint32*)dest;
2637 *p = value ? *(gint32*)value : 0;
2640 #if SIZEOF_VOID_P == 8
2645 case MONO_TYPE_U8: {
2646 gint64 *p = (gint64*)dest;
2647 *p = value ? *(gint64*)value : 0;
2650 case MONO_TYPE_R4: {
2651 float *p = (float*)dest;
2652 *p = value ? *(float*)value : 0;
2655 case MONO_TYPE_R8: {
2656 double *p = (double*)dest;
2657 *p = value ? *(double*)value : 0;
2660 case MONO_TYPE_STRING:
2661 case MONO_TYPE_SZARRAY:
2662 case MONO_TYPE_CLASS:
2663 case MONO_TYPE_OBJECT:
2664 case MONO_TYPE_ARRAY:
2665 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2667 case MONO_TYPE_FNPTR:
2668 case MONO_TYPE_PTR: {
2669 gpointer *p = (gpointer*)dest;
2670 *p = deref_pointer? *(gpointer*)value: value;
2673 case MONO_TYPE_VALUETYPE:
2674 /* note that 't' and 'type->type' can be different */
2675 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2676 t = mono_class_enum_basetype (type->data.klass)->type;
2679 MonoClass *class = mono_class_from_mono_type (type);
2680 int size = mono_class_value_size (class, NULL);
2681 if (value == NULL) {
2682 memset (dest, 0, size);
2684 memcpy (dest, value, size);
2685 mono_gc_wbarrier_value_copy (dest, value, size, class);
2689 case MONO_TYPE_GENERICINST:
2690 t = type->data.generic_class->container_class->byval_arg.type;
2693 g_warning ("got type %x", type->type);
2694 g_assert_not_reached ();
2699 * mono_field_set_value:
2700 * @obj: Instance object
2701 * @field: MonoClassField describing the field to set
2702 * @value: The value to be set
2704 * Sets the value of the field described by @field in the object instance @obj
2705 * to the value passed in @value. This method should only be used for instance
2706 * fields. For static fields, use mono_field_static_set_value.
2708 * The value must be on the native format of the field type.
2711 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2715 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2717 dest = (char*)obj + field->offset;
2718 set_value (field->type, dest, value, FALSE);
2722 * mono_field_static_set_value:
2723 * @field: MonoClassField describing the field to set
2724 * @value: The value to be set
2726 * Sets the value of the static field described by @field
2727 * to the value passed in @value.
2729 * The value must be on the native format of the field type.
2732 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2736 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2737 /* you cant set a constant! */
2738 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2740 if (field->offset == -1) {
2741 /* Special static */
2742 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2743 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2745 dest = (char*)vt->data + field->offset;
2747 set_value (field->type, dest, value, FALSE);
2750 /* Used by the debugger */
2752 mono_vtable_get_static_field_data (MonoVTable *vt)
2758 * mono_field_get_value:
2759 * @obj: Object instance
2760 * @field: MonoClassField describing the field to fetch information from
2761 * @value: pointer to the location where the value will be stored
2763 * Use this routine to get the value of the field @field in the object
2766 * The pointer provided by value must be of the field type, for reference
2767 * types this is a MonoObject*, for value types its the actual pointer to
2772 * mono_field_get_value (obj, int_field, &i);
2775 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2779 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2781 src = (char*)obj + field->offset;
2782 set_value (field->type, value, src, TRUE);
2786 * mono_field_get_value_object:
2787 * @domain: domain where the object will be created (if boxing)
2788 * @field: MonoClassField describing the field to fetch information from
2789 * @obj: The object instance for the field.
2791 * Returns: a new MonoObject with the value from the given field. If the
2792 * field represents a value type, the value is boxed.
2796 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2800 MonoVTable *vtable = NULL;
2802 gboolean is_static = FALSE;
2803 gboolean is_ref = FALSE;
2805 switch (field->type->type) {
2806 case MONO_TYPE_STRING:
2807 case MONO_TYPE_OBJECT:
2808 case MONO_TYPE_CLASS:
2809 case MONO_TYPE_ARRAY:
2810 case MONO_TYPE_SZARRAY:
2815 case MONO_TYPE_BOOLEAN:
2818 case MONO_TYPE_CHAR:
2827 case MONO_TYPE_VALUETYPE:
2828 is_ref = field->type->byref;
2830 case MONO_TYPE_GENERICINST:
2831 is_ref = !field->type->data.generic_class->container_class->valuetype;
2834 g_error ("type 0x%x not handled in "
2835 "mono_field_get_value_object", field->type->type);
2839 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2841 vtable = mono_class_vtable (domain, field->parent);
2842 if (!vtable->initialized)
2843 mono_runtime_class_init (vtable);
2848 mono_field_static_get_value (vtable, field, &o);
2850 mono_field_get_value (obj, field, &o);
2855 /* boxed value type */
2856 klass = mono_class_from_mono_type (field->type);
2857 o = mono_object_new (domain, klass);
2858 v = ((gchar *) o) + sizeof (MonoObject);
2860 mono_field_static_get_value (vtable, field, v);
2862 mono_field_get_value (obj, field, v);
2869 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2872 const char *p = blob;
2873 mono_metadata_decode_blob_size (p, &p);
2876 case MONO_TYPE_BOOLEAN:
2879 *(guint8 *) value = *p;
2881 case MONO_TYPE_CHAR:
2884 *(guint16*) value = read16 (p);
2888 *(guint32*) value = read32 (p);
2892 *(guint64*) value = read64 (p);
2895 readr4 (p, (float*) value);
2898 readr8 (p, (double*) value);
2900 case MONO_TYPE_STRING:
2901 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2903 case MONO_TYPE_CLASS:
2904 *(gpointer*) value = NULL;
2908 g_warning ("type 0x%02x should not be in constant table", type);
2914 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2916 MonoTypeEnum def_type;
2919 data = mono_class_get_field_default_value (field, &def_type);
2920 mono_get_constant_value_from_blob (domain, def_type, data, value);
2924 * mono_field_static_get_value:
2925 * @vt: vtable to the object
2926 * @field: MonoClassField describing the field to fetch information from
2927 * @value: where the value is returned
2929 * Use this routine to get the value of the static field @field value.
2931 * The pointer provided by value must be of the field type, for reference
2932 * types this is a MonoObject*, for value types its the actual pointer to
2937 * mono_field_static_get_value (vt, int_field, &i);
2940 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2944 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2946 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2947 get_default_field_value (vt->domain, field, value);
2951 if (field->offset == -1) {
2952 /* Special static */
2953 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2954 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2956 src = (char*)vt->data + field->offset;
2958 set_value (field->type, value, src, TRUE);
2962 * mono_property_set_value:
2963 * @prop: MonoProperty to set
2964 * @obj: instance object on which to act
2965 * @params: parameters to pass to the propery
2966 * @exc: optional exception
2968 * Invokes the property's set method with the given arguments on the
2969 * object instance obj (or NULL for static properties).
2971 * You can pass NULL as the exc argument if you don't want to
2972 * catch exceptions, otherwise, *exc will be set to the exception
2973 * thrown, if any. if an exception is thrown, you can't use the
2974 * MonoObject* result from the function.
2977 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2979 default_mono_runtime_invoke (prop->set, obj, params, exc);
2983 * mono_property_get_value:
2984 * @prop: MonoProperty to fetch
2985 * @obj: instance object on which to act
2986 * @params: parameters to pass to the propery
2987 * @exc: optional exception
2989 * Invokes the property's get method with the given arguments on the
2990 * object instance obj (or NULL for static properties).
2992 * You can pass NULL as the exc argument if you don't want to
2993 * catch exceptions, otherwise, *exc will be set to the exception
2994 * thrown, if any. if an exception is thrown, you can't use the
2995 * MonoObject* result from the function.
2997 * Returns: the value from invoking the get method on the property.
3000 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3002 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3006 * mono_nullable_init:
3007 * @buf: The nullable structure to initialize.
3008 * @value: the value to initialize from
3009 * @klass: the type for the object
3011 * Initialize the nullable structure pointed to by @buf from @value which
3012 * should be a boxed value type. The size of @buf should be able to hold
3013 * as much data as the @klass->instance_size (which is the number of bytes
3014 * that will be copies).
3016 * Since Nullables have variable structure, we can not define a C
3017 * structure for them.
3020 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3022 MonoClass *param_class = klass->cast_class;
3024 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3025 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3027 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3029 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3031 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3035 * mono_nullable_box:
3036 * @buf: The buffer representing the data to be boxed
3037 * @klass: the type to box it as.
3039 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3043 mono_nullable_box (guint8 *buf, MonoClass *klass)
3045 MonoClass *param_class = klass->cast_class;
3047 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3048 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3050 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3051 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3052 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3060 * mono_get_delegate_invoke:
3061 * @klass: The delegate class
3063 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3066 mono_get_delegate_invoke (MonoClass *klass)
3070 /* This is called at runtime, so avoid the slower search in metadata */
3071 mono_class_setup_methods (klass);
3073 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3080 * mono_runtime_delegate_invoke:
3081 * @delegate: pointer to a delegate object.
3082 * @params: parameters for the delegate.
3083 * @exc: Pointer to the exception result.
3085 * Invokes the delegate method @delegate with the parameters provided.
3087 * You can pass NULL as the exc argument if you don't want to
3088 * catch exceptions, otherwise, *exc will be set to the exception
3089 * thrown, if any. if an exception is thrown, you can't use the
3090 * MonoObject* result from the function.
3093 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3097 im = mono_get_delegate_invoke (delegate->vtable->klass);
3100 return mono_runtime_invoke (im, delegate, params, exc);
3103 static char **main_args = NULL;
3104 static int num_main_args;
3107 * mono_runtime_get_main_args:
3109 * Returns: a MonoArray with the arguments passed to the main program
3112 mono_runtime_get_main_args (void)
3116 MonoDomain *domain = mono_domain_get ();
3121 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3123 for (i = 0; i < num_main_args; ++i)
3124 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3130 fire_process_exit_event (void)
3132 MonoClassField *field;
3133 MonoDomain *domain = mono_domain_get ();
3135 MonoObject *delegate, *exc;
3137 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3140 if (domain != mono_get_root_domain ())
3143 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3144 if (delegate == NULL)
3149 mono_runtime_delegate_invoke (delegate, pa, &exc);
3153 * mono_runtime_run_main:
3154 * @method: the method to start the application with (usually Main)
3155 * @argc: number of arguments from the command line
3156 * @argv: array of strings from the command line
3157 * @exc: excetption results
3159 * Execute a standard Main() method (argc/argv contains the
3160 * executable name). This method also sets the command line argument value
3161 * needed by System.Environment.
3166 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3170 MonoArray *args = NULL;
3171 MonoDomain *domain = mono_domain_get ();
3172 gchar *utf8_fullpath;
3175 g_assert (method != NULL);
3177 mono_thread_set_main (mono_thread_current ());
3179 main_args = g_new0 (char*, argc);
3180 num_main_args = argc;
3182 if (!g_path_is_absolute (argv [0])) {
3183 gchar *basename = g_path_get_basename (argv [0]);
3184 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3188 utf8_fullpath = mono_utf8_from_external (fullpath);
3189 if(utf8_fullpath == NULL) {
3190 /* Printing the arg text will cause glib to
3191 * whinge about "Invalid UTF-8", but at least
3192 * its relevant, and shows the problem text
3195 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3196 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3203 utf8_fullpath = mono_utf8_from_external (argv[0]);
3204 if(utf8_fullpath == NULL) {
3205 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3206 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3211 main_args [0] = utf8_fullpath;
3213 for (i = 1; i < argc; ++i) {
3216 utf8_arg=mono_utf8_from_external (argv[i]);
3217 if(utf8_arg==NULL) {
3218 /* Ditto the comment about Invalid UTF-8 here */
3219 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3220 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3224 main_args [i] = utf8_arg;
3228 if (mono_method_signature (method)->param_count) {
3229 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3230 for (i = 0; i < argc; ++i) {
3231 /* The encodings should all work, given that
3232 * we've checked all these args for the
3235 gchar *str = mono_utf8_from_external (argv [i]);
3236 MonoString *arg = mono_string_new (domain, str);
3237 mono_array_setref (args, i, arg);
3241 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3244 mono_assembly_set_main (method->klass->image->assembly);
3246 result = mono_runtime_exec_main (method, args, exc);
3247 fire_process_exit_event ();
3251 /* Used in call_unhandled_exception_delegate */
3253 create_unhandled_exception_eventargs (MonoObject *exc)
3257 MonoMethod *method = NULL;
3258 MonoBoolean is_terminating = TRUE;
3261 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3264 mono_class_init (klass);
3266 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3267 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3271 args [1] = &is_terminating;
3273 obj = mono_object_new (mono_domain_get (), klass);
3274 mono_runtime_invoke (method, obj, args, NULL);
3279 /* Used in mono_unhandled_exception */
3281 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3282 MonoObject *e = NULL;
3285 pa [0] = domain->domain;
3286 pa [1] = create_unhandled_exception_eventargs (exc);
3287 mono_runtime_delegate_invoke (delegate, pa, &e);
3290 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3291 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3296 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3299 * mono_runtime_unhandled_exception_policy_set:
3300 * @policy: the new policy
3302 * This is a VM internal routine.
3304 * Sets the runtime policy for handling unhandled exceptions.
3307 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3308 runtime_unhandled_exception_policy = policy;
3312 * mono_runtime_unhandled_exception_policy_get:
3314 * This is a VM internal routine.
3316 * Gets the runtime policy for handling unhandled exceptions.
3318 MonoRuntimeUnhandledExceptionPolicy
3319 mono_runtime_unhandled_exception_policy_get (void) {
3320 return runtime_unhandled_exception_policy;
3324 * mono_unhandled_exception:
3325 * @exc: exception thrown
3327 * This is a VM internal routine.
3329 * We call this function when we detect an unhandled exception
3330 * in the default domain.
3332 * It invokes the * UnhandledException event in AppDomain or prints
3333 * a warning to the console
3336 mono_unhandled_exception (MonoObject *exc)
3338 MonoDomain *current_domain = mono_domain_get ();
3339 MonoDomain *root_domain = mono_get_root_domain ();
3340 MonoClassField *field;
3341 MonoObject *current_appdomain_delegate;
3342 MonoObject *root_appdomain_delegate;
3344 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3345 "UnhandledException");
3348 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3349 gboolean abort_process = (mono_thread_current () == main_thread) ||
3350 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3351 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3352 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3353 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3355 current_appdomain_delegate = NULL;
3358 /* set exitcode only if we will abort the process */
3360 mono_environment_exitcode_set (1);
3361 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3362 mono_print_unhandled_exception (exc);
3364 if (root_appdomain_delegate) {
3365 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3367 if (current_appdomain_delegate) {
3368 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3375 * Launch a new thread to execute a function
3377 * main_func is called back from the thread with main_args as the
3378 * parameter. The callback function is expected to start Main()
3379 * eventually. This function then waits for all managed threads to
3381 * It is not necesseray anymore to execute managed code in a subthread,
3382 * so this function should not be used anymore by default: just
3383 * execute the code and then call mono_thread_manage ().
3386 mono_runtime_exec_managed_code (MonoDomain *domain,
3387 MonoMainThreadFunc main_func,
3390 mono_thread_create (domain, main_func, main_args);
3392 mono_thread_manage ();
3396 * Execute a standard Main() method (args doesn't contain the
3400 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3405 MonoCustomAttrInfo* cinfo;
3406 gboolean has_stathread_attribute;
3407 MonoThread* thread = mono_thread_current ();
3413 domain = mono_object_domain (args);
3414 if (!domain->entry_assembly) {
3416 MonoAssembly *assembly;
3418 assembly = method->klass->image->assembly;
3419 domain->entry_assembly = assembly;
3420 /* Domains created from another domain already have application_base and configuration_file set */
3421 if (domain->setup->application_base == NULL) {
3422 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3425 if (domain->setup->configuration_file == NULL) {
3426 str = g_strconcat (assembly->image->name, ".config", NULL);
3427 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3429 mono_set_private_bin_path_from_config (domain);
3433 cinfo = mono_custom_attrs_from_method (method);
3435 static MonoClass *stathread_attribute = NULL;
3436 if (!stathread_attribute)
3437 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3438 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3440 mono_custom_attrs_free (cinfo);
3442 has_stathread_attribute = FALSE;
3444 if (has_stathread_attribute) {
3445 thread->apartment_state = ThreadApartmentState_STA;
3446 } else if (mono_framework_version () == 1) {
3447 thread->apartment_state = ThreadApartmentState_Unknown;
3449 thread->apartment_state = ThreadApartmentState_MTA;
3451 mono_thread_init_apartment_state ();
3453 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3455 /* FIXME: check signature of method */
3456 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3458 res = mono_runtime_invoke (method, NULL, pa, exc);
3460 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3464 mono_environment_exitcode_set (rval);
3466 mono_runtime_invoke (method, NULL, pa, exc);
3470 /* If the return type of Main is void, only
3471 * set the exitcode if an exception was thrown
3472 * (we don't want to blow away an
3473 * explicitly-set exit code)
3476 mono_environment_exitcode_set (rval);
3480 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3486 * mono_install_runtime_invoke:
3487 * @func: Function to install
3489 * This is a VM internal routine
3492 mono_install_runtime_invoke (MonoInvokeFunc func)
3494 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3499 * mono_runtime_invoke_array:
3500 * @method: method to invoke
3501 * @obJ: object instance
3502 * @params: arguments to the method
3503 * @exc: exception information.
3505 * Invokes the method represented by @method on the object @obj.
3507 * obj is the 'this' pointer, it should be NULL for static
3508 * methods, a MonoObject* for object instances and a pointer to
3509 * the value type for value types.
3511 * The params array contains the arguments to the method with the
3512 * same convention: MonoObject* pointers for object instances and
3513 * pointers to the value type otherwise. The _invoke_array
3514 * variant takes a C# object[] as the params argument (MonoArray
3515 * *params): in this case the value types are boxed inside the
3516 * respective reference representation.
3518 * From unmanaged code you'll usually use the
3519 * mono_runtime_invoke() variant.
3521 * Note that this function doesn't handle virtual methods for
3522 * you, it will exec the exact method you pass: we still need to
3523 * expose a function to lookup the derived class implementation
3524 * of a virtual method (there are examples of this in the code,
3527 * You can pass NULL as the exc argument if you don't want to
3528 * catch exceptions, otherwise, *exc will be set to the exception
3529 * thrown, if any. if an exception is thrown, you can't use the
3530 * MonoObject* result from the function.
3532 * If the method returns a value type, it is boxed in an object
3536 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3539 MonoMethodSignature *sig = mono_method_signature (method);
3540 gpointer *pa = NULL;
3543 gboolean has_byref_nullables = FALSE;
3545 if (NULL != params) {
3546 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3547 for (i = 0; i < mono_array_length (params); i++) {
3548 MonoType *t = sig->params [i];
3554 case MONO_TYPE_BOOLEAN:
3557 case MONO_TYPE_CHAR:
3566 case MONO_TYPE_VALUETYPE:
3567 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3568 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3569 pa [i] = mono_array_get (params, MonoObject*, i);
3571 has_byref_nullables = TRUE;
3573 /* MS seems to create the objects if a null is passed in */
3574 if (!mono_array_get (params, MonoObject*, i))
3575 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3579 * We can't pass the unboxed vtype byref to the callee, since
3580 * that would mean the callee would be able to modify boxed
3581 * primitive types. So we (and MS) make a copy of the boxed
3582 * object, pass that to the callee, and replace the original
3583 * boxed object in the arg array with the copy.
3585 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3586 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3587 mono_array_setref (params, i, copy);
3590 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3593 case MONO_TYPE_STRING:
3594 case MONO_TYPE_OBJECT:
3595 case MONO_TYPE_CLASS:
3596 case MONO_TYPE_ARRAY:
3597 case MONO_TYPE_SZARRAY:
3599 pa [i] = mono_array_addr (params, MonoObject*, i);
3600 // FIXME: I need to check this code path
3602 pa [i] = mono_array_get (params, MonoObject*, i);
3604 case MONO_TYPE_GENERICINST:
3606 t = &t->data.generic_class->container_class->this_arg;
3608 t = &t->data.generic_class->container_class->byval_arg;
3610 case MONO_TYPE_PTR: {
3613 /* The argument should be an IntPtr */
3614 arg = mono_array_get (params, MonoObject*, i);
3618 g_assert (arg->vtable->klass == mono_defaults.int_class);
3619 pa [i] = ((MonoIntPtr*)arg)->m_value;
3624 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3629 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3632 if (mono_class_is_nullable (method->klass)) {
3633 /* Need to create a boxed vtype instead */
3639 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3643 obj = mono_object_new (mono_domain_get (), method->klass);
3644 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3645 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3647 if (method->klass->valuetype)
3648 o = mono_object_unbox (obj);
3651 } else if (method->klass->valuetype) {
3652 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3655 mono_runtime_invoke (method, o, pa, exc);
3658 if (mono_class_is_nullable (method->klass)) {
3659 MonoObject *nullable;
3661 /* Convert the unboxed vtype into a Nullable structure */
3662 nullable = mono_object_new (mono_domain_get (), method->klass);
3664 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3665 obj = mono_object_unbox (nullable);
3668 /* obj must be already unboxed if needed */
3669 res = mono_runtime_invoke (method, obj, pa, exc);
3671 if (sig->ret->type == MONO_TYPE_PTR) {
3672 MonoClass *pointer_class;
3673 static MonoMethod *box_method;
3675 MonoObject *box_exc;
3678 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3679 * convert it to a Pointer object.
3681 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3683 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3685 g_assert (res->vtable->klass == mono_defaults.int_class);
3686 box_args [0] = ((MonoIntPtr*)res)->m_value;
3687 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3688 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3689 g_assert (!box_exc);
3692 if (has_byref_nullables) {
3694 * The runtime invoke wrapper already converted byref nullables back,
3695 * and stored them in pa, we just need to copy them back to the
3698 for (i = 0; i < mono_array_length (params); i++) {
3699 MonoType *t = sig->params [i];
3701 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3702 mono_array_setref (params, i, pa [i]);
3711 arith_overflow (void)
3713 mono_raise_exception (mono_get_exception_overflow ());
3717 * mono_object_allocate:
3718 * @size: number of bytes to allocate
3720 * This is a very simplistic routine until we have our GC-aware
3723 * Returns: an allocated object of size @size, or NULL on failure.
3725 static inline void *
3726 mono_object_allocate (size_t size, MonoVTable *vtable)
3729 mono_stats.new_object_count++;
3730 ALLOC_OBJECT (o, vtable, size);
3736 * mono_object_allocate_ptrfree:
3737 * @size: number of bytes to allocate
3739 * Note that the memory allocated is not zeroed.
3740 * Returns: an allocated object of size @size, or NULL on failure.
3742 static inline void *
3743 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3746 mono_stats.new_object_count++;
3747 ALLOC_PTRFREE (o, vtable, size);
3751 static inline void *
3752 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3755 ALLOC_TYPED (o, size, vtable);
3756 mono_stats.new_object_count++;
3763 * @klass: the class of the object that we want to create
3765 * Returns: a newly created object whose definition is
3766 * looked up using @klass. This will not invoke any constructors,
3767 * so the consumer of this routine has to invoke any constructors on
3768 * its own to initialize the object.
3771 mono_object_new (MonoDomain *domain, MonoClass *klass)
3773 MONO_ARCH_SAVE_REGS;
3774 return mono_object_new_specific (mono_class_vtable (domain, klass));
3778 * mono_object_new_specific:
3779 * @vtable: the vtable of the object that we want to create
3781 * Returns: A newly created object with class and domain specified
3785 mono_object_new_specific (MonoVTable *vtable)
3789 MONO_ARCH_SAVE_REGS;
3791 /* check for is_com_object for COM Interop */
3792 if (vtable->remote || vtable->klass->is_com_object)
3795 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3798 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3801 mono_class_init (klass);
3803 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3805 vtable->domain->create_proxy_for_type_method = im;
3808 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3810 o = mono_runtime_invoke (im, NULL, pa, NULL);
3811 if (o != NULL) return o;
3814 return mono_object_new_alloc_specific (vtable);
3818 mono_object_new_alloc_specific (MonoVTable *vtable)
3822 if (!vtable->klass->has_references) {
3823 o = mono_object_new_ptrfree (vtable);
3824 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3825 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3827 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3828 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3830 if (G_UNLIKELY (vtable->klass->has_finalize))
3831 mono_object_register_finalizer (o);
3833 if (G_UNLIKELY (profile_allocs))
3834 mono_profiler_allocation (o, vtable->klass);
3839 mono_object_new_fast (MonoVTable *vtable)
3842 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3847 mono_object_new_ptrfree (MonoVTable *vtable)
3850 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3851 #if NEED_TO_ZERO_PTRFREE
3852 /* an inline memset is much faster for the common vcase of small objects
3853 * note we assume the allocated size is a multiple of sizeof (void*).
3855 if (vtable->klass->instance_size < 128) {
3857 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3858 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3864 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3871 mono_object_new_ptrfree_box (MonoVTable *vtable)
3874 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3875 /* the object will be boxed right away, no need to memzero it */
3880 * mono_class_get_allocation_ftn:
3882 * @for_box: the object will be used for boxing
3883 * @pass_size_in_words:
3885 * Return the allocation function appropriate for the given class.
3889 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3891 *pass_size_in_words = FALSE;
3893 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3894 profile_allocs = FALSE;
3896 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3897 return mono_object_new_specific;
3899 if (!vtable->klass->has_references) {
3900 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3902 return mono_object_new_ptrfree_box;
3903 return mono_object_new_ptrfree;
3906 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3908 return mono_object_new_fast;
3911 * FIXME: This is actually slower than mono_object_new_fast, because
3912 * of the overhead of parameter passing.
3915 *pass_size_in_words = TRUE;
3916 #ifdef GC_REDIRECT_TO_LOCAL
3917 return GC_local_gcj_fast_malloc;
3919 return GC_gcj_fast_malloc;
3924 return mono_object_new_specific;
3928 * mono_object_new_from_token:
3929 * @image: Context where the type_token is hosted
3930 * @token: a token of the type that we want to create
3932 * Returns: A newly created object whose definition is
3933 * looked up using @token in the @image image
3936 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3940 class = mono_class_get (image, token);
3942 return mono_object_new (domain, class);
3947 * mono_object_clone:
3948 * @obj: the object to clone
3950 * Returns: A newly created object who is a shallow copy of @obj
3953 mono_object_clone (MonoObject *obj)
3958 size = obj->vtable->klass->instance_size;
3959 o = mono_object_allocate (size, obj->vtable);
3960 /* do not copy the sync state */
3961 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3964 if (obj->vtable->klass->has_references)
3965 mono_gc_wbarrier_object (o);
3967 if (G_UNLIKELY (profile_allocs))
3968 mono_profiler_allocation (o, obj->vtable->klass);
3970 if (obj->vtable->klass->has_finalize)
3971 mono_object_register_finalizer (o);
3976 * mono_array_full_copy:
3977 * @src: source array to copy
3978 * @dest: destination array
3980 * Copies the content of one array to another with exactly the same type and size.
3983 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3985 mono_array_size_t size;
3986 MonoClass *klass = src->obj.vtable->klass;
3988 MONO_ARCH_SAVE_REGS;
3990 g_assert (klass == dest->obj.vtable->klass);
3992 size = mono_array_length (src);
3993 g_assert (size == mono_array_length (dest));
3994 size *= mono_array_element_size (klass);
3996 if (klass->element_class->valuetype) {
3997 if (klass->element_class->has_references)
3998 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4000 memcpy (&dest->vector, &src->vector, size);
4002 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4005 memcpy (&dest->vector, &src->vector, size);
4010 * mono_array_clone_in_domain:
4011 * @domain: the domain in which the array will be cloned into
4012 * @array: the array to clone
4014 * This routine returns a copy of the array that is hosted on the
4015 * specified MonoDomain.
4018 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4021 mono_array_size_t size, i;
4022 mono_array_size_t *sizes;
4023 MonoClass *klass = array->obj.vtable->klass;
4025 MONO_ARCH_SAVE_REGS;
4027 if (array->bounds == NULL) {
4028 size = mono_array_length (array);
4029 o = mono_array_new_full (domain, klass, &size, NULL);
4031 size *= mono_array_element_size (klass);
4033 if (klass->element_class->valuetype) {
4034 if (klass->element_class->has_references)
4035 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4037 memcpy (&o->vector, &array->vector, size);
4039 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4042 memcpy (&o->vector, &array->vector, size);
4047 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4048 size = mono_array_element_size (klass);
4049 for (i = 0; i < klass->rank; ++i) {
4050 sizes [i] = array->bounds [i].length;
4051 size *= array->bounds [i].length;
4052 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4054 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4056 if (klass->element_class->valuetype) {
4057 if (klass->element_class->has_references)
4058 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4060 memcpy (&o->vector, &array->vector, size);
4062 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4065 memcpy (&o->vector, &array->vector, size);
4073 * @array: the array to clone
4075 * Returns: A newly created array who is a shallow copy of @array
4078 mono_array_clone (MonoArray *array)
4080 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4083 /* helper macros to check for overflow when calculating the size of arrays */
4084 #ifdef MONO_BIG_ARRAYS
4085 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4086 #define MYGUINT_MAX MYGUINT64_MAX
4087 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4088 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4089 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4090 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4091 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4093 #define MYGUINT32_MAX 4294967295U
4094 #define MYGUINT_MAX MYGUINT32_MAX
4095 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4096 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4097 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4098 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4099 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4103 * mono_array_new_full:
4104 * @domain: domain where the object is created
4105 * @array_class: array class
4106 * @lengths: lengths for each dimension in the array
4107 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4109 * This routine creates a new array objects with the given dimensions,
4110 * lower bounds and type.
4113 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4115 mono_array_size_t byte_len, len, bounds_size;
4121 if (!array_class->inited)
4122 mono_class_init (array_class);
4124 byte_len = mono_array_element_size (array_class);
4127 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4128 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4130 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4134 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4136 for (i = 0; i < array_class->rank; ++i) {
4137 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4139 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4140 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4145 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4146 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4148 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4149 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4150 byte_len += sizeof (MonoArray);
4153 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4154 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4155 byte_len = (byte_len + 3) & ~3;
4156 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4157 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4158 byte_len += bounds_size;
4161 * Following three lines almost taken from mono_object_new ():
4162 * they need to be kept in sync.
4164 vtable = mono_class_vtable (domain, array_class);
4165 if (!array_class->has_references) {
4166 o = mono_object_allocate_ptrfree (byte_len, vtable);
4167 #if NEED_TO_ZERO_PTRFREE
4168 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4170 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4171 o = mono_object_allocate_spec (byte_len, vtable);
4173 o = mono_object_allocate (byte_len, vtable);
4176 array = (MonoArray*)o;
4177 array->max_length = len;
4180 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4181 array->bounds = bounds;
4182 for (i = 0; i < array_class->rank; ++i) {
4183 bounds [i].length = lengths [i];
4185 bounds [i].lower_bound = lower_bounds [i];
4189 if (G_UNLIKELY (profile_allocs))
4190 mono_profiler_allocation (o, array_class);
4197 * @domain: domain where the object is created
4198 * @eclass: element class
4199 * @n: number of array elements
4201 * This routine creates a new szarray with @n elements of type @eclass.
4204 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4208 MONO_ARCH_SAVE_REGS;
4210 ac = mono_array_class_get (eclass, 1);
4213 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
4217 * mono_array_new_specific:
4218 * @vtable: a vtable in the appropriate domain for an initialized class
4219 * @n: number of array elements
4221 * This routine is a fast alternative to mono_array_new() for code which
4222 * can be sure about the domain it operates in.
4225 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4229 guint32 byte_len, elem_size;
4231 MONO_ARCH_SAVE_REGS;
4233 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4238 elem_size = mono_array_element_size (vtable->klass);
4239 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4240 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4243 byte_len = n * elem_size;
4244 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4245 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4248 byte_len += sizeof (MonoArray);
4249 if (!vtable->klass->has_references) {
4250 o = mono_object_allocate_ptrfree (byte_len, vtable);
4251 #if NEED_TO_ZERO_PTRFREE
4252 ((MonoArray*)o)->bounds = NULL;
4253 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4255 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4256 o = mono_object_allocate_spec (byte_len, vtable);
4258 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4259 o = mono_object_allocate (byte_len, vtable);
4262 ao = (MonoArray *)o;
4264 if (G_UNLIKELY (profile_allocs))
4265 mono_profiler_allocation (o, vtable->klass);
4271 * mono_string_new_utf16:
4272 * @text: a pointer to an utf16 string
4273 * @len: the length of the string
4275 * Returns: A newly created string object which contains @text.
4278 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4282 s = mono_string_new_size (domain, len);
4283 g_assert (s != NULL);
4285 memcpy (mono_string_chars (s), text, len * 2);
4291 * mono_string_new_size:
4292 * @text: a pointer to an utf16 string
4293 * @len: the length of the string
4295 * Returns: A newly created string object of @len
4298 mono_string_new_size (MonoDomain *domain, gint32 len)
4302 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4304 /* overflow ? can't fit it, can't allocate it! */
4306 mono_gc_out_of_memory (-1);
4308 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4310 s = mono_object_allocate_ptrfree (size, vtable);
4313 #if NEED_TO_ZERO_PTRFREE
4316 if (G_UNLIKELY (profile_allocs))
4317 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4323 * mono_string_new_len:
4324 * @text: a pointer to an utf8 string
4325 * @length: number of bytes in @text to consider
4327 * Returns: A newly created string object which contains @text.
4330 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4332 GError *error = NULL;
4333 MonoString *o = NULL;
4335 glong items_written;
4337 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4340 o = mono_string_new_utf16 (domain, ut, items_written);
4342 g_error_free (error);
4351 * @text: a pointer to an utf8 string
4353 * Returns: A newly created string object which contains @text.
4356 mono_string_new (MonoDomain *domain, const char *text)
4358 GError *error = NULL;
4359 MonoString *o = NULL;
4361 glong items_written;
4366 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4369 o = mono_string_new_utf16 (domain, ut, items_written);
4371 g_error_free (error);
4374 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4379 MonoString *o = NULL;
4381 if (!g_utf8_validate (text, -1, &end))
4384 len = g_utf8_strlen (text, -1);
4385 o = mono_string_new_size (domain, len);
4386 str = mono_string_chars (o);
4388 while (text < end) {
4389 *str++ = g_utf8_get_char (text);
4390 text = g_utf8_next_char (text);
4397 * mono_string_new_wrapper:
4398 * @text: pointer to utf8 characters.
4400 * Helper function to create a string object from @text in the current domain.
4403 mono_string_new_wrapper (const char *text)
4405 MonoDomain *domain = mono_domain_get ();
4407 MONO_ARCH_SAVE_REGS;
4410 return mono_string_new (domain, text);
4417 * @class: the class of the value
4418 * @value: a pointer to the unboxed data
4420 * Returns: A newly created object which contains @value.
4423 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4429 g_assert (class->valuetype);
4430 if (mono_class_is_nullable (class))
4431 return mono_nullable_box (value, class);
4433 vtable = mono_class_vtable (domain, class);
4434 size = mono_class_instance_size (class);
4435 res = mono_object_new_alloc_specific (vtable);
4436 if (G_UNLIKELY (profile_allocs))
4437 mono_profiler_allocation (res, class);
4439 size = size - sizeof (MonoObject);
4442 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4445 #if NO_UNALIGNED_ACCESS
4446 memcpy ((char *)res + sizeof (MonoObject), value, size);
4450 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4453 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4456 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4459 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4462 memcpy ((char *)res + sizeof (MonoObject), value, size);
4465 if (class->has_finalize)
4466 mono_object_register_finalizer (res);
4472 * @dest: destination pointer
4473 * @src: source pointer
4474 * @klass: a valuetype class
4476 * Copy a valuetype from @src to @dest. This function must be used
4477 * when @klass contains references fields.
4480 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4482 int size = mono_class_value_size (klass, NULL);
4483 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4484 memcpy (dest, src, size);
4488 * mono_value_copy_array:
4489 * @dest: destination array
4490 * @dest_idx: index in the @dest array
4491 * @src: source pointer
4492 * @count: number of items
4494 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4495 * This function must be used when @klass contains references fields.
4496 * Overlap is handled.
4499 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4501 int size = mono_array_element_size (dest->obj.vtable->klass);
4502 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4503 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4504 memmove (d, src, size * count);
4508 * mono_object_get_domain:
4509 * @obj: object to query
4511 * Returns: the MonoDomain where the object is hosted
4514 mono_object_get_domain (MonoObject *obj)
4516 return mono_object_domain (obj);
4520 * mono_object_get_class:
4521 * @obj: object to query
4523 * Returns: the MonOClass of the object.
4526 mono_object_get_class (MonoObject *obj)
4528 return mono_object_class (obj);
4531 * mono_object_get_size:
4532 * @o: object to query
4534 * Returns: the size, in bytes, of @o
4537 mono_object_get_size (MonoObject* o)
4539 MonoClass* klass = mono_object_class (o);
4540 if (klass == mono_defaults.string_class) {
4541 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4542 } else if (o->vtable->rank) {
4543 MonoArray *array = (MonoArray*)o;
4544 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4545 if (array->bounds) {
4548 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4552 return mono_class_instance_size (klass);
4557 * mono_object_unbox:
4558 * @obj: object to unbox
4560 * Returns: a pointer to the start of the valuetype boxed in this
4563 * This method will assert if the object passed is not a valuetype.
4566 mono_object_unbox (MonoObject *obj)
4568 /* add assert for valuetypes? */
4569 g_assert (obj->vtable->klass->valuetype);
4570 return ((char*)obj) + sizeof (MonoObject);
4574 * mono_object_isinst:
4576 * @klass: a pointer to a class
4578 * Returns: @obj if @obj is derived from @klass
4581 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4584 mono_class_init (klass);
4586 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4587 return mono_object_isinst_mbyref (obj, klass);
4592 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4596 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4605 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4606 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4610 MonoClass *oklass = vt->klass;
4611 if ((oklass == mono_defaults.transparent_proxy_class))
4612 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4614 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4618 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4620 MonoDomain *domain = mono_domain_get ();
4622 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4623 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4624 MonoMethod *im = NULL;
4627 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4628 im = mono_object_get_virtual_method (rp, im);
4631 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4634 res = mono_runtime_invoke (im, rp, pa, NULL);
4636 if (*(MonoBoolean *) mono_object_unbox(res)) {
4637 /* Update the vtable of the remote type, so it can safely cast to this new type */
4638 mono_upgrade_remote_class (domain, obj, klass);
4647 * mono_object_castclass_mbyref:
4649 * @klass: a pointer to a class
4651 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4654 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4656 if (!obj) return NULL;
4657 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4659 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4661 "InvalidCastException"));
4666 MonoDomain *orig_domain;
4672 str_lookup (MonoDomain *domain, gpointer user_data)
4674 LDStrInfo *info = user_data;
4675 if (info->res || domain == info->orig_domain)
4677 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4683 mono_string_get_pinned (MonoString *str)
4687 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4688 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4689 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4690 news->length = mono_string_length (str);
4695 #define mono_string_get_pinned(str) (str)
4699 mono_string_is_interned_lookup (MonoString *str, int insert)
4701 MonoGHashTable *ldstr_table;
4705 domain = ((MonoObject *)str)->vtable->domain;
4706 ldstr_table = domain->ldstr_table;
4708 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4713 str = mono_string_get_pinned (str);
4714 mono_g_hash_table_insert (ldstr_table, str, str);
4718 LDStrInfo ldstr_info;
4719 ldstr_info.orig_domain = domain;
4720 ldstr_info.ins = str;
4721 ldstr_info.res = NULL;
4723 mono_domain_foreach (str_lookup, &ldstr_info);
4724 if (ldstr_info.res) {
4726 * the string was already interned in some other domain:
4727 * intern it in the current one as well.
4729 mono_g_hash_table_insert (ldstr_table, str, str);
4739 * mono_string_is_interned:
4740 * @o: String to probe
4742 * Returns whether the string has been interned.
4745 mono_string_is_interned (MonoString *o)
4747 return mono_string_is_interned_lookup (o, FALSE);
4751 * mono_string_intern:
4752 * @o: String to intern
4754 * Interns the string passed.
4755 * Returns: The interned string.
4758 mono_string_intern (MonoString *str)
4760 return mono_string_is_interned_lookup (str, TRUE);
4765 * @domain: the domain where the string will be used.
4766 * @image: a metadata context
4767 * @idx: index into the user string table.
4769 * Implementation for the ldstr opcode.
4770 * Returns: a loaded string from the @image/@idx combination.
4773 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4775 MONO_ARCH_SAVE_REGS;
4778 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4780 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4784 * mono_ldstr_metadata_sig
4785 * @domain: the domain for the string
4786 * @sig: the signature of a metadata string
4788 * Returns: a MonoString for a string stored in the metadata
4791 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4793 const char *str = sig;
4794 MonoString *o, *interned;
4797 len2 = mono_metadata_decode_blob_size (str, &str);
4800 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4801 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4804 guint16 *p2 = (guint16*)mono_string_chars (o);
4805 for (i = 0; i < len2; ++i) {
4806 *p2 = GUINT16_FROM_LE (*p2);
4812 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4814 /* o will get garbage collected */
4818 o = mono_string_get_pinned (o);
4819 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4826 * mono_string_to_utf8:
4827 * @s: a System.String
4829 * Return the UTF8 representation for @s.
4830 * the resulting buffer nedds to be freed with g_free().
4833 mono_string_to_utf8 (MonoString *s)
4837 GError *error = NULL;
4843 return g_strdup ("");
4845 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4847 MonoException *exc = mono_get_exception_argument ("string", error->message);
4848 g_error_free (error);
4849 mono_raise_exception(exc);
4851 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4852 if (s->length > written) {
4853 /* allocate the total length and copy the part of the string that has been converted */
4854 char *as2 = g_malloc0 (s->length);
4855 memcpy (as2, as, written);
4864 * mono_string_to_utf16:
4867 * Return an null-terminated array of the utf-16 chars
4868 * contained in @s. The result must be freed with g_free().
4869 * This is a temporary helper until our string implementation
4870 * is reworked to always include the null terminating char.
4873 mono_string_to_utf16 (MonoString *s)
4880 as = g_malloc ((s->length * 2) + 2);
4881 as [(s->length * 2)] = '\0';
4882 as [(s->length * 2) + 1] = '\0';
4885 return (gunichar2 *)(as);
4888 memcpy (as, mono_string_chars(s), s->length * 2);
4889 return (gunichar2 *)(as);
4893 * mono_string_from_utf16:
4894 * @data: the UTF16 string (LPWSTR) to convert
4896 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4898 * Returns: a MonoString.
4901 mono_string_from_utf16 (gunichar2 *data)
4903 MonoDomain *domain = mono_domain_get ();
4909 while (data [len]) len++;
4911 return mono_string_new_utf16 (domain, data, len);
4916 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4923 return mono_string_to_utf8 (s);
4925 r = mono_string_to_utf8 (s);
4929 len = strlen (r) + 1;
4931 mp_s = mono_mempool_alloc (mp, len);
4933 mp_s = mono_image_alloc (image, len);
4935 memcpy (mp_s, r, len);
4943 * mono_string_to_utf8_image:
4944 * @s: a System.String
4946 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
4949 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
4951 return mono_string_to_utf8_internal (NULL, image, s);
4955 * mono_string_to_utf8_mp:
4956 * @s: a System.String
4958 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4961 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4963 return mono_string_to_utf8_internal (mp, NULL, s);
4967 default_ex_handler (MonoException *ex)
4969 MonoObject *o = (MonoObject*)ex;
4970 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4974 static MonoExceptionFunc ex_handler = default_ex_handler;
4977 * mono_install_handler:
4978 * @func: exception handler
4980 * This is an internal JIT routine used to install the handler for exceptions
4984 mono_install_handler (MonoExceptionFunc func)
4986 ex_handler = func? func: default_ex_handler;
4990 * mono_raise_exception:
4991 * @ex: exception object
4993 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4996 mono_raise_exception (MonoException *ex)
4999 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5000 * that will cause gcc to omit the function epilog, causing problems when
5001 * the JIT tries to walk the stack, since the return address on the stack
5002 * will point into the next function in the executable, not this one.
5005 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5006 MonoThread *thread = mono_thread_current ();
5007 g_assert (ex->object.vtable->domain == mono_domain_get ());
5008 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5015 * mono_wait_handle_new:
5016 * @domain: Domain where the object will be created
5017 * @handle: Handle for the wait handle
5019 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5022 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5024 MonoWaitHandle *res;
5025 gpointer params [1];
5026 static MonoMethod *handle_set;
5028 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
5030 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5032 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
5034 params [0] = &handle;
5035 mono_runtime_invoke (handle_set, res, params, NULL);
5041 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5043 static MonoClassField *f_os_handle;
5044 static MonoClassField *f_safe_handle;
5046 if (!f_os_handle && !f_safe_handle) {
5047 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
5048 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
5053 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5057 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5064 mono_runtime_capture_context (MonoDomain *domain)
5066 RuntimeInvokeFunction runtime_invoke;
5068 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5069 MonoMethod *method = mono_get_context_capture_method ();
5070 MonoMethod *wrapper;
5073 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5074 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5075 domain->capture_context_method = mono_compile_method (method);
5078 runtime_invoke = domain->capture_context_runtime_invoke;
5080 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5083 * mono_async_result_new:
5084 * @domain:domain where the object will be created.
5085 * @handle: wait handle.
5086 * @state: state to pass to AsyncResult
5087 * @data: C closure data.
5089 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5090 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5094 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5096 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5097 MonoObject *context = mono_runtime_capture_context (domain);
5098 /* we must capture the execution context from the original thread */
5100 MONO_OBJECT_SETREF (res, execution_context, context);
5101 /* note: result may be null if the flow is suppressed */
5105 MONO_OBJECT_SETREF (res, object_data, object_data);
5106 MONO_OBJECT_SETREF (res, async_state, state);
5108 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5110 res->sync_completed = FALSE;
5111 res->completed = FALSE;
5117 mono_message_init (MonoDomain *domain,
5118 MonoMethodMessage *this,
5119 MonoReflectionMethod *method,
5120 MonoArray *out_args)
5122 static MonoClass *object_array_klass;
5123 static MonoClass *byte_array_klass;
5124 static MonoClass *string_array_klass;
5125 MonoMethodSignature *sig = mono_method_signature (method->method);
5131 if (!object_array_klass) {
5134 klass = mono_array_class_get (mono_defaults.object_class, 1);
5137 mono_memory_barrier ();
5138 object_array_klass = klass;
5140 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5143 mono_memory_barrier ();
5144 byte_array_klass = klass;
5146 klass = mono_array_class_get (mono_defaults.string_class, 1);
5149 mono_memory_barrier ();
5150 string_array_klass = klass;
5153 MONO_OBJECT_SETREF (this, method, method);
5155 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5156 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5157 this->async_result = NULL;
5158 this->call_type = CallType_Sync;
5160 names = g_new (char *, sig->param_count);
5161 mono_method_get_param_names (method->method, (const char **) names);
5162 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5164 for (i = 0; i < sig->param_count; i++) {
5165 name = mono_string_new (domain, names [i]);
5166 mono_array_setref (this->names, i, name);
5170 for (i = 0, j = 0; i < sig->param_count; i++) {
5171 if (sig->params [i]->byref) {
5173 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5174 mono_array_setref (this->args, i, arg);
5178 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5182 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5185 mono_array_set (this->arg_types, guint8, i, arg_type);
5190 * mono_remoting_invoke:
5191 * @real_proxy: pointer to a RealProxy object
5192 * @msg: The MonoMethodMessage to execute
5193 * @exc: used to store exceptions
5194 * @out_args: used to store output arguments
5196 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5197 * IMessage interface and it is not trivial to extract results from there. So
5198 * we call an helper method PrivateInvoke instead of calling
5199 * RealProxy::Invoke() directly.
5201 * Returns: the result object.
5204 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5205 MonoObject **exc, MonoArray **out_args)
5207 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5210 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5213 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5215 real_proxy->vtable->domain->private_invoke_method = im;
5218 pa [0] = real_proxy;
5223 return mono_runtime_invoke (im, NULL, pa, exc);
5227 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5228 MonoObject **exc, MonoArray **out_args)
5230 static MonoClass *object_array_klass;
5233 MonoMethodSignature *sig;
5235 int i, j, outarg_count = 0;
5237 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5239 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5240 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5241 target = tp->rp->unwrapped_server;
5243 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5247 domain = mono_domain_get ();
5248 method = msg->method->method;
5249 sig = mono_method_signature (method);
5251 for (i = 0; i < sig->param_count; i++) {
5252 if (sig->params [i]->byref)
5256 if (!object_array_klass) {
5259 klass = mono_array_class_get (mono_defaults.object_class, 1);
5262 mono_memory_barrier ();
5263 object_array_klass = klass;
5266 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5267 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5270 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5272 for (i = 0, j = 0; i < sig->param_count; i++) {
5273 if (sig->params [i]->byref) {
5275 arg = mono_array_get (msg->args, gpointer, i);
5276 mono_array_setref (*out_args, j, arg);
5285 * mono_print_unhandled_exception:
5286 * @exc: The exception
5288 * Prints the unhandled exception.
5291 mono_print_unhandled_exception (MonoObject *exc)
5293 char *message = (char *) "";
5297 gboolean free_message = FALSE;
5299 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5300 klass = exc->vtable->klass;
5302 while (klass && method == NULL) {
5303 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5305 klass = klass->parent;
5310 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5312 message = mono_string_to_utf8 (str);
5313 free_message = TRUE;
5318 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5319 * exc->vtable->klass->name, message);
5321 g_printerr ("\nUnhandled Exception: %s\n", message);
5328 * mono_delegate_ctor:
5329 * @this: pointer to an uninitialized delegate object
5330 * @target: target object
5331 * @addr: pointer to native code
5334 * Initialize a delegate and sets a specific method, not the one
5335 * associated with addr. This is useful when sharing generic code.
5336 * In that case addr will most probably not be associated with the
5337 * correct instantiation of the method.
5340 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5342 MonoDelegate *delegate = (MonoDelegate *)this;
5349 delegate->method = method;
5351 class = this->vtable->klass;
5352 mono_stats.delegate_creations++;
5354 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5356 method = mono_marshal_get_remoting_invoke (method);
5357 delegate->method_ptr = mono_compile_method (method);
5358 MONO_OBJECT_SETREF (delegate, target, target);
5359 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
5360 method = mono_marshal_get_unbox_wrapper (method);
5361 delegate->method_ptr = mono_compile_method (method);
5362 MONO_OBJECT_SETREF (delegate, target, target);
5364 delegate->method_ptr = addr;
5365 MONO_OBJECT_SETREF (delegate, target, target);
5368 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5372 * mono_delegate_ctor:
5373 * @this: pointer to an uninitialized delegate object
5374 * @target: target object
5375 * @addr: pointer to native code
5377 * This is used to initialize a delegate.
5380 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5382 MonoDomain *domain = mono_domain_get ();
5384 MonoMethod *method = NULL;
5388 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5389 method = ji->method;
5390 g_assert (!method->klass->generic_container);
5393 mono_delegate_ctor_with_method (this, target, addr, method);
5397 * mono_method_call_message_new:
5398 * @method: method to encapsulate
5399 * @params: parameters to the method
5400 * @invoke: optional, delegate invoke.
5401 * @cb: async callback delegate.
5402 * @state: state passed to the async callback.
5404 * Translates arguments pointers into a MonoMethodMessage.
5407 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5408 MonoDelegate **cb, MonoObject **state)
5410 MonoDomain *domain = mono_domain_get ();
5411 MonoMethodSignature *sig = mono_method_signature (method);
5412 MonoMethodMessage *msg;
5415 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5418 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5419 count = sig->param_count - 2;
5421 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5422 count = sig->param_count;
5425 for (i = 0; i < count; i++) {
5430 if (sig->params [i]->byref)
5431 vpos = *((gpointer *)params [i]);
5435 type = sig->params [i]->type;
5436 class = mono_class_from_mono_type (sig->params [i]);
5438 if (class->valuetype)
5439 arg = mono_value_box (domain, class, vpos);
5441 arg = *((MonoObject **)vpos);
5443 mono_array_setref (msg->args, i, arg);
5446 if (cb != NULL && state != NULL) {
5447 *cb = *((MonoDelegate **)params [i]);
5449 *state = *((MonoObject **)params [i]);
5456 * mono_method_return_message_restore:
5458 * Restore results from message based processing back to arguments pointers
5461 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5463 MonoMethodSignature *sig = mono_method_signature (method);
5464 int i, j, type, size, out_len;
5466 if (out_args == NULL)
5468 out_len = mono_array_length (out_args);
5472 for (i = 0, j = 0; i < sig->param_count; i++) {
5473 MonoType *pt = sig->params [i];
5478 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5480 arg = mono_array_get (out_args, gpointer, j);
5484 case MONO_TYPE_VOID:
5485 g_assert_not_reached ();
5489 case MONO_TYPE_BOOLEAN:
5492 case MONO_TYPE_CHAR:
5499 case MONO_TYPE_VALUETYPE: {
5501 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5502 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5505 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5506 memset (*((gpointer *)params [i]), 0, size);
5510 case MONO_TYPE_STRING:
5511 case MONO_TYPE_CLASS:
5512 case MONO_TYPE_ARRAY:
5513 case MONO_TYPE_SZARRAY:
5514 case MONO_TYPE_OBJECT:
5515 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5518 g_assert_not_reached ();
5527 * mono_load_remote_field:
5528 * @this: pointer to an object
5529 * @klass: klass of the object containing @field
5530 * @field: the field to load
5531 * @res: a storage to store the result
5533 * This method is called by the runtime on attempts to load fields of
5534 * transparent proxy objects. @this points to such TP, @klass is the class of
5535 * the object containing @field. @res is a storage location which can be
5536 * used to store the result.
5538 * Returns: an address pointing to the value of field.
5541 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5543 static MonoMethod *getter = NULL;
5544 MonoDomain *domain = mono_domain_get ();
5545 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5546 MonoClass *field_class;
5547 MonoMethodMessage *msg;
5548 MonoArray *out_args;
5552 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5553 g_assert (res != NULL);
5555 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5556 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5561 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5565 field_class = mono_class_from_mono_type (field->type);
5567 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5568 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5569 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5571 full_name = mono_type_get_full_name (klass);
5572 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5573 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5576 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5578 if (exc) mono_raise_exception ((MonoException *)exc);
5580 if (mono_array_length (out_args) == 0)
5583 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5585 if (field_class->valuetype) {
5586 return ((char *)*res) + sizeof (MonoObject);
5592 * mono_load_remote_field_new:
5597 * Missing documentation.
5600 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5602 static MonoMethod *getter = NULL;
5603 MonoDomain *domain = mono_domain_get ();
5604 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5605 MonoClass *field_class;
5606 MonoMethodMessage *msg;
5607 MonoArray *out_args;
5608 MonoObject *exc, *res;
5611 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5613 field_class = mono_class_from_mono_type (field->type);
5615 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5617 if (field_class->valuetype) {
5618 res = mono_object_new (domain, field_class);
5619 val = ((gchar *) res) + sizeof (MonoObject);
5623 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5628 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5632 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5633 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5635 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5637 full_name = mono_type_get_full_name (klass);
5638 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5639 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5642 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5644 if (exc) mono_raise_exception ((MonoException *)exc);
5646 if (mono_array_length (out_args) == 0)
5649 res = mono_array_get (out_args, MonoObject *, 0);
5655 * mono_store_remote_field:
5656 * @this: pointer to an object
5657 * @klass: klass of the object containing @field
5658 * @field: the field to load
5659 * @val: the value/object to store
5661 * This method is called by the runtime on attempts to store fields of
5662 * transparent proxy objects. @this points to such TP, @klass is the class of
5663 * the object containing @field. @val is the new value to store in @field.
5666 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5668 static MonoMethod *setter = NULL;
5669 MonoDomain *domain = mono_domain_get ();
5670 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5671 MonoClass *field_class;
5672 MonoMethodMessage *msg;
5673 MonoArray *out_args;
5678 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5680 field_class = mono_class_from_mono_type (field->type);
5682 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5683 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5684 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5689 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5693 if (field_class->valuetype)
5694 arg = mono_value_box (domain, field_class, val);
5696 arg = *((MonoObject **)val);
5699 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5700 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5702 full_name = mono_type_get_full_name (klass);
5703 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5704 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5705 mono_array_setref (msg->args, 2, arg);
5708 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5710 if (exc) mono_raise_exception ((MonoException *)exc);
5714 * mono_store_remote_field_new:
5720 * Missing documentation
5723 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5725 static MonoMethod *setter = NULL;
5726 MonoDomain *domain = mono_domain_get ();
5727 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5728 MonoClass *field_class;
5729 MonoMethodMessage *msg;
5730 MonoArray *out_args;
5734 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5736 field_class = mono_class_from_mono_type (field->type);
5738 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5739 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5740 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5745 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5749 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5750 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5752 full_name = mono_type_get_full_name (klass);
5753 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5754 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5755 mono_array_setref (msg->args, 2, arg);
5758 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5760 if (exc) mono_raise_exception ((MonoException *)exc);
5764 * mono_create_ftnptr:
5766 * Given a function address, create a function descriptor for it.
5767 * This is only needed on some platforms.
5770 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5772 return callbacks.create_ftnptr (domain, addr);
5776 * mono_get_addr_from_ftnptr:
5778 * Given a pointer to a function descriptor, return the function address.
5779 * This is only needed on some platforms.
5782 mono_get_addr_from_ftnptr (gpointer descr)
5784 return callbacks.get_addr_from_ftnptr (descr);
5789 * mono_string_chars:
5792 * Returns a pointer to the UCS16 characters stored in the MonoString
5795 mono_string_chars(MonoString *s)
5797 /* This method is here only for documentation extraction, this is a macro */
5801 * mono_string_length:
5804 * Returns the lenght in characters of the string
5807 mono_string_length (MonoString *s)
5809 /* This method is here only for documentation extraction, this is a macro */