2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include "cominterop.h"
46 #define NEED_TO_ZERO_PTRFREE 1
47 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
48 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
49 #ifdef HAVE_GC_GCJ_MALLOC
50 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
51 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
53 #define GC_NO_DESCRIPTOR (NULL)
54 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
58 #define GC_NO_DESCRIPTOR (NULL)
59 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
61 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
63 #define NEED_TO_ZERO_PTRFREE 1
64 #define GC_NO_DESCRIPTOR (NULL)
65 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
66 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
67 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
71 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
72 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
75 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
78 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
80 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
81 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
82 static CRITICAL_SECTION ldstr_section;
84 static gboolean profile_allocs = TRUE;
87 mono_runtime_object_init (MonoObject *this)
89 MonoMethod *method = NULL;
90 MonoClass *klass = this->vtable->klass;
92 method = mono_class_get_method_from_name (klass, ".ctor", 0);
95 if (method->klass->valuetype)
96 this = mono_object_unbox (this);
97 mono_runtime_invoke (method, this, NULL, NULL);
100 /* The pseudo algorithm for type initialization from the spec
101 Note it doesn't say anything about domains - only threads.
103 2. If the type is initialized you are done.
104 2.1. If the type is not yet initialized, try to take an
106 2.2. If successful, record this thread as responsible for
107 initializing the type and proceed to step 2.3.
108 2.2.1. If not, see whether this thread or any thread
109 waiting for this thread to complete already holds the lock.
110 2.2.2. If so, return since blocking would create a deadlock. This thread
111 will now see an incompletely initialized state for the type,
112 but no deadlock will arise.
113 2.2.3 If not, block until the type is initialized then return.
114 2.3 Initialize the parent type and then all interfaces implemented
116 2.4 Execute the type initialization code for this type.
117 2.5 Mark the type as initialized, release the initialization lock,
118 awaken any threads waiting for this type to be initialized,
125 guint32 initializing_tid;
126 guint32 waiting_count;
128 CRITICAL_SECTION initialization_section;
129 } TypeInitializationLock;
131 /* for locking access to type_initialization_hash and blocked_thread_hash */
132 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
133 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
134 static CRITICAL_SECTION type_initialization_section;
136 /* from vtable to lock */
137 static GHashTable *type_initialization_hash;
139 /* from thread id to thread id being waited on */
140 static GHashTable *blocked_thread_hash;
143 static MonoThread *main_thread;
145 /* Functions supplied by the runtime */
146 static MonoRuntimeCallbacks callbacks;
149 * mono_thread_set_main:
150 * @thread: thread to set as the main thread
152 * This function can be used to instruct the runtime to treat @thread
153 * as the main thread, ie, the thread that would normally execute the Main()
154 * method. This basically means that at the end of @thread, the runtime will
155 * wait for the existing foreground threads to quit and other such details.
158 mono_thread_set_main (MonoThread *thread)
160 main_thread = thread;
164 mono_thread_get_main (void)
170 mono_type_initialization_init (void)
172 InitializeCriticalSection (&type_initialization_section);
173 type_initialization_hash = g_hash_table_new (NULL, NULL);
174 blocked_thread_hash = g_hash_table_new (NULL, NULL);
175 InitializeCriticalSection (&ldstr_section);
179 mono_type_initialization_cleanup (void)
182 /* This is causing race conditions with
183 * mono_release_type_locks
185 DeleteCriticalSection (&type_initialization_section);
187 DeleteCriticalSection (&ldstr_section);
191 * get_type_init_exception_for_vtable:
193 * Return the stored type initialization exception for VTABLE.
195 static MonoException*
196 get_type_init_exception_for_vtable (MonoVTable *vtable)
198 MonoDomain *domain = vtable->domain;
199 MonoClass *klass = vtable->klass;
203 g_assert (vtable->init_failed);
206 * If the initializing thread was rudely aborted, the exception is not stored
210 mono_domain_lock (domain);
211 if (domain->type_init_exception_hash)
212 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
213 mono_domain_unlock (domain);
216 if (klass->name_space && *klass->name_space)
217 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
219 full_name = g_strdup (klass->name);
220 ex = mono_get_exception_type_initialization (full_name, NULL);
227 * mono_runtime_class_init:
228 * @vtable: vtable that needs to be initialized
230 * This routine calls the class constructor for @vtable.
233 mono_runtime_class_init (MonoVTable *vtable)
235 mono_runtime_class_init_full (vtable, TRUE);
239 * mono_runtime_class_init_full:
240 * @vtable that neeeds to be initialized
241 * @raise_exception is TRUE, exceptions are raised intead of returned
245 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
248 MonoException *exc_to_throw;
249 MonoMethod *method = NULL;
255 if (vtable->initialized)
259 klass = vtable->klass;
261 if (!klass->image->checked_module_cctor) {
262 mono_image_check_for_module_cctor (klass->image);
263 if (klass->image->has_module_cctor) {
264 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
265 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
268 mono_runtime_class_init (module_vtable);
271 method = mono_class_get_cctor (klass);
274 MonoDomain *domain = vtable->domain;
275 TypeInitializationLock *lock;
276 guint32 tid = GetCurrentThreadId();
277 int do_initialization = 0;
278 MonoDomain *last_domain = NULL;
280 mono_type_initialization_lock ();
281 /* double check... */
282 if (vtable->initialized) {
283 mono_type_initialization_unlock ();
286 if (vtable->init_failed) {
287 mono_type_initialization_unlock ();
289 /* The type initialization already failed once, rethrow the same exception */
291 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
292 return get_type_init_exception_for_vtable (vtable);
294 lock = g_hash_table_lookup (type_initialization_hash, vtable);
296 /* This thread will get to do the initialization */
297 if (mono_domain_get () != domain) {
298 /* Transfer into the target domain */
299 last_domain = mono_domain_get ();
300 if (!mono_domain_set (domain, FALSE)) {
301 vtable->initialized = 1;
302 mono_type_initialization_unlock ();
304 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
305 return mono_get_exception_appdomain_unloaded ();
308 lock = g_malloc (sizeof(TypeInitializationLock));
309 InitializeCriticalSection (&lock->initialization_section);
310 lock->initializing_tid = tid;
311 lock->waiting_count = 1;
313 /* grab the vtable lock while this thread still owns type_initialization_section */
314 EnterCriticalSection (&lock->initialization_section);
315 g_hash_table_insert (type_initialization_hash, vtable, lock);
316 do_initialization = 1;
319 TypeInitializationLock *pending_lock;
321 if (lock->initializing_tid == tid || lock->done) {
322 mono_type_initialization_unlock ();
325 /* see if the thread doing the initialization is already blocked on this thread */
326 blocked = GUINT_TO_POINTER (lock->initializing_tid);
327 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
328 if (pending_lock->initializing_tid == tid) {
329 if (!pending_lock->done) {
330 mono_type_initialization_unlock ();
333 /* the thread doing the initialization is blocked on this thread,
334 but on a lock that has already been freed. It just hasn't got
339 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
341 ++lock->waiting_count;
342 /* record the fact that we are waiting on the initializing thread */
343 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
345 mono_type_initialization_unlock ();
347 if (do_initialization) {
348 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
350 /* If the initialization failed, mark the class as unusable. */
351 /* Avoid infinite loops */
353 (klass->image == mono_defaults.corlib &&
354 !strcmp (klass->name_space, "System") &&
355 !strcmp (klass->name, "TypeInitializationException")))) {
356 vtable->init_failed = 1;
358 if (klass->name_space && *klass->name_space)
359 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
361 full_name = g_strdup (klass->name);
362 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
366 * Store the exception object so it could be thrown on subsequent
369 mono_domain_lock (domain);
370 if (!domain->type_init_exception_hash)
371 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
372 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
373 mono_domain_unlock (domain);
377 mono_domain_set (last_domain, TRUE);
379 LeaveCriticalSection (&lock->initialization_section);
381 /* this just blocks until the initializing thread is done */
382 EnterCriticalSection (&lock->initialization_section);
383 LeaveCriticalSection (&lock->initialization_section);
386 mono_type_initialization_lock ();
387 if (lock->initializing_tid != tid)
388 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
389 --lock->waiting_count;
390 if (lock->waiting_count == 0) {
391 DeleteCriticalSection (&lock->initialization_section);
392 g_hash_table_remove (type_initialization_hash, vtable);
395 if (!vtable->init_failed)
396 vtable->initialized = 1;
397 mono_type_initialization_unlock ();
399 if (vtable->init_failed) {
400 /* Either we were the initializing thread or we waited for the initialization */
402 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
403 return get_type_init_exception_for_vtable (vtable);
406 vtable->initialized = 1;
413 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
415 MonoVTable *vtable = (MonoVTable*)key;
417 TypeInitializationLock *lock = (TypeInitializationLock*) value;
418 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
421 * Have to set this since it cannot be set by the normal code in
422 * mono_runtime_class_init (). In this case, the exception object is not stored,
423 * and get_type_init_exception_for_class () needs to be aware of this.
425 vtable->init_failed = 1;
426 LeaveCriticalSection (&lock->initialization_section);
427 --lock->waiting_count;
428 if (lock->waiting_count == 0) {
429 DeleteCriticalSection (&lock->initialization_section);
438 mono_release_type_locks (MonoInternalThread *thread)
440 mono_type_initialization_lock ();
441 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
442 mono_type_initialization_unlock ();
446 default_trampoline (MonoMethod *method)
452 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
454 g_assert_not_reached ();
460 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
462 g_error ("remoting not installed");
467 default_delegate_trampoline (MonoClass *klass)
469 g_assert_not_reached ();
473 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
474 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
475 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
476 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
477 static MonoImtThunkBuilder imt_thunk_builder = NULL;
478 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
479 #if (MONO_IMT_SIZE > 32)
480 #error "MONO_IMT_SIZE cannot be larger than 32"
484 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
486 memcpy (&callbacks, cbs, sizeof (*cbs));
489 MonoRuntimeCallbacks*
490 mono_get_runtime_callbacks (void)
496 mono_install_trampoline (MonoTrampoline func)
498 arch_create_jit_trampoline = func? func: default_trampoline;
502 mono_install_jump_trampoline (MonoJumpTrampoline func)
504 arch_create_jump_trampoline = func? func: default_jump_trampoline;
508 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
510 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
514 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
516 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
520 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
521 imt_thunk_builder = func;
524 static MonoCompileFunc default_mono_compile_method = NULL;
527 * mono_install_compile_method:
528 * @func: function to install
530 * This is a VM internal routine
533 mono_install_compile_method (MonoCompileFunc func)
535 default_mono_compile_method = func;
539 * mono_compile_method:
540 * @method: The method to compile.
542 * This JIT-compiles the method, and returns the pointer to the native code
546 mono_compile_method (MonoMethod *method)
548 if (!default_mono_compile_method) {
549 g_error ("compile method called on uninitialized runtime");
552 return default_mono_compile_method (method);
556 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
558 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
562 mono_runtime_create_delegate_trampoline (MonoClass *klass)
564 return arch_create_delegate_trampoline (klass);
567 static MonoFreeMethodFunc default_mono_free_method = NULL;
570 * mono_install_free_method:
571 * @func: pointer to the MonoFreeMethodFunc used to release a method
573 * This is an internal VM routine, it is used for the engines to
574 * register a handler to release the resources associated with a method.
576 * Methods are freed when no more references to the delegate that holds
580 mono_install_free_method (MonoFreeMethodFunc func)
582 default_mono_free_method = func;
586 * mono_runtime_free_method:
587 * @domain; domain where the method is hosted
588 * @method: method to release
590 * This routine is invoked to free the resources associated with
591 * a method that has been JIT compiled. This is used to discard
592 * methods that were used only temporarily (for example, used in marshalling)
596 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
598 if (default_mono_free_method != NULL)
599 default_mono_free_method (domain, method);
601 mono_method_clear_object (domain, method);
603 mono_free_method (method);
607 * The vtables in the root appdomain are assumed to be reachable by other
608 * roots, and we don't use typed allocation in the other domains.
611 /* The sync block is no longer a GC pointer */
612 #define GC_HEADER_BITMAP (0)
614 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
617 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
619 MonoClassField *field;
625 max_size = mono_class_data_size (class) / sizeof (gpointer);
627 max_size = class->instance_size / sizeof (gpointer);
628 if (max_size >= size) {
629 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
632 for (p = class; p != NULL; p = p->parent) {
633 gpointer iter = NULL;
634 while ((field = mono_class_get_fields (p, &iter))) {
638 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
640 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
643 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
646 /* FIXME: should not happen, flag as type load error */
647 if (field->type->byref)
650 if (static_fields && field->offset == -1)
654 pos = field->offset / sizeof (gpointer);
657 type = mono_type_get_underlying_type (field->type);
658 switch (type->type) {
661 case MONO_TYPE_FNPTR:
663 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
668 if (class->image != mono_defaults.corlib)
671 case MONO_TYPE_STRING:
672 case MONO_TYPE_SZARRAY:
673 case MONO_TYPE_CLASS:
674 case MONO_TYPE_OBJECT:
675 case MONO_TYPE_ARRAY:
676 g_assert ((field->offset % sizeof(gpointer)) == 0);
678 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
679 *max_set = MAX (*max_set, pos);
681 case MONO_TYPE_GENERICINST:
682 if (!mono_type_generic_inst_is_valuetype (type)) {
683 g_assert ((field->offset % sizeof(gpointer)) == 0);
685 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
686 *max_set = MAX (*max_set, pos);
691 case MONO_TYPE_VALUETYPE: {
692 MonoClass *fclass = mono_class_from_mono_type (field->type);
693 if (fclass->has_references) {
694 /* remove the object header */
695 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
709 case MONO_TYPE_BOOLEAN:
713 g_assert_not_reached ();
725 * similar to the above, but sets the bits in the bitmap for any non-ref field
726 * and ignores static fields
729 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
731 MonoClassField *field;
736 max_size = class->instance_size / sizeof (gpointer);
737 if (max_size >= size) {
738 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
741 for (p = class; p != NULL; p = p->parent) {
742 gpointer iter = NULL;
743 while ((field = mono_class_get_fields (p, &iter))) {
746 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
748 /* FIXME: should not happen, flag as type load error */
749 if (field->type->byref)
752 pos = field->offset / sizeof (gpointer);
755 type = mono_type_get_underlying_type (field->type);
756 switch (type->type) {
757 #if SIZEOF_VOID_P == 8
761 case MONO_TYPE_FNPTR:
766 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
767 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
768 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
771 #if SIZEOF_VOID_P == 4
775 case MONO_TYPE_FNPTR:
780 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
781 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
782 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
788 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
789 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
790 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
793 case MONO_TYPE_BOOLEAN:
796 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
798 case MONO_TYPE_STRING:
799 case MONO_TYPE_SZARRAY:
800 case MONO_TYPE_CLASS:
801 case MONO_TYPE_OBJECT:
802 case MONO_TYPE_ARRAY:
804 case MONO_TYPE_GENERICINST:
805 if (!mono_type_generic_inst_is_valuetype (type)) {
810 case MONO_TYPE_VALUETYPE: {
811 MonoClass *fclass = mono_class_from_mono_type (field->type);
812 /* remove the object header */
813 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
817 g_assert_not_reached ();
826 * mono_class_insecure_overlapping:
827 * check if a class with explicit layout has references and non-references
828 * fields overlapping.
830 * Returns: TRUE if it is insecure to load the type.
833 mono_class_insecure_overlapping (MonoClass *klass)
837 gsize default_bitmap [4] = {0};
839 gsize default_nrbitmap [4] = {0};
840 int i, insecure = FALSE;
843 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
844 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
846 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
847 int idx = i % (sizeof (bitmap [0]) * 8);
848 if (bitmap [idx] & nrbitmap [idx]) {
853 if (bitmap != default_bitmap)
855 if (nrbitmap != default_nrbitmap)
858 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
866 mono_string_alloc (int length)
868 return mono_string_new_size (mono_domain_get (), length);
872 mono_class_compute_gc_descriptor (MonoClass *class)
876 gsize default_bitmap [4] = {0};
877 static gboolean gcj_inited = FALSE;
882 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
883 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
884 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
885 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
887 #ifdef HAVE_GC_GCJ_MALLOC
889 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
893 #ifdef GC_REDIRECT_TO_LOCAL
894 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
895 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
897 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
898 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
903 mono_loader_unlock ();
907 mono_class_init (class);
909 if (class->gc_descr_inited)
912 class->gc_descr_inited = TRUE;
913 class->gc_descr = GC_NO_DESCRIPTOR;
915 bitmap = default_bitmap;
916 if (class == mono_defaults.string_class) {
917 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
918 } else if (class->rank) {
919 mono_class_compute_gc_descriptor (class->element_class);
920 if (!class->element_class->valuetype) {
922 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
923 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
924 class->name_space, class->name);*/
926 /* remove the object header */
927 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
928 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
929 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
930 class->name_space, class->name);*/
931 if (bitmap != default_bitmap)
935 /*static int count = 0;
938 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
939 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
941 if (class->gc_descr == GC_NO_DESCRIPTOR)
942 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
944 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
945 if (bitmap != default_bitmap)
951 * field_is_special_static:
952 * @fklass: The MonoClass to look up.
953 * @field: The MonoClassField describing the field.
955 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
956 * SPECIAL_STATIC_NONE otherwise.
959 field_is_special_static (MonoClass *fklass, MonoClassField *field)
961 MonoCustomAttrInfo *ainfo;
963 ainfo = mono_custom_attrs_from_field (fklass, field);
966 for (i = 0; i < ainfo->num_attrs; ++i) {
967 MonoClass *klass = ainfo->attrs [i].ctor->klass;
968 if (klass->image == mono_defaults.corlib) {
969 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
970 mono_custom_attrs_free (ainfo);
971 return SPECIAL_STATIC_THREAD;
973 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
974 mono_custom_attrs_free (ainfo);
975 return SPECIAL_STATIC_CONTEXT;
979 mono_custom_attrs_free (ainfo);
980 return SPECIAL_STATIC_NONE;
983 static gpointer imt_trampoline = NULL;
986 mono_install_imt_trampoline (gpointer tramp_code)
988 imt_trampoline = tramp_code;
991 static gpointer vtable_trampoline = NULL;
994 mono_install_vtable_trampoline (gpointer tramp_code)
996 vtable_trampoline = tramp_code;
999 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1000 #define mix(a,b,c) { \
1001 a -= c; a ^= rot(c, 4); c += b; \
1002 b -= a; b ^= rot(a, 6); a += c; \
1003 c -= b; c ^= rot(b, 8); b += a; \
1004 a -= c; a ^= rot(c,16); c += b; \
1005 b -= a; b ^= rot(a,19); a += c; \
1006 c -= b; c ^= rot(b, 4); b += a; \
1008 #define final(a,b,c) { \
1009 c ^= b; c -= rot(b,14); \
1010 a ^= c; a -= rot(c,11); \
1011 b ^= a; b -= rot(a,25); \
1012 c ^= b; c -= rot(b,16); \
1013 a ^= c; a -= rot(c,4); \
1014 b ^= a; b -= rot(a,14); \
1015 c ^= b; c -= rot(b,24); \
1019 mono_method_get_imt_slot (MonoMethod *method)
1021 MonoMethodSignature *sig;
1023 guint32 *hashes_start, *hashes;
1027 /* This can be used to stress tests the collision code */
1031 * We do this to simplify generic sharing. It will hurt
1032 * performance in cases where a class implements two different
1033 * instantiations of the same generic interface.
1034 * The code in build_imt_slots () depends on this.
1036 if (method->is_inflated)
1037 method = ((MonoMethodInflated*)method)->declaring;
1039 sig = mono_method_signature (method);
1040 hashes_count = sig->param_count + 4;
1041 hashes_start = malloc (hashes_count * sizeof (guint32));
1042 hashes = hashes_start;
1044 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1045 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1046 method->klass->name_space, method->klass->name, method->name);
1047 g_assert_not_reached ();
1050 /* Initialize hashes */
1051 hashes [0] = g_str_hash (method->klass->name);
1052 hashes [1] = g_str_hash (method->klass->name_space);
1053 hashes [2] = g_str_hash (method->name);
1054 hashes [3] = mono_metadata_type_hash (sig->ret);
1055 for (i = 0; i < sig->param_count; i++) {
1056 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1059 /* Setup internal state */
1060 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1062 /* Handle most of the hashes */
1063 while (hashes_count > 3) {
1072 /* Handle the last 3 hashes (all the case statements fall through) */
1073 switch (hashes_count) {
1074 case 3 : c += hashes [2];
1075 case 2 : b += hashes [1];
1076 case 1 : a += hashes [0];
1078 case 0: /* nothing left to add */
1082 free (hashes_start);
1083 /* Report the result */
1084 return c % MONO_IMT_SIZE;
1093 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1094 guint32 imt_slot = mono_method_get_imt_slot (method);
1095 MonoImtBuilderEntry *entry;
1097 if (slot_num >= 0 && imt_slot != slot_num) {
1098 /* we build just a single imt slot and this is not it */
1102 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1103 entry->key = method;
1104 entry->value.vtable_slot = vtable_slot;
1105 entry->next = imt_builder [imt_slot];
1106 if (imt_builder [imt_slot] != NULL) {
1107 entry->children = imt_builder [imt_slot]->children + 1;
1108 if (entry->children == 1) {
1109 mono_stats.imt_slots_with_collisions++;
1110 *imt_collisions_bitmap |= (1 << imt_slot);
1113 entry->children = 0;
1114 mono_stats.imt_used_slots++;
1116 imt_builder [imt_slot] = entry;
1118 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1119 method, method->klass->name_space, method->klass->name,
1120 method->name, imt_slot, vtable_slot, entry->children);
1126 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1128 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1132 e->method->klass->name_space,
1133 e->method->klass->name,
1136 printf (" * %s: NULL\n", message);
1142 compare_imt_builder_entries (const void *p1, const void *p2) {
1143 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1144 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1146 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1150 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1152 int count = end - start;
1153 int chunk_start = out_array->len;
1156 for (i = start; i < end; ++i) {
1157 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1158 item->key = sorted_array [i]->key;
1159 item->value = sorted_array [i]->value;
1160 item->has_target_code = sorted_array [i]->has_target_code;
1161 item->is_equals = TRUE;
1163 item->check_target_idx = out_array->len + 1;
1165 item->check_target_idx = 0;
1166 g_ptr_array_add (out_array, item);
1169 int middle = start + count / 2;
1170 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1172 item->key = sorted_array [middle]->key;
1173 item->is_equals = FALSE;
1174 g_ptr_array_add (out_array, item);
1175 imt_emit_ir (sorted_array, start, middle, out_array);
1176 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1182 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1183 int number_of_entries = entries->children + 1;
1184 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1185 GPtrArray *result = g_ptr_array_new ();
1186 MonoImtBuilderEntry *current_entry;
1189 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1190 sorted_array [i] = current_entry;
1192 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1194 /*for (i = 0; i < number_of_entries; i++) {
1195 print_imt_entry (" sorted array:", sorted_array [i], i);
1198 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1200 free (sorted_array);
1205 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1207 if (imt_builder_entry != NULL) {
1208 if (imt_builder_entry->children == 0 && !fail_tramp) {
1209 /* No collision, return the vtable slot contents */
1210 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1212 /* Collision, build the thunk */
1213 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1216 result = imt_thunk_builder (vtable, domain,
1217 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1218 for (i = 0; i < imt_ir->len; ++i)
1219 g_free (g_ptr_array_index (imt_ir, i));
1220 g_ptr_array_free (imt_ir, TRUE);
1232 static MonoImtBuilderEntry*
1233 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1236 * LOCKING: requires the loader and domain locks.
1240 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1244 guint32 imt_collisions_bitmap = 0;
1245 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1246 int method_count = 0;
1247 gboolean record_method_count_for_max_collisions = FALSE;
1248 gboolean has_generic_virtual = FALSE;
1251 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1253 for (i = 0; i < klass->interface_offsets_count; ++i) {
1254 MonoClass *iface = klass->interfaces_packed [i];
1255 int interface_offset = klass->interface_offsets_packed [i];
1256 int method_slot_in_interface;
1257 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1260 if (slot_num >= 0 && iface->is_inflated) {
1262 * The imt slot of the method is the same as for its declaring method,
1263 * see the comment in mono_method_get_imt_slot (), so we can
1264 * avoid inflating methods which will be discarded by
1265 * add_imt_builder_entry anyway.
1267 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1268 if (mono_method_get_imt_slot (method) != slot_num)
1271 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1272 if (method->is_generic) {
1273 has_generic_virtual = TRUE;
1276 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1279 if (extra_interfaces) {
1280 int interface_offset = klass->vtable_size;
1282 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1283 MonoClass* iface = list_item->data;
1284 int method_slot_in_interface;
1285 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1286 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1287 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1289 interface_offset += iface->method.count;
1292 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1293 /* overwrite the imt slot only if we're building all the entries or if
1294 * we're building this specific one
1296 if (slot_num < 0 || i == slot_num) {
1297 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1300 if (imt_builder [i]) {
1301 MonoImtBuilderEntry *entry;
1303 /* Link entries with imt_builder [i] */
1304 for (entry = entries; entry->next; entry = entry->next)
1306 entry->next = imt_builder [i];
1307 entries->children += imt_builder [i]->children + 1;
1309 imt_builder [i] = entries;
1312 if (has_generic_virtual) {
1314 * There might be collisions later when the the thunk is expanded.
1316 imt_collisions_bitmap |= (1 << i);
1319 * The IMT thunk might be called with an instance of one of the
1320 * generic virtual methods, so has to fallback to the IMT trampoline.
1322 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1324 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1328 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1330 if (imt_builder [i] != NULL) {
1331 int methods_in_slot = imt_builder [i]->children + 1;
1332 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1333 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1334 record_method_count_for_max_collisions = TRUE;
1336 method_count += methods_in_slot;
1340 mono_stats.imt_number_of_methods += method_count;
1341 if (record_method_count_for_max_collisions) {
1342 mono_stats.imt_method_count_when_max_collisions = method_count;
1345 for (i = 0; i < MONO_IMT_SIZE; i++) {
1346 MonoImtBuilderEntry* entry = imt_builder [i];
1347 while (entry != NULL) {
1348 MonoImtBuilderEntry* next = entry->next;
1354 /* we OR the bitmap since we may build just a single imt slot at a time */
1355 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1359 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1360 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1364 * mono_vtable_build_imt_slot:
1365 * @vtable: virtual object table struct
1366 * @imt_slot: slot in the IMT table
1368 * Fill the given @imt_slot in the IMT table of @vtable with
1369 * a trampoline or a thunk for the case of collisions.
1370 * This is part of the internal mono API.
1372 * LOCKING: Take the domain lock.
1375 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1377 gpointer *imt = (gpointer*)vtable;
1378 imt -= MONO_IMT_SIZE;
1379 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1381 /* no support for extra interfaces: the proxy objects will need
1382 * to build the complete IMT
1383 * Update and heck needs to ahppen inside the proper domain lock, as all
1384 * the changes made to a MonoVTable.
1386 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1387 mono_domain_lock (vtable->domain);
1388 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1389 if (imt [imt_slot] == imt_trampoline)
1390 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1391 mono_domain_unlock (vtable->domain);
1392 mono_loader_unlock ();
1397 * The first two free list entries both belong to the wait list: The
1398 * first entry is the pointer to the head of the list and the second
1399 * entry points to the last element. That way appending and removing
1400 * the first element are both O(1) operations.
1402 #define NUM_FREE_LISTS 12
1403 #define FIRST_FREE_LIST_SIZE 64
1404 #define MAX_WAIT_LENGTH 50
1405 #define THUNK_THRESHOLD 10
1408 * LOCKING: The domain lock must be held.
1411 init_thunk_free_lists (MonoDomain *domain)
1413 if (domain->thunk_free_lists)
1415 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1419 list_index_for_size (int item_size)
1422 int size = FIRST_FREE_LIST_SIZE;
1424 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1433 * mono_method_alloc_generic_virtual_thunk:
1435 * @size: size in bytes
1437 * Allocs size bytes to be used for the code of a generic virtual
1438 * thunk. It's either allocated from the domain's code manager or
1439 * reused from a previously invalidated piece.
1441 * LOCKING: The domain lock must be held.
1444 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1446 static gboolean inited = FALSE;
1447 static int generic_virtual_thunks_size = 0;
1451 MonoThunkFreeList **l;
1453 init_thunk_free_lists (domain);
1455 size += sizeof (guint32);
1456 if (size < sizeof (MonoThunkFreeList))
1457 size = sizeof (MonoThunkFreeList);
1459 i = list_index_for_size (size);
1460 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1461 if ((*l)->size >= size) {
1462 MonoThunkFreeList *item = *l;
1464 return ((guint32*)item) + 1;
1468 /* no suitable item found - search lists of larger sizes */
1469 while (++i < NUM_FREE_LISTS) {
1470 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1473 g_assert (item->size > size);
1474 domain->thunk_free_lists [i] = item->next;
1475 return ((guint32*)item) + 1;
1478 /* still nothing found - allocate it */
1480 mono_counters_register ("Generic virtual thunk bytes",
1481 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1484 generic_virtual_thunks_size += size;
1486 p = mono_domain_code_reserve (domain, size);
1493 * LOCKING: The domain lock must be held.
1496 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1499 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1501 init_thunk_free_lists (domain);
1503 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1504 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1505 int length = item->length;
1508 /* unlink the first item from the wait list */
1509 domain->thunk_free_lists [0] = item->next;
1510 domain->thunk_free_lists [0]->length = length - 1;
1512 i = list_index_for_size (item->size);
1514 /* put it in the free list */
1515 item->next = domain->thunk_free_lists [i];
1516 domain->thunk_free_lists [i] = item;
1520 if (domain->thunk_free_lists [1]) {
1521 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1522 domain->thunk_free_lists [0]->length++;
1524 g_assert (!domain->thunk_free_lists [0]);
1526 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1527 domain->thunk_free_lists [0]->length = 1;
1531 typedef struct _GenericVirtualCase {
1535 struct _GenericVirtualCase *next;
1536 } GenericVirtualCase;
1539 * get_generic_virtual_entries:
1541 * Return IMT entries for the generic virtual method instances for vtable slot
1544 static MonoImtBuilderEntry*
1545 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1547 GenericVirtualCase *list;
1548 MonoImtBuilderEntry *entries;
1550 mono_domain_lock (domain);
1551 if (!domain->generic_virtual_cases)
1552 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1554 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1557 for (; list; list = list->next) {
1558 MonoImtBuilderEntry *entry;
1560 if (list->count < THUNK_THRESHOLD)
1563 entry = g_new0 (MonoImtBuilderEntry, 1);
1564 entry->key = list->method;
1565 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1566 entry->has_target_code = 1;
1568 entry->children = entries->children + 1;
1569 entry->next = entries;
1573 mono_domain_unlock (domain);
1575 /* FIXME: Leaking memory ? */
1580 * mono_method_add_generic_virtual_invocation:
1582 * @vtable_slot: pointer to the vtable slot
1583 * @method: the inflated generic virtual method
1584 * @code: the method's code
1586 * Registers a call via unmanaged code to a generic virtual method
1587 * instantiation. If the number of calls reaches a threshold
1588 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1589 * virtual method thunk.
1592 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1593 gpointer *vtable_slot,
1594 MonoMethod *method, gpointer code)
1596 static gboolean inited = FALSE;
1597 static int num_added = 0;
1599 GenericVirtualCase *gvc, *list;
1600 MonoImtBuilderEntry *entries;
1604 mono_domain_lock (domain);
1605 if (!domain->generic_virtual_cases)
1606 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1608 /* Check whether the case was already added */
1609 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1612 if (gvc->method == method)
1617 /* If not found, make a new one */
1619 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1620 gvc->method = method;
1623 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1625 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1628 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1634 if (++gvc->count == THUNK_THRESHOLD) {
1635 gpointer *old_thunk = *vtable_slot;
1637 if ((gpointer)vtable_slot < (gpointer)vtable)
1638 /* Force the rebuild of the thunk at the next call */
1639 *vtable_slot = imt_trampoline;
1641 entries = get_generic_virtual_entries (domain, vtable_slot);
1643 sorted = imt_sort_slot_entries (entries);
1645 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1649 MonoImtBuilderEntry *next = entries->next;
1654 for (i = 0; i < sorted->len; ++i)
1655 g_free (g_ptr_array_index (sorted, i));
1656 g_ptr_array_free (sorted, TRUE);
1659 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1660 invalidate_generic_virtual_thunk (domain, old_thunk);
1663 mono_domain_unlock (domain);
1666 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1669 * mono_class_vtable:
1670 * @domain: the application domain
1671 * @class: the class to initialize
1673 * VTables are domain specific because we create domain specific code, and
1674 * they contain the domain specific static class data.
1675 * On failure, NULL is returned, and class->exception_type is set.
1678 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1680 return mono_class_vtable_full (domain, class, FALSE);
1684 * mono_class_vtable_full:
1685 * @domain: the application domain
1686 * @class: the class to initialize
1687 * @raise_on_error if an exception should be raised on failure or not
1689 * VTables are domain specific because we create domain specific code, and
1690 * they contain the domain specific static class data.
1693 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1695 MonoClassRuntimeInfo *runtime_info;
1699 if (class->exception_type) {
1701 mono_raise_exception (mono_class_get_exception_for_failure (class));
1705 /* this check can be inlined in jitted code, too */
1706 runtime_info = class->runtime_info;
1707 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1708 return runtime_info->domain_vtables [domain->domain_id];
1709 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1713 * mono_class_try_get_vtable:
1714 * @domain: the application domain
1715 * @class: the class to initialize
1717 * This function tries to get the associated vtable from @class if
1718 * it was already created.
1721 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1723 MonoClassRuntimeInfo *runtime_info;
1727 runtime_info = class->runtime_info;
1728 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1729 return runtime_info->domain_vtables [domain->domain_id];
1734 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1737 MonoClassRuntimeInfo *runtime_info, *old_info;
1738 MonoClassField *field;
1741 int imt_table_bytes = 0;
1742 guint32 vtable_size, class_size;
1745 gpointer *interface_offsets;
1747 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1748 mono_domain_lock (domain);
1749 runtime_info = class->runtime_info;
1750 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1751 mono_domain_unlock (domain);
1752 mono_loader_unlock ();
1753 return runtime_info->domain_vtables [domain->domain_id];
1755 if (!class->inited || class->exception_type) {
1756 if (!mono_class_init (class) || class->exception_type) {
1757 mono_domain_unlock (domain);
1758 mono_loader_unlock ();
1760 mono_raise_exception (mono_class_get_exception_for_failure (class));
1765 /* Array types require that their element type be valid*/
1766 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1767 MonoClass *element_class = class->element_class;
1768 if (!element_class->inited)
1769 mono_class_init (element_class);
1771 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1772 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1773 mono_class_setup_vtable (element_class);
1775 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1776 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1777 if (class->exception_type == MONO_EXCEPTION_NONE)
1778 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1779 mono_domain_unlock (domain);
1780 mono_loader_unlock ();
1782 mono_raise_exception (mono_class_get_exception_for_failure (class));
1788 * For some classes, mono_class_init () already computed class->vtable_size, and
1789 * that is all that is needed because of the vtable trampolines.
1791 if (!class->vtable_size)
1792 mono_class_setup_vtable (class);
1794 if (class->exception_type) {
1795 mono_domain_unlock (domain);
1796 mono_loader_unlock ();
1798 mono_raise_exception (mono_class_get_exception_for_failure (class));
1803 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1804 if (class->interface_offsets_count) {
1805 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1806 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1807 mono_stats.imt_number_of_tables++;
1808 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1811 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1812 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1815 mono_stats.used_class_count++;
1816 mono_stats.class_vtable_size += vtable_size;
1817 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1820 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1822 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1824 vt->rank = class->rank;
1825 vt->domain = domain;
1827 mono_class_compute_gc_descriptor (class);
1829 * We can't use typed allocation in the non-root domains, since the
1830 * collector needs the GC descriptor stored in the vtable even after
1831 * the mempool containing the vtable is destroyed when the domain is
1832 * unloaded. An alternative might be to allocate vtables in the GC
1833 * heap, but this does not seem to work (it leads to crashes inside
1834 * libgc). If that approach is tried, two gc descriptors need to be
1835 * allocated for each class: one for the root domain, and one for all
1836 * other domains. The second descriptor should contain a bit for the
1837 * vtable field in MonoObject, since we can no longer assume the
1838 * vtable is reachable by other roots after the appdomain is unloaded.
1840 #ifdef HAVE_BOEHM_GC
1841 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1842 vt->gc_descr = GC_NO_DESCRIPTOR;
1845 vt->gc_descr = class->gc_descr;
1847 if ((class_size = mono_class_data_size (class))) {
1848 if (class->has_static_refs) {
1849 gpointer statics_gc_descr;
1851 gsize default_bitmap [4] = {0};
1854 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1855 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1856 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1857 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1858 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1859 if (bitmap != default_bitmap)
1862 vt->data = mono_domain_alloc0 (domain, class_size);
1864 mono_stats.class_static_data_size += class_size;
1869 while ((field = mono_class_get_fields (class, &iter))) {
1870 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1872 if (mono_field_is_deleted (field))
1874 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1875 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1876 if (special_static != SPECIAL_STATIC_NONE) {
1877 guint32 size, offset;
1879 size = mono_type_size (field->type, &align);
1880 offset = mono_alloc_special_static_data (special_static, size, align);
1881 if (!domain->special_static_fields)
1882 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1883 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1885 * This marks the field as special static to speed up the
1886 * checks in mono_field_static_get/set_value ().
1892 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1893 MonoClass *fklass = mono_class_from_mono_type (field->type);
1894 const char *data = mono_field_get_data (field);
1896 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1897 t = (char*)vt->data + field->offset;
1898 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1901 if (fklass->valuetype) {
1902 memcpy (t, data, mono_class_value_size (fklass, NULL));
1904 /* it's a pointer type: add check */
1905 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1912 vt->max_interface_id = class->max_interface_id;
1913 vt->interface_bitmap = class->interface_bitmap;
1915 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1916 // class->name, class->interface_offsets_count);
1918 if (! ARCH_USE_IMT) {
1919 /* initialize interface offsets */
1920 for (i = 0; i < class->interface_offsets_count; ++i) {
1921 int interface_id = class->interfaces_packed [i]->interface_id;
1922 int slot = class->interface_offsets_packed [i];
1923 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1927 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1928 * as we change the code in appdomain.c to invalidate vtables by
1929 * looking at the possible MonoClasses created for the domain.
1931 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1932 /* class->runtime_info is protected by the loader lock, both when
1933 * it it enlarged and when it is stored info.
1936 old_info = class->runtime_info;
1937 if (old_info && old_info->max_domain >= domain->domain_id) {
1938 /* someone already created a large enough runtime info */
1939 mono_memory_barrier ();
1940 old_info->domain_vtables [domain->domain_id] = vt;
1942 int new_size = domain->domain_id;
1944 new_size = MAX (new_size, old_info->max_domain);
1946 /* make the new size a power of two */
1948 while (new_size > i)
1951 /* this is a bounded memory retention issue: may want to
1952 * handle it differently when we'll have a rcu-like system.
1954 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1955 runtime_info->max_domain = new_size - 1;
1956 /* copy the stuff from the older info */
1958 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1960 runtime_info->domain_vtables [domain->domain_id] = vt;
1962 mono_memory_barrier ();
1963 class->runtime_info = runtime_info;
1966 /* Initialize vtable */
1967 if (vtable_trampoline) {
1968 // This also covers the AOT case
1969 for (i = 0; i < class->vtable_size; ++i) {
1970 vt->vtable [i] = vtable_trampoline;
1973 mono_class_setup_vtable (class);
1975 for (i = 0; i < class->vtable_size; ++i) {
1978 if ((cm = class->vtable [i]))
1979 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1983 if (ARCH_USE_IMT && imt_table_bytes) {
1984 /* Now that the vtable is full, we can actually fill up the IMT */
1985 if (imt_trampoline) {
1986 /* lazy construction of the IMT entries enabled */
1987 for (i = 0; i < MONO_IMT_SIZE; ++i)
1988 interface_offsets [i] = imt_trampoline;
1990 build_imt (class, vt, domain, interface_offsets, NULL);
1994 mono_domain_unlock (domain);
1995 mono_loader_unlock ();
1997 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1998 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
1999 mono_raise_exception (mono_class_get_exception_for_failure (class));
2001 /* make sure the parent is initialized */
2002 /*FIXME shouldn't this fail the current type?*/
2004 mono_class_vtable_full (domain, class->parent, raise_on_error);
2006 /*FIXME check for OOM*/
2007 vt->type = mono_type_get_object (domain, &class->byval_arg);
2008 if (class->contextbound)
2017 * mono_class_proxy_vtable:
2018 * @domain: the application domain
2019 * @remove_class: the remote class
2021 * Creates a vtable for transparent proxies. It is basically
2022 * a copy of the real vtable of the class wrapped in @remote_class,
2023 * but all function pointers invoke the remoting functions, and
2024 * vtable->klass points to the transparent proxy class, and not to @class.
2027 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2029 MonoVTable *vt, *pvt;
2030 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2032 GSList *extra_interfaces = NULL;
2033 MonoClass *class = remote_class->proxy_class;
2034 gpointer *interface_offsets;
2036 vt = mono_class_vtable (domain, class);
2037 g_assert (vt); /*FIXME property handle failure*/
2038 max_interface_id = vt->max_interface_id;
2040 /* Calculate vtable space for extra interfaces */
2041 for (j = 0; j < remote_class->interface_count; j++) {
2042 MonoClass* iclass = remote_class->interfaces[j];
2046 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2047 continue; /* interface implemented by the class */
2048 if (g_slist_find (extra_interfaces, iclass))
2051 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2053 method_count = mono_class_num_methods (iclass);
2055 ifaces = mono_class_get_implemented_interfaces (iclass);
2057 for (i = 0; i < ifaces->len; ++i) {
2058 MonoClass *ic = g_ptr_array_index (ifaces, i);
2059 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2060 continue; /* interface implemented by the class */
2061 if (g_slist_find (extra_interfaces, ic))
2063 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2064 method_count += mono_class_num_methods (ic);
2066 g_ptr_array_free (ifaces, TRUE);
2069 extra_interface_vtsize += method_count * sizeof (gpointer);
2070 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2074 mono_stats.imt_number_of_tables++;
2075 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2076 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2077 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2079 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2080 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2083 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2085 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2087 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2089 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2090 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2092 pvt->klass = mono_defaults.transparent_proxy_class;
2093 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2094 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2096 /* initialize vtable */
2097 mono_class_setup_vtable (class);
2098 for (i = 0; i < class->vtable_size; ++i) {
2101 if ((cm = class->vtable [i]))
2102 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2104 pvt->vtable [i] = NULL;
2107 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2108 /* create trampolines for abstract methods */
2109 for (k = class; k; k = k->parent) {
2111 gpointer iter = NULL;
2112 while ((m = mono_class_get_methods (k, &iter)))
2113 if (!pvt->vtable [m->slot])
2114 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2118 pvt->max_interface_id = max_interface_id;
2119 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2121 if (! ARCH_USE_IMT) {
2122 /* initialize interface offsets */
2123 for (i = 0; i < class->interface_offsets_count; ++i) {
2124 int interface_id = class->interfaces_packed [i]->interface_id;
2125 int slot = class->interface_offsets_packed [i];
2126 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2129 for (i = 0; i < class->interface_offsets_count; ++i) {
2130 int interface_id = class->interfaces_packed [i]->interface_id;
2131 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2134 if (extra_interfaces) {
2135 int slot = class->vtable_size;
2141 /* Create trampolines for the methods of the interfaces */
2142 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2143 interf = list_item->data;
2145 if (! ARCH_USE_IMT) {
2146 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2148 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2152 while ((cm = mono_class_get_methods (interf, &iter)))
2153 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2155 slot += mono_class_num_methods (interf);
2157 if (! ARCH_USE_IMT) {
2158 g_slist_free (extra_interfaces);
2163 /* Now that the vtable is full, we can actually fill up the IMT */
2164 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2165 if (extra_interfaces) {
2166 g_slist_free (extra_interfaces);
2174 * mono_class_field_is_special_static:
2176 * Returns whether @field is a thread/context static field.
2179 mono_class_field_is_special_static (MonoClassField *field)
2181 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2183 if (mono_field_is_deleted (field))
2185 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2186 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2193 * mono_class_has_special_static_fields:
2195 * Returns whenever @klass has any thread/context static fields.
2198 mono_class_has_special_static_fields (MonoClass *klass)
2200 MonoClassField *field;
2204 while ((field = mono_class_get_fields (klass, &iter))) {
2205 g_assert (field->parent == klass);
2206 if (mono_class_field_is_special_static (field))
2214 * create_remote_class_key:
2215 * Creates an array of pointers that can be used as a hash key for a remote class.
2216 * The first element of the array is the number of pointers.
2219 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2224 if (remote_class == NULL) {
2225 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2226 key = g_malloc (sizeof(gpointer) * 3);
2227 key [0] = GINT_TO_POINTER (2);
2228 key [1] = mono_defaults.marshalbyrefobject_class;
2229 key [2] = extra_class;
2231 key = g_malloc (sizeof(gpointer) * 2);
2232 key [0] = GINT_TO_POINTER (1);
2233 key [1] = extra_class;
2236 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2237 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2238 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2239 key [1] = remote_class->proxy_class;
2241 // Keep the list of interfaces sorted
2242 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2243 if (extra_class && remote_class->interfaces [i] > extra_class) {
2244 key [j++] = extra_class;
2247 key [j] = remote_class->interfaces [i];
2250 key [j] = extra_class;
2252 // Replace the old class. The interface list is the same
2253 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2254 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2255 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2256 for (i = 0; i < remote_class->interface_count; i++)
2257 key [2 + i] = remote_class->interfaces [i];
2265 * copy_remote_class_key:
2267 * Make a copy of KEY in the domain and return the copy.
2270 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2272 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2273 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2275 memcpy (mp_key, key, key_size);
2281 * mono_remote_class:
2282 * @domain: the application domain
2283 * @class_name: name of the remote class
2285 * Creates and initializes a MonoRemoteClass object for a remote type.
2289 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2291 MonoRemoteClass *rc;
2292 gpointer* key, *mp_key;
2294 key = create_remote_class_key (NULL, proxy_class);
2296 mono_domain_lock (domain);
2297 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2301 mono_domain_unlock (domain);
2305 mp_key = copy_remote_class_key (domain, key);
2309 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2310 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2311 rc->interface_count = 1;
2312 rc->interfaces [0] = proxy_class;
2313 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2315 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2316 rc->interface_count = 0;
2317 rc->proxy_class = proxy_class;
2320 rc->default_vtable = NULL;
2321 rc->xdomain_vtable = NULL;
2322 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
2323 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2325 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2327 mono_domain_unlock (domain);
2332 * clone_remote_class:
2333 * Creates a copy of the remote_class, adding the provided class or interface
2335 static MonoRemoteClass*
2336 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2338 MonoRemoteClass *rc;
2339 gpointer* key, *mp_key;
2341 key = create_remote_class_key (remote_class, extra_class);
2342 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2348 mp_key = copy_remote_class_key (domain, key);
2352 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2354 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2355 rc->proxy_class = remote_class->proxy_class;
2356 rc->interface_count = remote_class->interface_count + 1;
2358 // Keep the list of interfaces sorted, since the hash key of
2359 // the remote class depends on this
2360 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2361 if (remote_class->interfaces [i] > extra_class && i == j)
2362 rc->interfaces [j++] = extra_class;
2363 rc->interfaces [j] = remote_class->interfaces [i];
2366 rc->interfaces [j] = extra_class;
2368 // Replace the old class. The interface array is the same
2369 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2370 rc->proxy_class = extra_class;
2371 rc->interface_count = remote_class->interface_count;
2372 if (rc->interface_count > 0)
2373 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2376 rc->default_vtable = NULL;
2377 rc->xdomain_vtable = NULL;
2378 rc->proxy_class_name = remote_class->proxy_class_name;
2380 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2386 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2388 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2389 mono_domain_lock (domain);
2390 if (rp->target_domain_id != -1) {
2391 if (remote_class->xdomain_vtable == NULL)
2392 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2393 mono_domain_unlock (domain);
2394 mono_loader_unlock ();
2395 return remote_class->xdomain_vtable;
2397 if (remote_class->default_vtable == NULL) {
2400 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2401 klass = mono_class_from_mono_type (type);
2402 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2403 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2405 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2408 mono_domain_unlock (domain);
2409 mono_loader_unlock ();
2410 return remote_class->default_vtable;
2414 * mono_upgrade_remote_class:
2415 * @domain: the application domain
2416 * @tproxy: the proxy whose remote class has to be upgraded.
2417 * @klass: class to which the remote class can be casted.
2419 * Updates the vtable of the remote class by adding the necessary method slots
2420 * and interface offsets so it can be safely casted to klass. klass can be a
2421 * class or an interface.
2424 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2426 MonoTransparentProxy *tproxy;
2427 MonoRemoteClass *remote_class;
2428 gboolean redo_vtable;
2430 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2431 mono_domain_lock (domain);
2433 tproxy = (MonoTransparentProxy*) proxy_object;
2434 remote_class = tproxy->remote_class;
2436 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2439 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2440 if (remote_class->interfaces [i] == klass)
2441 redo_vtable = FALSE;
2444 redo_vtable = (remote_class->proxy_class != klass);
2448 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2449 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2452 mono_domain_unlock (domain);
2453 mono_loader_unlock ();
2458 * mono_object_get_virtual_method:
2459 * @obj: object to operate on.
2462 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2463 * the instance of a callvirt of method.
2466 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2469 MonoMethod **vtable;
2471 MonoMethod *res = NULL;
2473 klass = mono_object_class (obj);
2474 if (klass == mono_defaults.transparent_proxy_class) {
2475 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2481 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2484 mono_class_setup_vtable (klass);
2485 vtable = klass->vtable;
2487 if (method->slot == -1) {
2488 /* method->slot might not be set for instances of generic methods */
2489 if (method->is_inflated) {
2490 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2491 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2494 g_assert_not_reached ();
2498 /* check method->slot is a valid index: perform isinstance? */
2499 if (method->slot != -1) {
2500 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2502 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2504 res = vtable [method->slot];
2509 /* It may be an interface, abstract class method or generic method */
2510 if (!res || mono_method_signature (res)->generic_param_count)
2513 /* generic methods demand invoke_with_check */
2514 if (mono_method_signature (res)->generic_param_count)
2515 res = mono_marshal_get_remoting_invoke_with_check (res);
2518 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2519 res = mono_cominterop_get_invoke (res);
2522 res = mono_marshal_get_remoting_invoke (res);
2525 if (method->is_inflated) {
2526 /* Have to inflate the result */
2527 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2537 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2539 g_error ("runtime invoke called on uninitialized runtime");
2543 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2546 * mono_runtime_invoke:
2547 * @method: method to invoke
2548 * @obJ: object instance
2549 * @params: arguments to the method
2550 * @exc: exception information.
2552 * Invokes the method represented by @method on the object @obj.
2554 * obj is the 'this' pointer, it should be NULL for static
2555 * methods, a MonoObject* for object instances and a pointer to
2556 * the value type for value types.
2558 * The params array contains the arguments to the method with the
2559 * same convention: MonoObject* pointers for object instances and
2560 * pointers to the value type otherwise.
2562 * From unmanaged code you'll usually use the
2563 * mono_runtime_invoke() variant.
2565 * Note that this function doesn't handle virtual methods for
2566 * you, it will exec the exact method you pass: we still need to
2567 * expose a function to lookup the derived class implementation
2568 * of a virtual method (there are examples of this in the code,
2571 * You can pass NULL as the exc argument if you don't want to
2572 * catch exceptions, otherwise, *exc will be set to the exception
2573 * thrown, if any. if an exception is thrown, you can't use the
2574 * MonoObject* result from the function.
2576 * If the method returns a value type, it is boxed in an object
2580 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2582 if (mono_runtime_get_no_exec ())
2583 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2585 return default_mono_runtime_invoke (method, obj, params, exc);
2589 * mono_method_get_unmanaged_thunk:
2590 * @method: method to generate a thunk for.
2592 * Returns an unmanaged->managed thunk that can be used to call
2593 * a managed method directly from C.
2595 * The thunk's C signature closely matches the managed signature:
2597 * C#: public bool Equals (object obj);
2598 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2599 * MonoObject*, MonoException**);
2601 * The 1st ("this") parameter must not be used with static methods:
2603 * C#: public static bool ReferenceEquals (object a, object b);
2604 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2607 * The last argument must be a non-null pointer of a MonoException* pointer.
2608 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2609 * exception has been thrown in managed code. Otherwise it will point
2610 * to the MonoException* caught by the thunk. In this case, the result of
2611 * the thunk is undefined:
2613 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2614 * MonoException *ex = NULL;
2615 * Equals func = mono_method_get_unmanaged_thunk (method);
2616 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2618 * // handle exception
2621 * The calling convention of the thunk matches the platform's default
2622 * convention. This means that under Windows, C declarations must
2623 * contain the __stdcall attribute:
2625 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2626 * MonoObject*, MonoException**);
2630 * Value type arguments and return values are treated as they were objects:
2632 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2633 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2635 * Arguments must be properly boxed upon trunk's invocation, while return
2636 * values must be unboxed.
2639 mono_method_get_unmanaged_thunk (MonoMethod *method)
2641 method = mono_marshal_get_thunk_invoke_wrapper (method);
2642 return mono_compile_method (method);
2646 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2650 /* object fields cannot be byref, so we don't need a
2652 gpointer *p = (gpointer*)dest;
2659 case MONO_TYPE_BOOLEAN:
2661 case MONO_TYPE_U1: {
2662 guint8 *p = (guint8*)dest;
2663 *p = value ? *(guint8*)value : 0;
2668 case MONO_TYPE_CHAR: {
2669 guint16 *p = (guint16*)dest;
2670 *p = value ? *(guint16*)value : 0;
2673 #if SIZEOF_VOID_P == 4
2678 case MONO_TYPE_U4: {
2679 gint32 *p = (gint32*)dest;
2680 *p = value ? *(gint32*)value : 0;
2683 #if SIZEOF_VOID_P == 8
2688 case MONO_TYPE_U8: {
2689 gint64 *p = (gint64*)dest;
2690 *p = value ? *(gint64*)value : 0;
2693 case MONO_TYPE_R4: {
2694 float *p = (float*)dest;
2695 *p = value ? *(float*)value : 0;
2698 case MONO_TYPE_R8: {
2699 double *p = (double*)dest;
2700 *p = value ? *(double*)value : 0;
2703 case MONO_TYPE_STRING:
2704 case MONO_TYPE_SZARRAY:
2705 case MONO_TYPE_CLASS:
2706 case MONO_TYPE_OBJECT:
2707 case MONO_TYPE_ARRAY:
2708 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2710 case MONO_TYPE_FNPTR:
2711 case MONO_TYPE_PTR: {
2712 gpointer *p = (gpointer*)dest;
2713 *p = deref_pointer? *(gpointer*)value: value;
2716 case MONO_TYPE_VALUETYPE:
2717 /* note that 't' and 'type->type' can be different */
2718 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2719 t = mono_class_enum_basetype (type->data.klass)->type;
2722 MonoClass *class = mono_class_from_mono_type (type);
2723 int size = mono_class_value_size (class, NULL);
2724 if (value == NULL) {
2725 memset (dest, 0, size);
2727 memcpy (dest, value, size);
2728 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2732 case MONO_TYPE_GENERICINST:
2733 t = type->data.generic_class->container_class->byval_arg.type;
2736 g_warning ("got type %x", type->type);
2737 g_assert_not_reached ();
2742 * mono_field_set_value:
2743 * @obj: Instance object
2744 * @field: MonoClassField describing the field to set
2745 * @value: The value to be set
2747 * Sets the value of the field described by @field in the object instance @obj
2748 * to the value passed in @value. This method should only be used for instance
2749 * fields. For static fields, use mono_field_static_set_value.
2751 * The value must be on the native format of the field type.
2754 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2758 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2760 dest = (char*)obj + field->offset;
2761 set_value (field->type, dest, value, FALSE);
2765 * mono_field_static_set_value:
2766 * @field: MonoClassField describing the field to set
2767 * @value: The value to be set
2769 * Sets the value of the static field described by @field
2770 * to the value passed in @value.
2772 * The value must be on the native format of the field type.
2775 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2779 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2780 /* you cant set a constant! */
2781 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2783 if (field->offset == -1) {
2784 /* Special static */
2785 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2786 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2788 dest = (char*)vt->data + field->offset;
2790 set_value (field->type, dest, value, FALSE);
2793 /* Used by the debugger */
2795 mono_vtable_get_static_field_data (MonoVTable *vt)
2801 * mono_field_get_value:
2802 * @obj: Object instance
2803 * @field: MonoClassField describing the field to fetch information from
2804 * @value: pointer to the location where the value will be stored
2806 * Use this routine to get the value of the field @field in the object
2809 * The pointer provided by value must be of the field type, for reference
2810 * types this is a MonoObject*, for value types its the actual pointer to
2815 * mono_field_get_value (obj, int_field, &i);
2818 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2822 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2824 src = (char*)obj + field->offset;
2825 set_value (field->type, value, src, TRUE);
2829 * mono_field_get_value_object:
2830 * @domain: domain where the object will be created (if boxing)
2831 * @field: MonoClassField describing the field to fetch information from
2832 * @obj: The object instance for the field.
2834 * Returns: a new MonoObject with the value from the given field. If the
2835 * field represents a value type, the value is boxed.
2839 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2843 MonoVTable *vtable = NULL;
2845 gboolean is_static = FALSE;
2846 gboolean is_ref = FALSE;
2848 switch (field->type->type) {
2849 case MONO_TYPE_STRING:
2850 case MONO_TYPE_OBJECT:
2851 case MONO_TYPE_CLASS:
2852 case MONO_TYPE_ARRAY:
2853 case MONO_TYPE_SZARRAY:
2858 case MONO_TYPE_BOOLEAN:
2861 case MONO_TYPE_CHAR:
2870 case MONO_TYPE_VALUETYPE:
2871 is_ref = field->type->byref;
2873 case MONO_TYPE_GENERICINST:
2874 is_ref = !field->type->data.generic_class->container_class->valuetype;
2877 g_error ("type 0x%x not handled in "
2878 "mono_field_get_value_object", field->type->type);
2882 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2884 vtable = mono_class_vtable (domain, field->parent);
2886 char *name = mono_type_get_full_name (field->parent);
2887 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2891 if (!vtable->initialized)
2892 mono_runtime_class_init (vtable);
2897 mono_field_static_get_value (vtable, field, &o);
2899 mono_field_get_value (obj, field, &o);
2904 /* boxed value type */
2905 klass = mono_class_from_mono_type (field->type);
2906 o = mono_object_new (domain, klass);
2907 v = ((gchar *) o) + sizeof (MonoObject);
2909 mono_field_static_get_value (vtable, field, v);
2911 mono_field_get_value (obj, field, v);
2918 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2921 const char *p = blob;
2922 mono_metadata_decode_blob_size (p, &p);
2925 case MONO_TYPE_BOOLEAN:
2928 *(guint8 *) value = *p;
2930 case MONO_TYPE_CHAR:
2933 *(guint16*) value = read16 (p);
2937 *(guint32*) value = read32 (p);
2941 *(guint64*) value = read64 (p);
2944 readr4 (p, (float*) value);
2947 readr8 (p, (double*) value);
2949 case MONO_TYPE_STRING:
2950 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2952 case MONO_TYPE_CLASS:
2953 *(gpointer*) value = NULL;
2957 g_warning ("type 0x%02x should not be in constant table", type);
2963 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2965 MonoTypeEnum def_type;
2968 data = mono_class_get_field_default_value (field, &def_type);
2969 mono_get_constant_value_from_blob (domain, def_type, data, value);
2973 * mono_field_static_get_value:
2974 * @vt: vtable to the object
2975 * @field: MonoClassField describing the field to fetch information from
2976 * @value: where the value is returned
2978 * Use this routine to get the value of the static field @field value.
2980 * The pointer provided by value must be of the field type, for reference
2981 * types this is a MonoObject*, for value types its the actual pointer to
2986 * mono_field_static_get_value (vt, int_field, &i);
2989 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2993 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2995 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2996 get_default_field_value (vt->domain, field, value);
3000 if (field->offset == -1) {
3001 /* Special static */
3002 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3003 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3005 src = (char*)vt->data + field->offset;
3007 set_value (field->type, value, src, TRUE);
3011 * mono_property_set_value:
3012 * @prop: MonoProperty to set
3013 * @obj: instance object on which to act
3014 * @params: parameters to pass to the propery
3015 * @exc: optional exception
3017 * Invokes the property's set method with the given arguments on the
3018 * object instance obj (or NULL for static properties).
3020 * You can pass NULL as the exc argument if you don't want to
3021 * catch exceptions, otherwise, *exc will be set to the exception
3022 * thrown, if any. if an exception is thrown, you can't use the
3023 * MonoObject* result from the function.
3026 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3028 default_mono_runtime_invoke (prop->set, obj, params, exc);
3032 * mono_property_get_value:
3033 * @prop: MonoProperty to fetch
3034 * @obj: instance object on which to act
3035 * @params: parameters to pass to the propery
3036 * @exc: optional exception
3038 * Invokes the property's get method with the given arguments on the
3039 * object instance obj (or NULL for static properties).
3041 * You can pass NULL as the exc argument if you don't want to
3042 * catch exceptions, otherwise, *exc will be set to the exception
3043 * thrown, if any. if an exception is thrown, you can't use the
3044 * MonoObject* result from the function.
3046 * Returns: the value from invoking the get method on the property.
3049 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3051 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3055 * mono_nullable_init:
3056 * @buf: The nullable structure to initialize.
3057 * @value: the value to initialize from
3058 * @klass: the type for the object
3060 * Initialize the nullable structure pointed to by @buf from @value which
3061 * should be a boxed value type. The size of @buf should be able to hold
3062 * as much data as the @klass->instance_size (which is the number of bytes
3063 * that will be copies).
3065 * Since Nullables have variable structure, we can not define a C
3066 * structure for them.
3069 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3071 MonoClass *param_class = klass->cast_class;
3073 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3074 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3076 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3078 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3080 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3084 * mono_nullable_box:
3085 * @buf: The buffer representing the data to be boxed
3086 * @klass: the type to box it as.
3088 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3092 mono_nullable_box (guint8 *buf, MonoClass *klass)
3094 MonoClass *param_class = klass->cast_class;
3096 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3097 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3099 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3100 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3101 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3109 * mono_get_delegate_invoke:
3110 * @klass: The delegate class
3112 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3115 mono_get_delegate_invoke (MonoClass *klass)
3119 /* This is called at runtime, so avoid the slower search in metadata */
3120 mono_class_setup_methods (klass);
3122 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3129 * mono_runtime_delegate_invoke:
3130 * @delegate: pointer to a delegate object.
3131 * @params: parameters for the delegate.
3132 * @exc: Pointer to the exception result.
3134 * Invokes the delegate method @delegate with the parameters provided.
3136 * You can pass NULL as the exc argument if you don't want to
3137 * catch exceptions, otherwise, *exc will be set to the exception
3138 * thrown, if any. if an exception is thrown, you can't use the
3139 * MonoObject* result from the function.
3142 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3146 im = mono_get_delegate_invoke (delegate->vtable->klass);
3149 return mono_runtime_invoke (im, delegate, params, exc);
3152 static char **main_args = NULL;
3153 static int num_main_args;
3156 * mono_runtime_get_main_args:
3158 * Returns: a MonoArray with the arguments passed to the main program
3161 mono_runtime_get_main_args (void)
3165 MonoDomain *domain = mono_domain_get ();
3170 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3172 for (i = 0; i < num_main_args; ++i)
3173 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3179 fire_process_exit_event (void)
3181 MonoClassField *field;
3182 MonoDomain *domain = mono_domain_get ();
3184 MonoObject *delegate, *exc;
3186 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3189 if (domain != mono_get_root_domain ())
3192 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3193 if (delegate == NULL)
3198 mono_runtime_delegate_invoke (delegate, pa, &exc);
3202 * mono_runtime_run_main:
3203 * @method: the method to start the application with (usually Main)
3204 * @argc: number of arguments from the command line
3205 * @argv: array of strings from the command line
3206 * @exc: excetption results
3208 * Execute a standard Main() method (argc/argv contains the
3209 * executable name). This method also sets the command line argument value
3210 * needed by System.Environment.
3215 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3219 MonoArray *args = NULL;
3220 MonoDomain *domain = mono_domain_get ();
3221 gchar *utf8_fullpath;
3224 g_assert (method != NULL);
3226 mono_thread_set_main (mono_thread_current ());
3228 main_args = g_new0 (char*, argc);
3229 num_main_args = argc;
3231 if (!g_path_is_absolute (argv [0])) {
3232 gchar *basename = g_path_get_basename (argv [0]);
3233 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3237 utf8_fullpath = mono_utf8_from_external (fullpath);
3238 if(utf8_fullpath == NULL) {
3239 /* Printing the arg text will cause glib to
3240 * whinge about "Invalid UTF-8", but at least
3241 * its relevant, and shows the problem text
3244 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3245 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3252 utf8_fullpath = mono_utf8_from_external (argv[0]);
3253 if(utf8_fullpath == NULL) {
3254 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3255 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3260 main_args [0] = utf8_fullpath;
3262 for (i = 1; i < argc; ++i) {
3265 utf8_arg=mono_utf8_from_external (argv[i]);
3266 if(utf8_arg==NULL) {
3267 /* Ditto the comment about Invalid UTF-8 here */
3268 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3269 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3273 main_args [i] = utf8_arg;
3277 if (mono_method_signature (method)->param_count) {
3278 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3279 for (i = 0; i < argc; ++i) {
3280 /* The encodings should all work, given that
3281 * we've checked all these args for the
3284 gchar *str = mono_utf8_from_external (argv [i]);
3285 MonoString *arg = mono_string_new (domain, str);
3286 mono_array_setref (args, i, arg);
3290 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3293 mono_assembly_set_main (method->klass->image->assembly);
3295 result = mono_runtime_exec_main (method, args, exc);
3296 fire_process_exit_event ();
3300 /* Used in call_unhandled_exception_delegate */
3302 create_unhandled_exception_eventargs (MonoObject *exc)
3306 MonoMethod *method = NULL;
3307 MonoBoolean is_terminating = TRUE;
3310 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3313 mono_class_init (klass);
3315 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3316 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3320 args [1] = &is_terminating;
3322 obj = mono_object_new (mono_domain_get (), klass);
3323 mono_runtime_invoke (method, obj, args, NULL);
3328 /* Used in mono_unhandled_exception */
3330 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3331 MonoObject *e = NULL;
3334 pa [0] = domain->domain;
3335 pa [1] = create_unhandled_exception_eventargs (exc);
3336 mono_runtime_delegate_invoke (delegate, pa, &e);
3339 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3340 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3345 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3348 * mono_runtime_unhandled_exception_policy_set:
3349 * @policy: the new policy
3351 * This is a VM internal routine.
3353 * Sets the runtime policy for handling unhandled exceptions.
3356 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3357 runtime_unhandled_exception_policy = policy;
3361 * mono_runtime_unhandled_exception_policy_get:
3363 * This is a VM internal routine.
3365 * Gets the runtime policy for handling unhandled exceptions.
3367 MonoRuntimeUnhandledExceptionPolicy
3368 mono_runtime_unhandled_exception_policy_get (void) {
3369 return runtime_unhandled_exception_policy;
3373 * mono_unhandled_exception:
3374 * @exc: exception thrown
3376 * This is a VM internal routine.
3378 * We call this function when we detect an unhandled exception
3379 * in the default domain.
3381 * It invokes the * UnhandledException event in AppDomain or prints
3382 * a warning to the console
3385 mono_unhandled_exception (MonoObject *exc)
3387 MonoDomain *current_domain = mono_domain_get ();
3388 MonoDomain *root_domain = mono_get_root_domain ();
3389 MonoClassField *field;
3390 MonoObject *current_appdomain_delegate;
3391 MonoObject *root_appdomain_delegate;
3393 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3394 "UnhandledException");
3397 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3398 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3399 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3400 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3401 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3402 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3404 current_appdomain_delegate = NULL;
3407 /* set exitcode only if we will abort the process */
3409 mono_environment_exitcode_set (1);
3410 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3411 mono_print_unhandled_exception (exc);
3413 if (root_appdomain_delegate) {
3414 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3416 if (current_appdomain_delegate) {
3417 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3424 * Launch a new thread to execute a function
3426 * main_func is called back from the thread with main_args as the
3427 * parameter. The callback function is expected to start Main()
3428 * eventually. This function then waits for all managed threads to
3430 * It is not necesseray anymore to execute managed code in a subthread,
3431 * so this function should not be used anymore by default: just
3432 * execute the code and then call mono_thread_manage ().
3435 mono_runtime_exec_managed_code (MonoDomain *domain,
3436 MonoMainThreadFunc main_func,
3439 mono_thread_create (domain, main_func, main_args);
3441 mono_thread_manage ();
3445 * Execute a standard Main() method (args doesn't contain the
3449 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3454 MonoCustomAttrInfo* cinfo;
3455 gboolean has_stathread_attribute;
3456 MonoInternalThread* thread = mono_thread_internal_current ();
3462 domain = mono_object_domain (args);
3463 if (!domain->entry_assembly) {
3465 MonoAssembly *assembly;
3467 assembly = method->klass->image->assembly;
3468 domain->entry_assembly = assembly;
3469 /* Domains created from another domain already have application_base and configuration_file set */
3470 if (domain->setup->application_base == NULL) {
3471 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3474 if (domain->setup->configuration_file == NULL) {
3475 str = g_strconcat (assembly->image->name, ".config", NULL);
3476 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3478 mono_set_private_bin_path_from_config (domain);
3482 cinfo = mono_custom_attrs_from_method (method);
3484 static MonoClass *stathread_attribute = NULL;
3485 if (!stathread_attribute)
3486 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3487 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3489 mono_custom_attrs_free (cinfo);
3491 has_stathread_attribute = FALSE;
3493 if (has_stathread_attribute) {
3494 thread->apartment_state = ThreadApartmentState_STA;
3495 } else if (mono_framework_version () == 1) {
3496 thread->apartment_state = ThreadApartmentState_Unknown;
3498 thread->apartment_state = ThreadApartmentState_MTA;
3500 mono_thread_init_apartment_state ();
3502 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3504 /* FIXME: check signature of method */
3505 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3507 res = mono_runtime_invoke (method, NULL, pa, exc);
3509 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3513 mono_environment_exitcode_set (rval);
3515 mono_runtime_invoke (method, NULL, pa, exc);
3519 /* If the return type of Main is void, only
3520 * set the exitcode if an exception was thrown
3521 * (we don't want to blow away an
3522 * explicitly-set exit code)
3525 mono_environment_exitcode_set (rval);
3529 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3535 * mono_install_runtime_invoke:
3536 * @func: Function to install
3538 * This is a VM internal routine
3541 mono_install_runtime_invoke (MonoInvokeFunc func)
3543 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3548 * mono_runtime_invoke_array:
3549 * @method: method to invoke
3550 * @obJ: object instance
3551 * @params: arguments to the method
3552 * @exc: exception information.
3554 * Invokes the method represented by @method on the object @obj.
3556 * obj is the 'this' pointer, it should be NULL for static
3557 * methods, a MonoObject* for object instances and a pointer to
3558 * the value type for value types.
3560 * The params array contains the arguments to the method with the
3561 * same convention: MonoObject* pointers for object instances and
3562 * pointers to the value type otherwise. The _invoke_array
3563 * variant takes a C# object[] as the params argument (MonoArray
3564 * *params): in this case the value types are boxed inside the
3565 * respective reference representation.
3567 * From unmanaged code you'll usually use the
3568 * mono_runtime_invoke() variant.
3570 * Note that this function doesn't handle virtual methods for
3571 * you, it will exec the exact method you pass: we still need to
3572 * expose a function to lookup the derived class implementation
3573 * of a virtual method (there are examples of this in the code,
3576 * You can pass NULL as the exc argument if you don't want to
3577 * catch exceptions, otherwise, *exc will be set to the exception
3578 * thrown, if any. if an exception is thrown, you can't use the
3579 * MonoObject* result from the function.
3581 * If the method returns a value type, it is boxed in an object
3585 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3588 MonoMethodSignature *sig = mono_method_signature (method);
3589 gpointer *pa = NULL;
3592 gboolean has_byref_nullables = FALSE;
3594 if (NULL != params) {
3595 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3596 for (i = 0; i < mono_array_length (params); i++) {
3597 MonoType *t = sig->params [i];
3603 case MONO_TYPE_BOOLEAN:
3606 case MONO_TYPE_CHAR:
3615 case MONO_TYPE_VALUETYPE:
3616 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3617 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3618 pa [i] = mono_array_get (params, MonoObject*, i);
3620 has_byref_nullables = TRUE;
3622 /* MS seems to create the objects if a null is passed in */
3623 if (!mono_array_get (params, MonoObject*, i))
3624 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3628 * We can't pass the unboxed vtype byref to the callee, since
3629 * that would mean the callee would be able to modify boxed
3630 * primitive types. So we (and MS) make a copy of the boxed
3631 * object, pass that to the callee, and replace the original
3632 * boxed object in the arg array with the copy.
3634 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3635 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3636 mono_array_setref (params, i, copy);
3639 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3642 case MONO_TYPE_STRING:
3643 case MONO_TYPE_OBJECT:
3644 case MONO_TYPE_CLASS:
3645 case MONO_TYPE_ARRAY:
3646 case MONO_TYPE_SZARRAY:
3648 pa [i] = mono_array_addr (params, MonoObject*, i);
3649 // FIXME: I need to check this code path
3651 pa [i] = mono_array_get (params, MonoObject*, i);
3653 case MONO_TYPE_GENERICINST:
3655 t = &t->data.generic_class->container_class->this_arg;
3657 t = &t->data.generic_class->container_class->byval_arg;
3659 case MONO_TYPE_PTR: {
3662 /* The argument should be an IntPtr */
3663 arg = mono_array_get (params, MonoObject*, i);
3667 g_assert (arg->vtable->klass == mono_defaults.int_class);
3668 pa [i] = ((MonoIntPtr*)arg)->m_value;
3673 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3678 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3681 if (mono_class_is_nullable (method->klass)) {
3682 /* Need to create a boxed vtype instead */
3688 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3692 obj = mono_object_new (mono_domain_get (), method->klass);
3693 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3694 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3696 if (method->klass->valuetype)
3697 o = mono_object_unbox (obj);
3700 } else if (method->klass->valuetype) {
3701 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3704 mono_runtime_invoke (method, o, pa, exc);
3707 if (mono_class_is_nullable (method->klass)) {
3708 MonoObject *nullable;
3710 /* Convert the unboxed vtype into a Nullable structure */
3711 nullable = mono_object_new (mono_domain_get (), method->klass);
3713 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3714 obj = mono_object_unbox (nullable);
3717 /* obj must be already unboxed if needed */
3718 res = mono_runtime_invoke (method, obj, pa, exc);
3720 if (sig->ret->type == MONO_TYPE_PTR) {
3721 MonoClass *pointer_class;
3722 static MonoMethod *box_method;
3724 MonoObject *box_exc;
3727 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3728 * convert it to a Pointer object.
3730 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3732 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3734 g_assert (res->vtable->klass == mono_defaults.int_class);
3735 box_args [0] = ((MonoIntPtr*)res)->m_value;
3736 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3737 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3738 g_assert (!box_exc);
3741 if (has_byref_nullables) {
3743 * The runtime invoke wrapper already converted byref nullables back,
3744 * and stored them in pa, we just need to copy them back to the
3747 for (i = 0; i < mono_array_length (params); i++) {
3748 MonoType *t = sig->params [i];
3750 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3751 mono_array_setref (params, i, pa [i]);
3760 arith_overflow (void)
3762 mono_raise_exception (mono_get_exception_overflow ());
3766 * mono_object_allocate:
3767 * @size: number of bytes to allocate
3769 * This is a very simplistic routine until we have our GC-aware
3772 * Returns: an allocated object of size @size, or NULL on failure.
3774 static inline void *
3775 mono_object_allocate (size_t size, MonoVTable *vtable)
3778 mono_stats.new_object_count++;
3779 ALLOC_OBJECT (o, vtable, size);
3785 * mono_object_allocate_ptrfree:
3786 * @size: number of bytes to allocate
3788 * Note that the memory allocated is not zeroed.
3789 * Returns: an allocated object of size @size, or NULL on failure.
3791 static inline void *
3792 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3795 mono_stats.new_object_count++;
3796 ALLOC_PTRFREE (o, vtable, size);
3800 static inline void *
3801 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3804 ALLOC_TYPED (o, size, vtable);
3805 mono_stats.new_object_count++;
3812 * @klass: the class of the object that we want to create
3814 * Returns: a newly created object whose definition is
3815 * looked up using @klass. This will not invoke any constructors,
3816 * so the consumer of this routine has to invoke any constructors on
3817 * its own to initialize the object.
3819 * It returns NULL on failure.
3822 mono_object_new (MonoDomain *domain, MonoClass *klass)
3826 MONO_ARCH_SAVE_REGS;
3827 vtable = mono_class_vtable (domain, klass);
3830 return mono_object_new_specific (vtable);
3834 * mono_object_new_specific:
3835 * @vtable: the vtable of the object that we want to create
3837 * Returns: A newly created object with class and domain specified
3841 mono_object_new_specific (MonoVTable *vtable)
3845 MONO_ARCH_SAVE_REGS;
3847 /* check for is_com_object for COM Interop */
3848 if (vtable->remote || vtable->klass->is_com_object)
3851 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3854 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3857 mono_class_init (klass);
3859 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3861 vtable->domain->create_proxy_for_type_method = im;
3864 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3866 o = mono_runtime_invoke (im, NULL, pa, NULL);
3867 if (o != NULL) return o;
3870 return mono_object_new_alloc_specific (vtable);
3874 mono_object_new_alloc_specific (MonoVTable *vtable)
3878 if (!vtable->klass->has_references) {
3879 o = mono_object_new_ptrfree (vtable);
3880 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3881 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3883 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3884 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3886 if (G_UNLIKELY (vtable->klass->has_finalize))
3887 mono_object_register_finalizer (o);
3889 if (G_UNLIKELY (profile_allocs))
3890 mono_profiler_allocation (o, vtable->klass);
3895 mono_object_new_fast (MonoVTable *vtable)
3898 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3903 mono_object_new_ptrfree (MonoVTable *vtable)
3906 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3907 #if NEED_TO_ZERO_PTRFREE
3908 /* an inline memset is much faster for the common vcase of small objects
3909 * note we assume the allocated size is a multiple of sizeof (void*).
3911 if (vtable->klass->instance_size < 128) {
3913 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3914 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3920 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3927 mono_object_new_ptrfree_box (MonoVTable *vtable)
3930 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3931 /* the object will be boxed right away, no need to memzero it */
3936 * mono_class_get_allocation_ftn:
3938 * @for_box: the object will be used for boxing
3939 * @pass_size_in_words:
3941 * Return the allocation function appropriate for the given class.
3945 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3947 *pass_size_in_words = FALSE;
3949 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3950 profile_allocs = FALSE;
3952 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3953 return mono_object_new_specific;
3955 if (!vtable->klass->has_references) {
3956 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3958 return mono_object_new_ptrfree_box;
3959 return mono_object_new_ptrfree;
3962 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3964 return mono_object_new_fast;
3967 * FIXME: This is actually slower than mono_object_new_fast, because
3968 * of the overhead of parameter passing.
3971 *pass_size_in_words = TRUE;
3972 #ifdef GC_REDIRECT_TO_LOCAL
3973 return GC_local_gcj_fast_malloc;
3975 return GC_gcj_fast_malloc;
3980 return mono_object_new_specific;
3984 * mono_object_new_from_token:
3985 * @image: Context where the type_token is hosted
3986 * @token: a token of the type that we want to create
3988 * Returns: A newly created object whose definition is
3989 * looked up using @token in the @image image
3992 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3996 class = mono_class_get (image, token);
3998 return mono_object_new (domain, class);
4003 * mono_object_clone:
4004 * @obj: the object to clone
4006 * Returns: A newly created object who is a shallow copy of @obj
4009 mono_object_clone (MonoObject *obj)
4014 size = obj->vtable->klass->instance_size;
4015 o = mono_object_allocate (size, obj->vtable);
4016 /* do not copy the sync state */
4017 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4020 if (obj->vtable->klass->has_references)
4021 mono_gc_wbarrier_object (o);
4023 if (G_UNLIKELY (profile_allocs))
4024 mono_profiler_allocation (o, obj->vtable->klass);
4026 if (obj->vtable->klass->has_finalize)
4027 mono_object_register_finalizer (o);
4032 * mono_array_full_copy:
4033 * @src: source array to copy
4034 * @dest: destination array
4036 * Copies the content of one array to another with exactly the same type and size.
4039 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4041 mono_array_size_t size;
4042 MonoClass *klass = src->obj.vtable->klass;
4044 MONO_ARCH_SAVE_REGS;
4046 g_assert (klass == dest->obj.vtable->klass);
4048 size = mono_array_length (src);
4049 g_assert (size == mono_array_length (dest));
4050 size *= mono_array_element_size (klass);
4052 if (klass->element_class->valuetype) {
4053 if (klass->element_class->has_references)
4054 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4056 memcpy (&dest->vector, &src->vector, size);
4058 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4061 memcpy (&dest->vector, &src->vector, size);
4066 * mono_array_clone_in_domain:
4067 * @domain: the domain in which the array will be cloned into
4068 * @array: the array to clone
4070 * This routine returns a copy of the array that is hosted on the
4071 * specified MonoDomain.
4074 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4077 mono_array_size_t size, i;
4078 mono_array_size_t *sizes;
4079 MonoClass *klass = array->obj.vtable->klass;
4081 MONO_ARCH_SAVE_REGS;
4083 if (array->bounds == NULL) {
4084 size = mono_array_length (array);
4085 o = mono_array_new_full (domain, klass, &size, NULL);
4087 size *= mono_array_element_size (klass);
4089 if (klass->element_class->valuetype) {
4090 if (klass->element_class->has_references)
4091 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4093 memcpy (&o->vector, &array->vector, size);
4095 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4098 memcpy (&o->vector, &array->vector, size);
4103 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4104 size = mono_array_element_size (klass);
4105 for (i = 0; i < klass->rank; ++i) {
4106 sizes [i] = array->bounds [i].length;
4107 size *= array->bounds [i].length;
4108 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4110 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4112 if (klass->element_class->valuetype) {
4113 if (klass->element_class->has_references)
4114 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4116 memcpy (&o->vector, &array->vector, size);
4118 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4121 memcpy (&o->vector, &array->vector, size);
4129 * @array: the array to clone
4131 * Returns: A newly created array who is a shallow copy of @array
4134 mono_array_clone (MonoArray *array)
4136 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4139 /* helper macros to check for overflow when calculating the size of arrays */
4140 #ifdef MONO_BIG_ARRAYS
4141 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4142 #define MYGUINT_MAX MYGUINT64_MAX
4143 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4144 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4145 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4146 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4147 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4149 #define MYGUINT32_MAX 4294967295U
4150 #define MYGUINT_MAX MYGUINT32_MAX
4151 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4152 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4153 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4154 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4155 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4159 * mono_array_new_full:
4160 * @domain: domain where the object is created
4161 * @array_class: array class
4162 * @lengths: lengths for each dimension in the array
4163 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4165 * This routine creates a new array objects with the given dimensions,
4166 * lower bounds and type.
4169 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4171 mono_array_size_t byte_len, len, bounds_size;
4177 if (!array_class->inited)
4178 mono_class_init (array_class);
4180 byte_len = mono_array_element_size (array_class);
4183 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4184 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4186 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4190 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4192 for (i = 0; i < array_class->rank; ++i) {
4193 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4195 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4196 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4201 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4202 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4204 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4205 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4206 byte_len += sizeof (MonoArray);
4209 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4210 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4211 byte_len = (byte_len + 3) & ~3;
4212 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4213 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4214 byte_len += bounds_size;
4217 * Following three lines almost taken from mono_object_new ():
4218 * they need to be kept in sync.
4220 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4221 if (!array_class->has_references) {
4222 o = mono_object_allocate_ptrfree (byte_len, vtable);
4223 #if NEED_TO_ZERO_PTRFREE
4224 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4226 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4227 o = mono_object_allocate_spec (byte_len, vtable);
4229 o = mono_object_allocate (byte_len, vtable);
4232 array = (MonoArray*)o;
4233 array->max_length = len;
4236 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4237 array->bounds = bounds;
4238 for (i = 0; i < array_class->rank; ++i) {
4239 bounds [i].length = lengths [i];
4241 bounds [i].lower_bound = lower_bounds [i];
4245 if (G_UNLIKELY (profile_allocs))
4246 mono_profiler_allocation (o, array_class);
4253 * @domain: domain where the object is created
4254 * @eclass: element class
4255 * @n: number of array elements
4257 * This routine creates a new szarray with @n elements of type @eclass.
4260 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4264 MONO_ARCH_SAVE_REGS;
4266 ac = mono_array_class_get (eclass, 1);
4269 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4273 * mono_array_new_specific:
4274 * @vtable: a vtable in the appropriate domain for an initialized class
4275 * @n: number of array elements
4277 * This routine is a fast alternative to mono_array_new() for code which
4278 * can be sure about the domain it operates in.
4281 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4285 guint32 byte_len, elem_size;
4287 MONO_ARCH_SAVE_REGS;
4289 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4294 elem_size = mono_array_element_size (vtable->klass);
4295 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
4296 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4299 byte_len = n * elem_size;
4300 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
4301 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4304 byte_len += sizeof (MonoArray);
4305 if (!vtable->klass->has_references) {
4306 o = mono_object_allocate_ptrfree (byte_len, vtable);
4307 #if NEED_TO_ZERO_PTRFREE
4308 ((MonoArray*)o)->bounds = NULL;
4309 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4311 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4312 o = mono_object_allocate_spec (byte_len, vtable);
4314 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4315 o = mono_object_allocate (byte_len, vtable);
4318 ao = (MonoArray *)o;
4320 if (G_UNLIKELY (profile_allocs))
4321 mono_profiler_allocation (o, vtable->klass);
4327 * mono_string_new_utf16:
4328 * @text: a pointer to an utf16 string
4329 * @len: the length of the string
4331 * Returns: A newly created string object which contains @text.
4334 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4338 s = mono_string_new_size (domain, len);
4339 g_assert (s != NULL);
4341 memcpy (mono_string_chars (s), text, len * 2);
4347 * mono_string_new_size:
4348 * @text: a pointer to an utf16 string
4349 * @len: the length of the string
4351 * Returns: A newly created string object of @len
4354 mono_string_new_size (MonoDomain *domain, gint32 len)
4358 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4360 /* overflow ? can't fit it, can't allocate it! */
4362 mono_gc_out_of_memory (-1);
4364 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4367 s = mono_object_allocate_ptrfree (size, vtable);
4370 #if NEED_TO_ZERO_PTRFREE
4373 if (G_UNLIKELY (profile_allocs))
4374 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4380 * mono_string_new_len:
4381 * @text: a pointer to an utf8 string
4382 * @length: number of bytes in @text to consider
4384 * Returns: A newly created string object which contains @text.
4387 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4389 GError *error = NULL;
4390 MonoString *o = NULL;
4392 glong items_written;
4394 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4397 o = mono_string_new_utf16 (domain, ut, items_written);
4399 g_error_free (error);
4408 * @text: a pointer to an utf8 string
4410 * Returns: A newly created string object which contains @text.
4413 mono_string_new (MonoDomain *domain, const char *text)
4415 GError *error = NULL;
4416 MonoString *o = NULL;
4418 glong items_written;
4423 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4426 o = mono_string_new_utf16 (domain, ut, items_written);
4428 g_error_free (error);
4431 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4436 MonoString *o = NULL;
4438 if (!g_utf8_validate (text, -1, &end))
4441 len = g_utf8_strlen (text, -1);
4442 o = mono_string_new_size (domain, len);
4443 str = mono_string_chars (o);
4445 while (text < end) {
4446 *str++ = g_utf8_get_char (text);
4447 text = g_utf8_next_char (text);
4454 * mono_string_new_wrapper:
4455 * @text: pointer to utf8 characters.
4457 * Helper function to create a string object from @text in the current domain.
4460 mono_string_new_wrapper (const char *text)
4462 MonoDomain *domain = mono_domain_get ();
4464 MONO_ARCH_SAVE_REGS;
4467 return mono_string_new (domain, text);
4474 * @class: the class of the value
4475 * @value: a pointer to the unboxed data
4477 * Returns: A newly created object which contains @value.
4480 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4486 g_assert (class->valuetype);
4487 if (mono_class_is_nullable (class))
4488 return mono_nullable_box (value, class);
4490 vtable = mono_class_vtable (domain, class);
4493 size = mono_class_instance_size (class);
4494 res = mono_object_new_alloc_specific (vtable);
4495 if (G_UNLIKELY (profile_allocs))
4496 mono_profiler_allocation (res, class);
4498 size = size - sizeof (MonoObject);
4501 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4504 #if NO_UNALIGNED_ACCESS
4505 memcpy ((char *)res + sizeof (MonoObject), value, size);
4509 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4512 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4515 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4518 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4521 memcpy ((char *)res + sizeof (MonoObject), value, size);
4524 if (class->has_finalize)
4525 mono_object_register_finalizer (res);
4531 * @dest: destination pointer
4532 * @src: source pointer
4533 * @klass: a valuetype class
4535 * Copy a valuetype from @src to @dest. This function must be used
4536 * when @klass contains references fields.
4539 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4541 int size = mono_class_value_size (klass, NULL);
4542 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4543 memcpy (dest, src, size);
4547 * mono_value_copy_array:
4548 * @dest: destination array
4549 * @dest_idx: index in the @dest array
4550 * @src: source pointer
4551 * @count: number of items
4553 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4554 * This function must be used when @klass contains references fields.
4555 * Overlap is handled.
4558 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4560 int size = mono_array_element_size (dest->obj.vtable->klass);
4561 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4562 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4563 memmove (d, src, size * count);
4567 * mono_object_get_domain:
4568 * @obj: object to query
4570 * Returns: the MonoDomain where the object is hosted
4573 mono_object_get_domain (MonoObject *obj)
4575 return mono_object_domain (obj);
4579 * mono_object_get_class:
4580 * @obj: object to query
4582 * Returns: the MonOClass of the object.
4585 mono_object_get_class (MonoObject *obj)
4587 return mono_object_class (obj);
4590 * mono_object_get_size:
4591 * @o: object to query
4593 * Returns: the size, in bytes, of @o
4596 mono_object_get_size (MonoObject* o)
4598 MonoClass* klass = mono_object_class (o);
4599 if (klass == mono_defaults.string_class) {
4600 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4601 } else if (o->vtable->rank) {
4602 MonoArray *array = (MonoArray*)o;
4603 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4604 if (array->bounds) {
4607 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4611 return mono_class_instance_size (klass);
4616 * mono_object_unbox:
4617 * @obj: object to unbox
4619 * Returns: a pointer to the start of the valuetype boxed in this
4622 * This method will assert if the object passed is not a valuetype.
4625 mono_object_unbox (MonoObject *obj)
4627 /* add assert for valuetypes? */
4628 g_assert (obj->vtable->klass->valuetype);
4629 return ((char*)obj) + sizeof (MonoObject);
4633 * mono_object_isinst:
4635 * @klass: a pointer to a class
4637 * Returns: @obj if @obj is derived from @klass
4640 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4643 mono_class_init (klass);
4645 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4646 return mono_object_isinst_mbyref (obj, klass);
4651 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4655 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4664 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4665 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4669 MonoClass *oklass = vt->klass;
4670 if ((oklass == mono_defaults.transparent_proxy_class))
4671 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4673 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4677 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4679 MonoDomain *domain = mono_domain_get ();
4681 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4682 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4683 MonoMethod *im = NULL;
4686 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4687 im = mono_object_get_virtual_method (rp, im);
4690 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4693 res = mono_runtime_invoke (im, rp, pa, NULL);
4695 if (*(MonoBoolean *) mono_object_unbox(res)) {
4696 /* Update the vtable of the remote type, so it can safely cast to this new type */
4697 mono_upgrade_remote_class (domain, obj, klass);
4706 * mono_object_castclass_mbyref:
4708 * @klass: a pointer to a class
4710 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4713 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4715 if (!obj) return NULL;
4716 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4718 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4720 "InvalidCastException"));
4725 MonoDomain *orig_domain;
4731 str_lookup (MonoDomain *domain, gpointer user_data)
4733 LDStrInfo *info = user_data;
4734 if (info->res || domain == info->orig_domain)
4736 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4742 mono_string_get_pinned (MonoString *str)
4746 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4747 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4748 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4749 news->length = mono_string_length (str);
4754 #define mono_string_get_pinned(str) (str)
4758 mono_string_is_interned_lookup (MonoString *str, int insert)
4760 MonoGHashTable *ldstr_table;
4764 domain = ((MonoObject *)str)->vtable->domain;
4765 ldstr_table = domain->ldstr_table;
4767 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4772 str = mono_string_get_pinned (str);
4773 mono_g_hash_table_insert (ldstr_table, str, str);
4777 LDStrInfo ldstr_info;
4778 ldstr_info.orig_domain = domain;
4779 ldstr_info.ins = str;
4780 ldstr_info.res = NULL;
4782 mono_domain_foreach (str_lookup, &ldstr_info);
4783 if (ldstr_info.res) {
4785 * the string was already interned in some other domain:
4786 * intern it in the current one as well.
4788 mono_g_hash_table_insert (ldstr_table, str, str);
4798 * mono_string_is_interned:
4799 * @o: String to probe
4801 * Returns whether the string has been interned.
4804 mono_string_is_interned (MonoString *o)
4806 return mono_string_is_interned_lookup (o, FALSE);
4810 * mono_string_intern:
4811 * @o: String to intern
4813 * Interns the string passed.
4814 * Returns: The interned string.
4817 mono_string_intern (MonoString *str)
4819 return mono_string_is_interned_lookup (str, TRUE);
4824 * @domain: the domain where the string will be used.
4825 * @image: a metadata context
4826 * @idx: index into the user string table.
4828 * Implementation for the ldstr opcode.
4829 * Returns: a loaded string from the @image/@idx combination.
4832 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4834 MONO_ARCH_SAVE_REGS;
4837 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4839 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
4843 * mono_ldstr_metadata_sig
4844 * @domain: the domain for the string
4845 * @sig: the signature of a metadata string
4847 * Returns: a MonoString for a string stored in the metadata
4850 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
4852 const char *str = sig;
4853 MonoString *o, *interned;
4856 len2 = mono_metadata_decode_blob_size (str, &str);
4859 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4860 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4863 guint16 *p2 = (guint16*)mono_string_chars (o);
4864 for (i = 0; i < len2; ++i) {
4865 *p2 = GUINT16_FROM_LE (*p2);
4871 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4873 /* o will get garbage collected */
4877 o = mono_string_get_pinned (o);
4878 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4885 * mono_string_to_utf8:
4886 * @s: a System.String
4888 * Return the UTF8 representation for @s.
4889 * the resulting buffer nedds to be freed with g_free().
4892 mono_string_to_utf8 (MonoString *s)
4896 GError *error = NULL;
4902 return g_strdup ("");
4904 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4906 MonoException *exc = mono_get_exception_argument ("string", error->message);
4907 g_error_free (error);
4908 mono_raise_exception(exc);
4910 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4911 if (s->length > written) {
4912 /* allocate the total length and copy the part of the string that has been converted */
4913 char *as2 = g_malloc0 (s->length);
4914 memcpy (as2, as, written);
4923 * mono_string_to_utf16:
4926 * Return an null-terminated array of the utf-16 chars
4927 * contained in @s. The result must be freed with g_free().
4928 * This is a temporary helper until our string implementation
4929 * is reworked to always include the null terminating char.
4932 mono_string_to_utf16 (MonoString *s)
4939 as = g_malloc ((s->length * 2) + 2);
4940 as [(s->length * 2)] = '\0';
4941 as [(s->length * 2) + 1] = '\0';
4944 return (gunichar2 *)(as);
4947 memcpy (as, mono_string_chars(s), s->length * 2);
4948 return (gunichar2 *)(as);
4952 * mono_string_from_utf16:
4953 * @data: the UTF16 string (LPWSTR) to convert
4955 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4957 * Returns: a MonoString.
4960 mono_string_from_utf16 (gunichar2 *data)
4962 MonoDomain *domain = mono_domain_get ();
4968 while (data [len]) len++;
4970 return mono_string_new_utf16 (domain, data, len);
4975 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
4982 return mono_string_to_utf8 (s);
4984 r = mono_string_to_utf8 (s);
4988 len = strlen (r) + 1;
4990 mp_s = mono_mempool_alloc (mp, len);
4992 mp_s = mono_image_alloc (image, len);
4994 memcpy (mp_s, r, len);
5002 * mono_string_to_utf8_image:
5003 * @s: a System.String
5005 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5008 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
5010 return mono_string_to_utf8_internal (NULL, image, s);
5014 * mono_string_to_utf8_mp:
5015 * @s: a System.String
5017 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5020 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
5022 return mono_string_to_utf8_internal (mp, NULL, s);
5026 default_ex_handler (MonoException *ex)
5028 MonoObject *o = (MonoObject*)ex;
5029 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5033 static MonoExceptionFunc ex_handler = default_ex_handler;
5036 * mono_install_handler:
5037 * @func: exception handler
5039 * This is an internal JIT routine used to install the handler for exceptions
5043 mono_install_handler (MonoExceptionFunc func)
5045 ex_handler = func? func: default_ex_handler;
5049 * mono_raise_exception:
5050 * @ex: exception object
5052 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5055 mono_raise_exception (MonoException *ex)
5058 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5059 * that will cause gcc to omit the function epilog, causing problems when
5060 * the JIT tries to walk the stack, since the return address on the stack
5061 * will point into the next function in the executable, not this one.
5064 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5065 MonoInternalThread *thread = mono_thread_internal_current ();
5066 g_assert (ex->object.vtable->domain == mono_domain_get ());
5067 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5074 * mono_wait_handle_new:
5075 * @domain: Domain where the object will be created
5076 * @handle: Handle for the wait handle
5078 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5081 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5083 MonoWaitHandle *res;
5084 gpointer params [1];
5085 static MonoMethod *handle_set;
5087 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5089 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5091 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5093 params [0] = &handle;
5094 mono_runtime_invoke (handle_set, res, params, NULL);
5100 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5102 static MonoClassField *f_os_handle;
5103 static MonoClassField *f_safe_handle;
5105 if (!f_os_handle && !f_safe_handle) {
5106 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5107 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5112 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5116 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5123 mono_runtime_capture_context (MonoDomain *domain)
5125 RuntimeInvokeFunction runtime_invoke;
5127 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5128 MonoMethod *method = mono_get_context_capture_method ();
5129 MonoMethod *wrapper;
5132 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5133 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5134 domain->capture_context_method = mono_compile_method (method);
5137 runtime_invoke = domain->capture_context_runtime_invoke;
5139 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5142 * mono_async_result_new:
5143 * @domain:domain where the object will be created.
5144 * @handle: wait handle.
5145 * @state: state to pass to AsyncResult
5146 * @data: C closure data.
5148 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5149 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5153 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5155 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5156 MonoObject *context = mono_runtime_capture_context (domain);
5157 /* we must capture the execution context from the original thread */
5159 MONO_OBJECT_SETREF (res, execution_context, context);
5160 /* note: result may be null if the flow is suppressed */
5164 MONO_OBJECT_SETREF (res, object_data, object_data);
5165 MONO_OBJECT_SETREF (res, async_state, state);
5167 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5169 res->sync_completed = FALSE;
5170 res->completed = FALSE;
5176 mono_message_init (MonoDomain *domain,
5177 MonoMethodMessage *this,
5178 MonoReflectionMethod *method,
5179 MonoArray *out_args)
5181 static MonoClass *object_array_klass;
5182 static MonoClass *byte_array_klass;
5183 static MonoClass *string_array_klass;
5184 MonoMethodSignature *sig = mono_method_signature (method->method);
5190 if (!object_array_klass) {
5193 klass = mono_array_class_get (mono_defaults.object_class, 1);
5196 mono_memory_barrier ();
5197 object_array_klass = klass;
5199 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5202 mono_memory_barrier ();
5203 byte_array_klass = klass;
5205 klass = mono_array_class_get (mono_defaults.string_class, 1);
5208 mono_memory_barrier ();
5209 string_array_klass = klass;
5212 MONO_OBJECT_SETREF (this, method, method);
5214 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5215 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5216 this->async_result = NULL;
5217 this->call_type = CallType_Sync;
5219 names = g_new (char *, sig->param_count);
5220 mono_method_get_param_names (method->method, (const char **) names);
5221 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5223 for (i = 0; i < sig->param_count; i++) {
5224 name = mono_string_new (domain, names [i]);
5225 mono_array_setref (this->names, i, name);
5229 for (i = 0, j = 0; i < sig->param_count; i++) {
5230 if (sig->params [i]->byref) {
5232 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5233 mono_array_setref (this->args, i, arg);
5237 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5241 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5244 mono_array_set (this->arg_types, guint8, i, arg_type);
5249 * mono_remoting_invoke:
5250 * @real_proxy: pointer to a RealProxy object
5251 * @msg: The MonoMethodMessage to execute
5252 * @exc: used to store exceptions
5253 * @out_args: used to store output arguments
5255 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5256 * IMessage interface and it is not trivial to extract results from there. So
5257 * we call an helper method PrivateInvoke instead of calling
5258 * RealProxy::Invoke() directly.
5260 * Returns: the result object.
5263 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5264 MonoObject **exc, MonoArray **out_args)
5266 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5269 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5272 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5274 real_proxy->vtable->domain->private_invoke_method = im;
5277 pa [0] = real_proxy;
5282 return mono_runtime_invoke (im, NULL, pa, exc);
5286 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5287 MonoObject **exc, MonoArray **out_args)
5289 static MonoClass *object_array_klass;
5292 MonoMethodSignature *sig;
5294 int i, j, outarg_count = 0;
5296 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5298 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5299 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5300 target = tp->rp->unwrapped_server;
5302 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5306 domain = mono_domain_get ();
5307 method = msg->method->method;
5308 sig = mono_method_signature (method);
5310 for (i = 0; i < sig->param_count; i++) {
5311 if (sig->params [i]->byref)
5315 if (!object_array_klass) {
5318 klass = mono_array_class_get (mono_defaults.object_class, 1);
5321 mono_memory_barrier ();
5322 object_array_klass = klass;
5325 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5326 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5329 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5331 for (i = 0, j = 0; i < sig->param_count; i++) {
5332 if (sig->params [i]->byref) {
5334 arg = mono_array_get (msg->args, gpointer, i);
5335 mono_array_setref (*out_args, j, arg);
5344 * mono_print_unhandled_exception:
5345 * @exc: The exception
5347 * Prints the unhandled exception.
5350 mono_print_unhandled_exception (MonoObject *exc)
5352 char *message = (char *) "";
5356 gboolean free_message = FALSE;
5358 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5359 klass = exc->vtable->klass;
5361 while (klass && method == NULL) {
5362 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5364 klass = klass->parent;
5369 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5371 message = mono_string_to_utf8 (str);
5372 free_message = TRUE;
5377 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5378 * exc->vtable->klass->name, message);
5380 g_printerr ("\nUnhandled Exception: %s\n", message);
5387 * mono_delegate_ctor:
5388 * @this: pointer to an uninitialized delegate object
5389 * @target: target object
5390 * @addr: pointer to native code
5393 * Initialize a delegate and sets a specific method, not the one
5394 * associated with addr. This is useful when sharing generic code.
5395 * In that case addr will most probably not be associated with the
5396 * correct instantiation of the method.
5399 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5401 MonoDelegate *delegate = (MonoDelegate *)this;
5408 delegate->method = method;
5410 class = this->vtable->klass;
5411 mono_stats.delegate_creations++;
5413 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5415 method = mono_marshal_get_remoting_invoke (method);
5416 delegate->method_ptr = mono_compile_method (method);
5417 MONO_OBJECT_SETREF (delegate, target, target);
5418 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5419 method = mono_marshal_get_unbox_wrapper (method);
5420 delegate->method_ptr = mono_compile_method (method);
5421 MONO_OBJECT_SETREF (delegate, target, target);
5423 delegate->method_ptr = addr;
5424 MONO_OBJECT_SETREF (delegate, target, target);
5427 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5431 * mono_delegate_ctor:
5432 * @this: pointer to an uninitialized delegate object
5433 * @target: target object
5434 * @addr: pointer to native code
5436 * This is used to initialize a delegate.
5439 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5441 MonoDomain *domain = mono_domain_get ();
5443 MonoMethod *method = NULL;
5447 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5448 method = ji->method;
5449 g_assert (!method->klass->generic_container);
5452 mono_delegate_ctor_with_method (this, target, addr, method);
5456 * mono_method_call_message_new:
5457 * @method: method to encapsulate
5458 * @params: parameters to the method
5459 * @invoke: optional, delegate invoke.
5460 * @cb: async callback delegate.
5461 * @state: state passed to the async callback.
5463 * Translates arguments pointers into a MonoMethodMessage.
5466 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5467 MonoDelegate **cb, MonoObject **state)
5469 MonoDomain *domain = mono_domain_get ();
5470 MonoMethodSignature *sig = mono_method_signature (method);
5471 MonoMethodMessage *msg;
5474 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5477 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5478 count = sig->param_count - 2;
5480 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5481 count = sig->param_count;
5484 for (i = 0; i < count; i++) {
5489 if (sig->params [i]->byref)
5490 vpos = *((gpointer *)params [i]);
5494 type = sig->params [i]->type;
5495 class = mono_class_from_mono_type (sig->params [i]);
5497 if (class->valuetype)
5498 arg = mono_value_box (domain, class, vpos);
5500 arg = *((MonoObject **)vpos);
5502 mono_array_setref (msg->args, i, arg);
5505 if (cb != NULL && state != NULL) {
5506 *cb = *((MonoDelegate **)params [i]);
5508 *state = *((MonoObject **)params [i]);
5515 * mono_method_return_message_restore:
5517 * Restore results from message based processing back to arguments pointers
5520 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5522 MonoMethodSignature *sig = mono_method_signature (method);
5523 int i, j, type, size, out_len;
5525 if (out_args == NULL)
5527 out_len = mono_array_length (out_args);
5531 for (i = 0, j = 0; i < sig->param_count; i++) {
5532 MonoType *pt = sig->params [i];
5537 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5539 arg = mono_array_get (out_args, gpointer, j);
5543 case MONO_TYPE_VOID:
5544 g_assert_not_reached ();
5548 case MONO_TYPE_BOOLEAN:
5551 case MONO_TYPE_CHAR:
5558 case MONO_TYPE_VALUETYPE: {
5560 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5561 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5564 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5565 memset (*((gpointer *)params [i]), 0, size);
5569 case MONO_TYPE_STRING:
5570 case MONO_TYPE_CLASS:
5571 case MONO_TYPE_ARRAY:
5572 case MONO_TYPE_SZARRAY:
5573 case MONO_TYPE_OBJECT:
5574 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5577 g_assert_not_reached ();
5586 * mono_load_remote_field:
5587 * @this: pointer to an object
5588 * @klass: klass of the object containing @field
5589 * @field: the field to load
5590 * @res: a storage to store the result
5592 * This method is called by the runtime on attempts to load fields of
5593 * transparent proxy objects. @this points to such TP, @klass is the class of
5594 * the object containing @field. @res is a storage location which can be
5595 * used to store the result.
5597 * Returns: an address pointing to the value of field.
5600 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
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;
5611 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5612 g_assert (res != NULL);
5614 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5615 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5620 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5624 field_class = mono_class_from_mono_type (field->type);
5626 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5627 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5628 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5630 full_name = mono_type_get_full_name (klass);
5631 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5632 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5635 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5637 if (exc) mono_raise_exception ((MonoException *)exc);
5639 if (mono_array_length (out_args) == 0)
5642 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5644 if (field_class->valuetype) {
5645 return ((char *)*res) + sizeof (MonoObject);
5651 * mono_load_remote_field_new:
5656 * Missing documentation.
5659 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5661 static MonoMethod *getter = NULL;
5662 MonoDomain *domain = mono_domain_get ();
5663 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5664 MonoClass *field_class;
5665 MonoMethodMessage *msg;
5666 MonoArray *out_args;
5667 MonoObject *exc, *res;
5670 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5672 field_class = mono_class_from_mono_type (field->type);
5674 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5676 if (field_class->valuetype) {
5677 res = mono_object_new (domain, field_class);
5678 val = ((gchar *) res) + sizeof (MonoObject);
5682 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5687 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5691 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5692 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5694 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5696 full_name = mono_type_get_full_name (klass);
5697 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5698 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5701 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5703 if (exc) mono_raise_exception ((MonoException *)exc);
5705 if (mono_array_length (out_args) == 0)
5708 res = mono_array_get (out_args, MonoObject *, 0);
5714 * mono_store_remote_field:
5715 * @this: pointer to an object
5716 * @klass: klass of the object containing @field
5717 * @field: the field to load
5718 * @val: the value/object to store
5720 * This method is called by the runtime on attempts to store fields of
5721 * transparent proxy objects. @this points to such TP, @klass is the class of
5722 * the object containing @field. @val is the new value to store in @field.
5725 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5727 static MonoMethod *setter = NULL;
5728 MonoDomain *domain = mono_domain_get ();
5729 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5730 MonoClass *field_class;
5731 MonoMethodMessage *msg;
5732 MonoArray *out_args;
5737 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5739 field_class = mono_class_from_mono_type (field->type);
5741 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5742 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5743 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5748 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5752 if (field_class->valuetype)
5753 arg = mono_value_box (domain, field_class, val);
5755 arg = *((MonoObject **)val);
5758 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5759 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5761 full_name = mono_type_get_full_name (klass);
5762 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5763 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5764 mono_array_setref (msg->args, 2, arg);
5767 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5769 if (exc) mono_raise_exception ((MonoException *)exc);
5773 * mono_store_remote_field_new:
5779 * Missing documentation
5782 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5784 static MonoMethod *setter = NULL;
5785 MonoDomain *domain = mono_domain_get ();
5786 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5787 MonoClass *field_class;
5788 MonoMethodMessage *msg;
5789 MonoArray *out_args;
5793 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5795 field_class = mono_class_from_mono_type (field->type);
5797 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5798 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5799 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5804 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5808 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5809 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5811 full_name = mono_type_get_full_name (klass);
5812 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5813 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5814 mono_array_setref (msg->args, 2, arg);
5817 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5819 if (exc) mono_raise_exception ((MonoException *)exc);
5823 * mono_create_ftnptr:
5825 * Given a function address, create a function descriptor for it.
5826 * This is only needed on some platforms.
5829 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5831 return callbacks.create_ftnptr (domain, addr);
5835 * mono_get_addr_from_ftnptr:
5837 * Given a pointer to a function descriptor, return the function address.
5838 * This is only needed on some platforms.
5841 mono_get_addr_from_ftnptr (gpointer descr)
5843 return callbacks.get_addr_from_ftnptr (descr);
5848 * mono_string_chars:
5851 * Returns a pointer to the UCS16 characters stored in the MonoString
5854 mono_string_chars(MonoString *s)
5856 /* This method is here only for documentation extraction, this is a macro */
5860 * mono_string_length:
5863 * Returns the lenght in characters of the string
5866 mono_string_length (MonoString *s)
5868 /* This method is here only for documentation extraction, this is a macro */