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)
2584 if (mono_runtime_get_no_exec ())
2585 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2587 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2588 mono_profiler_method_start_invoke (method);
2590 result = default_mono_runtime_invoke (method, obj, params, exc);
2592 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2593 mono_profiler_method_end_invoke (method);
2599 * mono_method_get_unmanaged_thunk:
2600 * @method: method to generate a thunk for.
2602 * Returns an unmanaged->managed thunk that can be used to call
2603 * a managed method directly from C.
2605 * The thunk's C signature closely matches the managed signature:
2607 * C#: public bool Equals (object obj);
2608 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2609 * MonoObject*, MonoException**);
2611 * The 1st ("this") parameter must not be used with static methods:
2613 * C#: public static bool ReferenceEquals (object a, object b);
2614 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2617 * The last argument must be a non-null pointer of a MonoException* pointer.
2618 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2619 * exception has been thrown in managed code. Otherwise it will point
2620 * to the MonoException* caught by the thunk. In this case, the result of
2621 * the thunk is undefined:
2623 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2624 * MonoException *ex = NULL;
2625 * Equals func = mono_method_get_unmanaged_thunk (method);
2626 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2628 * // handle exception
2631 * The calling convention of the thunk matches the platform's default
2632 * convention. This means that under Windows, C declarations must
2633 * contain the __stdcall attribute:
2635 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2636 * MonoObject*, MonoException**);
2640 * Value type arguments and return values are treated as they were objects:
2642 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2643 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2645 * Arguments must be properly boxed upon trunk's invocation, while return
2646 * values must be unboxed.
2649 mono_method_get_unmanaged_thunk (MonoMethod *method)
2651 method = mono_marshal_get_thunk_invoke_wrapper (method);
2652 return mono_compile_method (method);
2656 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2660 /* object fields cannot be byref, so we don't need a
2662 gpointer *p = (gpointer*)dest;
2669 case MONO_TYPE_BOOLEAN:
2671 case MONO_TYPE_U1: {
2672 guint8 *p = (guint8*)dest;
2673 *p = value ? *(guint8*)value : 0;
2678 case MONO_TYPE_CHAR: {
2679 guint16 *p = (guint16*)dest;
2680 *p = value ? *(guint16*)value : 0;
2683 #if SIZEOF_VOID_P == 4
2688 case MONO_TYPE_U4: {
2689 gint32 *p = (gint32*)dest;
2690 *p = value ? *(gint32*)value : 0;
2693 #if SIZEOF_VOID_P == 8
2698 case MONO_TYPE_U8: {
2699 gint64 *p = (gint64*)dest;
2700 *p = value ? *(gint64*)value : 0;
2703 case MONO_TYPE_R4: {
2704 float *p = (float*)dest;
2705 *p = value ? *(float*)value : 0;
2708 case MONO_TYPE_R8: {
2709 double *p = (double*)dest;
2710 *p = value ? *(double*)value : 0;
2713 case MONO_TYPE_STRING:
2714 case MONO_TYPE_SZARRAY:
2715 case MONO_TYPE_CLASS:
2716 case MONO_TYPE_OBJECT:
2717 case MONO_TYPE_ARRAY:
2718 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2720 case MONO_TYPE_FNPTR:
2721 case MONO_TYPE_PTR: {
2722 gpointer *p = (gpointer*)dest;
2723 *p = deref_pointer? *(gpointer*)value: value;
2726 case MONO_TYPE_VALUETYPE:
2727 /* note that 't' and 'type->type' can be different */
2728 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2729 t = mono_class_enum_basetype (type->data.klass)->type;
2732 MonoClass *class = mono_class_from_mono_type (type);
2733 int size = mono_class_value_size (class, NULL);
2735 memset (dest, 0, size);
2737 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2740 case MONO_TYPE_GENERICINST:
2741 t = type->data.generic_class->container_class->byval_arg.type;
2744 g_warning ("got type %x", type->type);
2745 g_assert_not_reached ();
2750 * mono_field_set_value:
2751 * @obj: Instance object
2752 * @field: MonoClassField describing the field to set
2753 * @value: The value to be set
2755 * Sets the value of the field described by @field in the object instance @obj
2756 * to the value passed in @value. This method should only be used for instance
2757 * fields. For static fields, use mono_field_static_set_value.
2759 * The value must be on the native format of the field type.
2762 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2766 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2768 dest = (char*)obj + field->offset;
2769 set_value (field->type, dest, value, FALSE);
2773 * mono_field_static_set_value:
2774 * @field: MonoClassField describing the field to set
2775 * @value: The value to be set
2777 * Sets the value of the static field described by @field
2778 * to the value passed in @value.
2780 * The value must be on the native format of the field type.
2783 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2787 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2788 /* you cant set a constant! */
2789 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2791 if (field->offset == -1) {
2792 /* Special static */
2793 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2794 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2796 dest = (char*)vt->data + field->offset;
2798 set_value (field->type, dest, value, FALSE);
2801 /* Used by the debugger */
2803 mono_vtable_get_static_field_data (MonoVTable *vt)
2809 * mono_field_get_value:
2810 * @obj: Object instance
2811 * @field: MonoClassField describing the field to fetch information from
2812 * @value: pointer to the location where the value will be stored
2814 * Use this routine to get the value of the field @field in the object
2817 * The pointer provided by value must be of the field type, for reference
2818 * types this is a MonoObject*, for value types its the actual pointer to
2823 * mono_field_get_value (obj, int_field, &i);
2826 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2830 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2832 src = (char*)obj + field->offset;
2833 set_value (field->type, value, src, TRUE);
2837 * mono_field_get_value_object:
2838 * @domain: domain where the object will be created (if boxing)
2839 * @field: MonoClassField describing the field to fetch information from
2840 * @obj: The object instance for the field.
2842 * Returns: a new MonoObject with the value from the given field. If the
2843 * field represents a value type, the value is boxed.
2847 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2851 MonoVTable *vtable = NULL;
2853 gboolean is_static = FALSE;
2854 gboolean is_ref = FALSE;
2856 switch (field->type->type) {
2857 case MONO_TYPE_STRING:
2858 case MONO_TYPE_OBJECT:
2859 case MONO_TYPE_CLASS:
2860 case MONO_TYPE_ARRAY:
2861 case MONO_TYPE_SZARRAY:
2866 case MONO_TYPE_BOOLEAN:
2869 case MONO_TYPE_CHAR:
2878 case MONO_TYPE_VALUETYPE:
2879 is_ref = field->type->byref;
2881 case MONO_TYPE_GENERICINST:
2882 is_ref = !field->type->data.generic_class->container_class->valuetype;
2885 g_error ("type 0x%x not handled in "
2886 "mono_field_get_value_object", field->type->type);
2890 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2892 vtable = mono_class_vtable (domain, field->parent);
2894 char *name = mono_type_get_full_name (field->parent);
2895 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2899 if (!vtable->initialized)
2900 mono_runtime_class_init (vtable);
2905 mono_field_static_get_value (vtable, field, &o);
2907 mono_field_get_value (obj, field, &o);
2912 /* boxed value type */
2913 klass = mono_class_from_mono_type (field->type);
2914 o = mono_object_new (domain, klass);
2915 v = ((gchar *) o) + sizeof (MonoObject);
2917 mono_field_static_get_value (vtable, field, v);
2919 mono_field_get_value (obj, field, v);
2926 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2929 const char *p = blob;
2930 mono_metadata_decode_blob_size (p, &p);
2933 case MONO_TYPE_BOOLEAN:
2936 *(guint8 *) value = *p;
2938 case MONO_TYPE_CHAR:
2941 *(guint16*) value = read16 (p);
2945 *(guint32*) value = read32 (p);
2949 *(guint64*) value = read64 (p);
2952 readr4 (p, (float*) value);
2955 readr8 (p, (double*) value);
2957 case MONO_TYPE_STRING:
2958 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2960 case MONO_TYPE_CLASS:
2961 *(gpointer*) value = NULL;
2965 g_warning ("type 0x%02x should not be in constant table", type);
2971 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2973 MonoTypeEnum def_type;
2976 data = mono_class_get_field_default_value (field, &def_type);
2977 mono_get_constant_value_from_blob (domain, def_type, data, value);
2981 * mono_field_static_get_value:
2982 * @vt: vtable to the object
2983 * @field: MonoClassField describing the field to fetch information from
2984 * @value: where the value is returned
2986 * Use this routine to get the value of the static field @field value.
2988 * The pointer provided by value must be of the field type, for reference
2989 * types this is a MonoObject*, for value types its the actual pointer to
2994 * mono_field_static_get_value (vt, int_field, &i);
2997 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3001 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3003 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3004 get_default_field_value (vt->domain, field, value);
3008 if (field->offset == -1) {
3009 /* Special static */
3010 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3011 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3013 src = (char*)vt->data + field->offset;
3015 set_value (field->type, value, src, TRUE);
3019 * mono_property_set_value:
3020 * @prop: MonoProperty to set
3021 * @obj: instance object on which to act
3022 * @params: parameters to pass to the propery
3023 * @exc: optional exception
3025 * Invokes the property's set method with the given arguments on the
3026 * object instance obj (or NULL for static properties).
3028 * You can pass NULL as the exc argument if you don't want to
3029 * catch exceptions, otherwise, *exc will be set to the exception
3030 * thrown, if any. if an exception is thrown, you can't use the
3031 * MonoObject* result from the function.
3034 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3036 default_mono_runtime_invoke (prop->set, obj, params, exc);
3040 * mono_property_get_value:
3041 * @prop: MonoProperty to fetch
3042 * @obj: instance object on which to act
3043 * @params: parameters to pass to the propery
3044 * @exc: optional exception
3046 * Invokes the property's get method with the given arguments on the
3047 * object instance obj (or NULL for static properties).
3049 * You can pass NULL as the exc argument if you don't want to
3050 * catch exceptions, otherwise, *exc will be set to the exception
3051 * thrown, if any. if an exception is thrown, you can't use the
3052 * MonoObject* result from the function.
3054 * Returns: the value from invoking the get method on the property.
3057 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3059 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3063 * mono_nullable_init:
3064 * @buf: The nullable structure to initialize.
3065 * @value: the value to initialize from
3066 * @klass: the type for the object
3068 * Initialize the nullable structure pointed to by @buf from @value which
3069 * should be a boxed value type. The size of @buf should be able to hold
3070 * as much data as the @klass->instance_size (which is the number of bytes
3071 * that will be copies).
3073 * Since Nullables have variable structure, we can not define a C
3074 * structure for them.
3077 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3079 MonoClass *param_class = klass->cast_class;
3081 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3082 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3084 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3086 if (param_class->has_references)
3087 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3089 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3091 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3096 * mono_nullable_box:
3097 * @buf: The buffer representing the data to be boxed
3098 * @klass: the type to box it as.
3100 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3104 mono_nullable_box (guint8 *buf, MonoClass *klass)
3106 MonoClass *param_class = klass->cast_class;
3108 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3109 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3111 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3112 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3113 if (param_class->has_references)
3114 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3116 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3124 * mono_get_delegate_invoke:
3125 * @klass: The delegate class
3127 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3130 mono_get_delegate_invoke (MonoClass *klass)
3134 /* This is called at runtime, so avoid the slower search in metadata */
3135 mono_class_setup_methods (klass);
3137 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3144 * mono_runtime_delegate_invoke:
3145 * @delegate: pointer to a delegate object.
3146 * @params: parameters for the delegate.
3147 * @exc: Pointer to the exception result.
3149 * Invokes the delegate method @delegate with the parameters provided.
3151 * You can pass NULL as the exc argument if you don't want to
3152 * catch exceptions, otherwise, *exc will be set to the exception
3153 * thrown, if any. if an exception is thrown, you can't use the
3154 * MonoObject* result from the function.
3157 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3161 im = mono_get_delegate_invoke (delegate->vtable->klass);
3164 return mono_runtime_invoke (im, delegate, params, exc);
3167 static char **main_args = NULL;
3168 static int num_main_args;
3171 * mono_runtime_get_main_args:
3173 * Returns: a MonoArray with the arguments passed to the main program
3176 mono_runtime_get_main_args (void)
3180 MonoDomain *domain = mono_domain_get ();
3185 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3187 for (i = 0; i < num_main_args; ++i)
3188 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3194 fire_process_exit_event (void)
3196 MonoClassField *field;
3197 MonoDomain *domain = mono_domain_get ();
3199 MonoObject *delegate, *exc;
3201 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3204 if (domain != mono_get_root_domain ())
3207 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3208 if (delegate == NULL)
3213 mono_runtime_delegate_invoke (delegate, pa, &exc);
3217 * mono_runtime_run_main:
3218 * @method: the method to start the application with (usually Main)
3219 * @argc: number of arguments from the command line
3220 * @argv: array of strings from the command line
3221 * @exc: excetption results
3223 * Execute a standard Main() method (argc/argv contains the
3224 * executable name). This method also sets the command line argument value
3225 * needed by System.Environment.
3230 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3234 MonoArray *args = NULL;
3235 MonoDomain *domain = mono_domain_get ();
3236 gchar *utf8_fullpath;
3239 g_assert (method != NULL);
3241 mono_thread_set_main (mono_thread_current ());
3243 main_args = g_new0 (char*, argc);
3244 num_main_args = argc;
3246 if (!g_path_is_absolute (argv [0])) {
3247 gchar *basename = g_path_get_basename (argv [0]);
3248 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3252 utf8_fullpath = mono_utf8_from_external (fullpath);
3253 if(utf8_fullpath == NULL) {
3254 /* Printing the arg text will cause glib to
3255 * whinge about "Invalid UTF-8", but at least
3256 * its relevant, and shows the problem text
3259 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3260 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3267 utf8_fullpath = mono_utf8_from_external (argv[0]);
3268 if(utf8_fullpath == NULL) {
3269 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3270 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3275 main_args [0] = utf8_fullpath;
3277 for (i = 1; i < argc; ++i) {
3280 utf8_arg=mono_utf8_from_external (argv[i]);
3281 if(utf8_arg==NULL) {
3282 /* Ditto the comment about Invalid UTF-8 here */
3283 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3284 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3288 main_args [i] = utf8_arg;
3292 if (mono_method_signature (method)->param_count) {
3293 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3294 for (i = 0; i < argc; ++i) {
3295 /* The encodings should all work, given that
3296 * we've checked all these args for the
3299 gchar *str = mono_utf8_from_external (argv [i]);
3300 MonoString *arg = mono_string_new (domain, str);
3301 mono_array_setref (args, i, arg);
3305 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3308 mono_assembly_set_main (method->klass->image->assembly);
3310 result = mono_runtime_exec_main (method, args, exc);
3311 fire_process_exit_event ();
3316 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3318 static MonoMethod *serialize_method;
3323 if (!serialize_method) {
3324 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3325 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3328 if (!serialize_method) {
3333 g_assert (!mono_object_class (obj)->marshalbyref);
3337 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3345 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3347 static MonoMethod *deserialize_method;
3352 if (!deserialize_method) {
3353 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3354 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3356 if (!deserialize_method) {
3363 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3371 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3373 static MonoMethod *get_proxy_method;
3375 MonoDomain *domain = mono_domain_get ();
3376 MonoRealProxy *real_proxy;
3377 MonoReflectionType *reflection_type;
3378 MonoTransparentProxy *transparent_proxy;
3380 if (!get_proxy_method)
3381 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3383 g_assert (obj->vtable->klass->marshalbyref);
3385 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3386 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3388 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3389 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3392 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3396 return (MonoObject*) transparent_proxy;
3400 * mono_object_xdomain_representation
3402 * @target_domain: a domain
3403 * @exc: pointer to a MonoObject*
3405 * Creates a representation of obj in the domain target_domain. This
3406 * is either a copy of obj arrived through via serialization and
3407 * deserialization or a proxy, depending on whether the object is
3408 * serializable or marshal by ref. obj must not be in target_domain.
3410 * If the object cannot be represented in target_domain, NULL is
3411 * returned and *exc is set to an appropriate exception.
3414 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3416 MonoObject *deserialized = NULL;
3417 gboolean failure = FALSE;
3421 if (mono_object_class (obj)->marshalbyref) {
3422 deserialized = make_transparent_proxy (obj, &failure, exc);
3424 MonoDomain *domain = mono_domain_get ();
3425 MonoObject *serialized;
3427 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3428 serialized = serialize_object (obj, &failure, exc);
3429 mono_domain_set_internal_with_options (target_domain, FALSE);
3431 deserialized = deserialize_object (serialized, &failure, exc);
3432 if (domain != target_domain)
3433 mono_domain_set_internal_with_options (domain, FALSE);
3436 return deserialized;
3439 /* Used in call_unhandled_exception_delegate */
3441 create_unhandled_exception_eventargs (MonoObject *exc)
3445 MonoMethod *method = NULL;
3446 MonoBoolean is_terminating = TRUE;
3449 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3452 mono_class_init (klass);
3454 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3455 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3459 args [1] = &is_terminating;
3461 obj = mono_object_new (mono_domain_get (), klass);
3462 mono_runtime_invoke (method, obj, args, NULL);
3467 /* Used in mono_unhandled_exception */
3469 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3470 MonoObject *e = NULL;
3472 MonoDomain *current_domain = mono_domain_get ();
3474 if (domain != current_domain)
3475 mono_domain_set_internal_with_options (domain, FALSE);
3477 g_assert (domain == mono_object_domain (domain->domain));
3479 if (mono_object_domain (exc) != domain) {
3480 MonoObject *serialization_exc;
3482 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3484 if (serialization_exc) {
3486 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3489 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3490 "System.Runtime.Serialization", "SerializationException",
3491 "Could not serialize unhandled exception.");
3495 g_assert (mono_object_domain (exc) == domain);
3497 pa [0] = domain->domain;
3498 pa [1] = create_unhandled_exception_eventargs (exc);
3499 mono_runtime_delegate_invoke (delegate, pa, &e);
3501 if (domain != current_domain)
3502 mono_domain_set_internal_with_options (current_domain, FALSE);
3505 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
3506 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3511 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3514 * mono_runtime_unhandled_exception_policy_set:
3515 * @policy: the new policy
3517 * This is a VM internal routine.
3519 * Sets the runtime policy for handling unhandled exceptions.
3522 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3523 runtime_unhandled_exception_policy = policy;
3527 * mono_runtime_unhandled_exception_policy_get:
3529 * This is a VM internal routine.
3531 * Gets the runtime policy for handling unhandled exceptions.
3533 MonoRuntimeUnhandledExceptionPolicy
3534 mono_runtime_unhandled_exception_policy_get (void) {
3535 return runtime_unhandled_exception_policy;
3539 * mono_unhandled_exception:
3540 * @exc: exception thrown
3542 * This is a VM internal routine.
3544 * We call this function when we detect an unhandled exception
3545 * in the default domain.
3547 * It invokes the * UnhandledException event in AppDomain or prints
3548 * a warning to the console
3551 mono_unhandled_exception (MonoObject *exc)
3553 MonoDomain *current_domain = mono_domain_get ();
3554 MonoDomain *root_domain = mono_get_root_domain ();
3555 MonoClassField *field;
3556 MonoObject *current_appdomain_delegate;
3557 MonoObject *root_appdomain_delegate;
3559 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3560 "UnhandledException");
3563 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3564 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3565 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3566 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3567 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3568 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3570 current_appdomain_delegate = NULL;
3573 /* set exitcode only if we will abort the process */
3575 mono_environment_exitcode_set (1);
3576 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3577 mono_print_unhandled_exception (exc);
3579 if (root_appdomain_delegate) {
3580 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3582 if (current_appdomain_delegate) {
3583 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3590 * Launch a new thread to execute a function
3592 * main_func is called back from the thread with main_args as the
3593 * parameter. The callback function is expected to start Main()
3594 * eventually. This function then waits for all managed threads to
3596 * It is not necesseray anymore to execute managed code in a subthread,
3597 * so this function should not be used anymore by default: just
3598 * execute the code and then call mono_thread_manage ().
3601 mono_runtime_exec_managed_code (MonoDomain *domain,
3602 MonoMainThreadFunc main_func,
3605 mono_thread_create (domain, main_func, main_args);
3607 mono_thread_manage ();
3611 * Execute a standard Main() method (args doesn't contain the
3615 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3620 MonoCustomAttrInfo* cinfo;
3621 gboolean has_stathread_attribute;
3622 MonoInternalThread* thread = mono_thread_internal_current ();
3628 domain = mono_object_domain (args);
3629 if (!domain->entry_assembly) {
3631 MonoAssembly *assembly;
3633 assembly = method->klass->image->assembly;
3634 domain->entry_assembly = assembly;
3635 /* Domains created from another domain already have application_base and configuration_file set */
3636 if (domain->setup->application_base == NULL) {
3637 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3640 if (domain->setup->configuration_file == NULL) {
3641 str = g_strconcat (assembly->image->name, ".config", NULL);
3642 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3644 mono_set_private_bin_path_from_config (domain);
3648 cinfo = mono_custom_attrs_from_method (method);
3650 static MonoClass *stathread_attribute = NULL;
3651 if (!stathread_attribute)
3652 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3653 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3655 mono_custom_attrs_free (cinfo);
3657 has_stathread_attribute = FALSE;
3659 if (has_stathread_attribute) {
3660 thread->apartment_state = ThreadApartmentState_STA;
3661 } else if (mono_framework_version () == 1) {
3662 thread->apartment_state = ThreadApartmentState_Unknown;
3664 thread->apartment_state = ThreadApartmentState_MTA;
3666 mono_thread_init_apartment_state ();
3668 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3670 /* FIXME: check signature of method */
3671 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3673 res = mono_runtime_invoke (method, NULL, pa, exc);
3675 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3679 mono_environment_exitcode_set (rval);
3681 mono_runtime_invoke (method, NULL, pa, exc);
3685 /* If the return type of Main is void, only
3686 * set the exitcode if an exception was thrown
3687 * (we don't want to blow away an
3688 * explicitly-set exit code)
3691 mono_environment_exitcode_set (rval);
3695 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3701 * mono_install_runtime_invoke:
3702 * @func: Function to install
3704 * This is a VM internal routine
3707 mono_install_runtime_invoke (MonoInvokeFunc func)
3709 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3714 * mono_runtime_invoke_array:
3715 * @method: method to invoke
3716 * @obJ: object instance
3717 * @params: arguments to the method
3718 * @exc: exception information.
3720 * Invokes the method represented by @method on the object @obj.
3722 * obj is the 'this' pointer, it should be NULL for static
3723 * methods, a MonoObject* for object instances and a pointer to
3724 * the value type for value types.
3726 * The params array contains the arguments to the method with the
3727 * same convention: MonoObject* pointers for object instances and
3728 * pointers to the value type otherwise. The _invoke_array
3729 * variant takes a C# object[] as the params argument (MonoArray
3730 * *params): in this case the value types are boxed inside the
3731 * respective reference representation.
3733 * From unmanaged code you'll usually use the
3734 * mono_runtime_invoke() variant.
3736 * Note that this function doesn't handle virtual methods for
3737 * you, it will exec the exact method you pass: we still need to
3738 * expose a function to lookup the derived class implementation
3739 * of a virtual method (there are examples of this in the code,
3742 * You can pass NULL as the exc argument if you don't want to
3743 * catch exceptions, otherwise, *exc will be set to the exception
3744 * thrown, if any. if an exception is thrown, you can't use the
3745 * MonoObject* result from the function.
3747 * If the method returns a value type, it is boxed in an object
3751 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3754 MonoMethodSignature *sig = mono_method_signature (method);
3755 gpointer *pa = NULL;
3758 gboolean has_byref_nullables = FALSE;
3760 if (NULL != params) {
3761 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3762 for (i = 0; i < mono_array_length (params); i++) {
3763 MonoType *t = sig->params [i];
3769 case MONO_TYPE_BOOLEAN:
3772 case MONO_TYPE_CHAR:
3781 case MONO_TYPE_VALUETYPE:
3782 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3783 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3784 pa [i] = mono_array_get (params, MonoObject*, i);
3786 has_byref_nullables = TRUE;
3788 /* MS seems to create the objects if a null is passed in */
3789 if (!mono_array_get (params, MonoObject*, i))
3790 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3794 * We can't pass the unboxed vtype byref to the callee, since
3795 * that would mean the callee would be able to modify boxed
3796 * primitive types. So we (and MS) make a copy of the boxed
3797 * object, pass that to the callee, and replace the original
3798 * boxed object in the arg array with the copy.
3800 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3801 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3802 mono_array_setref (params, i, copy);
3805 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3808 case MONO_TYPE_STRING:
3809 case MONO_TYPE_OBJECT:
3810 case MONO_TYPE_CLASS:
3811 case MONO_TYPE_ARRAY:
3812 case MONO_TYPE_SZARRAY:
3814 pa [i] = mono_array_addr (params, MonoObject*, i);
3815 // FIXME: I need to check this code path
3817 pa [i] = mono_array_get (params, MonoObject*, i);
3819 case MONO_TYPE_GENERICINST:
3821 t = &t->data.generic_class->container_class->this_arg;
3823 t = &t->data.generic_class->container_class->byval_arg;
3825 case MONO_TYPE_PTR: {
3828 /* The argument should be an IntPtr */
3829 arg = mono_array_get (params, MonoObject*, i);
3833 g_assert (arg->vtable->klass == mono_defaults.int_class);
3834 pa [i] = ((MonoIntPtr*)arg)->m_value;
3839 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3844 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3847 if (mono_class_is_nullable (method->klass)) {
3848 /* Need to create a boxed vtype instead */
3854 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3858 obj = mono_object_new (mono_domain_get (), method->klass);
3859 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3860 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3862 if (method->klass->valuetype)
3863 o = mono_object_unbox (obj);
3866 } else if (method->klass->valuetype) {
3867 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3870 mono_runtime_invoke (method, o, pa, exc);
3873 if (mono_class_is_nullable (method->klass)) {
3874 MonoObject *nullable;
3876 /* Convert the unboxed vtype into a Nullable structure */
3877 nullable = mono_object_new (mono_domain_get (), method->klass);
3879 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3880 obj = mono_object_unbox (nullable);
3883 /* obj must be already unboxed if needed */
3884 res = mono_runtime_invoke (method, obj, pa, exc);
3886 if (sig->ret->type == MONO_TYPE_PTR) {
3887 MonoClass *pointer_class;
3888 static MonoMethod *box_method;
3890 MonoObject *box_exc;
3893 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3894 * convert it to a Pointer object.
3896 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3898 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3900 g_assert (res->vtable->klass == mono_defaults.int_class);
3901 box_args [0] = ((MonoIntPtr*)res)->m_value;
3902 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3903 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3904 g_assert (!box_exc);
3907 if (has_byref_nullables) {
3909 * The runtime invoke wrapper already converted byref nullables back,
3910 * and stored them in pa, we just need to copy them back to the
3913 for (i = 0; i < mono_array_length (params); i++) {
3914 MonoType *t = sig->params [i];
3916 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3917 mono_array_setref (params, i, pa [i]);
3926 arith_overflow (void)
3928 mono_raise_exception (mono_get_exception_overflow ());
3932 * mono_object_allocate:
3933 * @size: number of bytes to allocate
3935 * This is a very simplistic routine until we have our GC-aware
3938 * Returns: an allocated object of size @size, or NULL on failure.
3940 static inline void *
3941 mono_object_allocate (size_t size, MonoVTable *vtable)
3944 mono_stats.new_object_count++;
3945 ALLOC_OBJECT (o, vtable, size);
3951 * mono_object_allocate_ptrfree:
3952 * @size: number of bytes to allocate
3954 * Note that the memory allocated is not zeroed.
3955 * Returns: an allocated object of size @size, or NULL on failure.
3957 static inline void *
3958 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3961 mono_stats.new_object_count++;
3962 ALLOC_PTRFREE (o, vtable, size);
3966 static inline void *
3967 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3970 ALLOC_TYPED (o, size, vtable);
3971 mono_stats.new_object_count++;
3978 * @klass: the class of the object that we want to create
3980 * Returns: a newly created object whose definition is
3981 * looked up using @klass. This will not invoke any constructors,
3982 * so the consumer of this routine has to invoke any constructors on
3983 * its own to initialize the object.
3985 * It returns NULL on failure.
3988 mono_object_new (MonoDomain *domain, MonoClass *klass)
3992 MONO_ARCH_SAVE_REGS;
3993 vtable = mono_class_vtable (domain, klass);
3996 return mono_object_new_specific (vtable);
4000 * mono_object_new_specific:
4001 * @vtable: the vtable of the object that we want to create
4003 * Returns: A newly created object with class and domain specified
4007 mono_object_new_specific (MonoVTable *vtable)
4011 MONO_ARCH_SAVE_REGS;
4013 /* check for is_com_object for COM Interop */
4014 if (vtable->remote || vtable->klass->is_com_object)
4017 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4020 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4023 mono_class_init (klass);
4025 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4027 vtable->domain->create_proxy_for_type_method = im;
4030 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4032 o = mono_runtime_invoke (im, NULL, pa, NULL);
4033 if (o != NULL) return o;
4036 return mono_object_new_alloc_specific (vtable);
4040 mono_object_new_alloc_specific (MonoVTable *vtable)
4044 if (!vtable->klass->has_references) {
4045 o = mono_object_new_ptrfree (vtable);
4046 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4047 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4049 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4050 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4052 if (G_UNLIKELY (vtable->klass->has_finalize))
4053 mono_object_register_finalizer (o);
4055 if (G_UNLIKELY (profile_allocs))
4056 mono_profiler_allocation (o, vtable->klass);
4061 mono_object_new_fast (MonoVTable *vtable)
4064 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4069 mono_object_new_ptrfree (MonoVTable *vtable)
4072 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4073 #if NEED_TO_ZERO_PTRFREE
4074 /* an inline memset is much faster for the common vcase of small objects
4075 * note we assume the allocated size is a multiple of sizeof (void*).
4077 if (vtable->klass->instance_size < 128) {
4079 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4080 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4086 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4093 mono_object_new_ptrfree_box (MonoVTable *vtable)
4096 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4097 /* the object will be boxed right away, no need to memzero it */
4102 * mono_class_get_allocation_ftn:
4104 * @for_box: the object will be used for boxing
4105 * @pass_size_in_words:
4107 * Return the allocation function appropriate for the given class.
4111 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4113 *pass_size_in_words = FALSE;
4115 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4116 profile_allocs = FALSE;
4118 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4119 return mono_object_new_specific;
4121 if (!vtable->klass->has_references) {
4122 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4124 return mono_object_new_ptrfree_box;
4125 return mono_object_new_ptrfree;
4128 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4130 return mono_object_new_fast;
4133 * FIXME: This is actually slower than mono_object_new_fast, because
4134 * of the overhead of parameter passing.
4137 *pass_size_in_words = TRUE;
4138 #ifdef GC_REDIRECT_TO_LOCAL
4139 return GC_local_gcj_fast_malloc;
4141 return GC_gcj_fast_malloc;
4146 return mono_object_new_specific;
4150 * mono_object_new_from_token:
4151 * @image: Context where the type_token is hosted
4152 * @token: a token of the type that we want to create
4154 * Returns: A newly created object whose definition is
4155 * looked up using @token in the @image image
4158 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4162 class = mono_class_get (image, token);
4164 return mono_object_new (domain, class);
4169 * mono_object_clone:
4170 * @obj: the object to clone
4172 * Returns: A newly created object who is a shallow copy of @obj
4175 mono_object_clone (MonoObject *obj)
4178 int size = obj->vtable->klass->instance_size;
4180 o = mono_object_allocate (size, obj->vtable);
4182 if (obj->vtable->klass->has_references) {
4183 mono_gc_wbarrier_object_copy (o, obj);
4185 int size = obj->vtable->klass->instance_size;
4186 /* do not copy the sync state */
4187 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4189 if (G_UNLIKELY (profile_allocs))
4190 mono_profiler_allocation (o, obj->vtable->klass);
4192 if (obj->vtable->klass->has_finalize)
4193 mono_object_register_finalizer (o);
4198 * mono_array_full_copy:
4199 * @src: source array to copy
4200 * @dest: destination array
4202 * Copies the content of one array to another with exactly the same type and size.
4205 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4207 mono_array_size_t size;
4208 MonoClass *klass = src->obj.vtable->klass;
4210 MONO_ARCH_SAVE_REGS;
4212 g_assert (klass == dest->obj.vtable->klass);
4214 size = mono_array_length (src);
4215 g_assert (size == mono_array_length (dest));
4216 size *= mono_array_element_size (klass);
4218 if (klass->element_class->valuetype) {
4219 if (klass->element_class->has_references)
4220 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4222 memcpy (&dest->vector, &src->vector, size);
4224 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4227 memcpy (&dest->vector, &src->vector, size);
4232 * mono_array_clone_in_domain:
4233 * @domain: the domain in which the array will be cloned into
4234 * @array: the array to clone
4236 * This routine returns a copy of the array that is hosted on the
4237 * specified MonoDomain.
4240 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4243 mono_array_size_t size, i;
4244 mono_array_size_t *sizes;
4245 MonoClass *klass = array->obj.vtable->klass;
4247 MONO_ARCH_SAVE_REGS;
4249 if (array->bounds == NULL) {
4250 size = mono_array_length (array);
4251 o = mono_array_new_full (domain, klass, &size, NULL);
4253 size *= mono_array_element_size (klass);
4255 if (klass->element_class->valuetype) {
4256 if (klass->element_class->has_references)
4257 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4259 memcpy (&o->vector, &array->vector, size);
4261 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4264 memcpy (&o->vector, &array->vector, size);
4269 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4270 size = mono_array_element_size (klass);
4271 for (i = 0; i < klass->rank; ++i) {
4272 sizes [i] = array->bounds [i].length;
4273 size *= array->bounds [i].length;
4274 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4276 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4278 if (klass->element_class->valuetype) {
4279 if (klass->element_class->has_references)
4280 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4282 memcpy (&o->vector, &array->vector, size);
4284 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4287 memcpy (&o->vector, &array->vector, size);
4295 * @array: the array to clone
4297 * Returns: A newly created array who is a shallow copy of @array
4300 mono_array_clone (MonoArray *array)
4302 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4305 /* helper macros to check for overflow when calculating the size of arrays */
4306 #ifdef MONO_BIG_ARRAYS
4307 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4308 #define MYGUINT_MAX MYGUINT64_MAX
4309 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4310 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4311 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4312 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4313 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4315 #define MYGUINT32_MAX 4294967295U
4316 #define MYGUINT_MAX MYGUINT32_MAX
4317 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4318 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4319 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4320 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4321 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4325 mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
4327 mono_array_size_t byte_len;
4329 byte_len = mono_array_element_size (class);
4330 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4333 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4335 byte_len += sizeof (MonoArray);
4343 * mono_array_new_full:
4344 * @domain: domain where the object is created
4345 * @array_class: array class
4346 * @lengths: lengths for each dimension in the array
4347 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4349 * This routine creates a new array objects with the given dimensions,
4350 * lower bounds and type.
4353 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4355 mono_array_size_t byte_len, len, bounds_size;
4358 MonoArrayBounds *bounds;
4362 if (!array_class->inited)
4363 mono_class_init (array_class);
4367 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4368 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4370 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4374 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4376 for (i = 0; i < array_class->rank; ++i) {
4377 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4379 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4380 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4385 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4386 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4390 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4391 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4392 byte_len = (byte_len + 3) & ~3;
4393 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4394 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4395 byte_len += bounds_size;
4398 * Following three lines almost taken from mono_object_new ():
4399 * they need to be kept in sync.
4401 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4402 #ifndef HAVE_SGEN_GC
4403 if (!array_class->has_references) {
4404 o = mono_object_allocate_ptrfree (byte_len, vtable);
4405 #if NEED_TO_ZERO_PTRFREE
4406 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4408 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4409 o = mono_object_allocate_spec (byte_len, vtable);
4411 o = mono_object_allocate (byte_len, vtable);
4414 array = (MonoArray*)o;
4415 array->max_length = len;
4418 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4419 array->bounds = bounds;
4423 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4425 o = mono_gc_alloc_vector (vtable, byte_len, len);
4426 array = (MonoArray*)o;
4427 mono_stats.new_object_count++;
4429 bounds = array->bounds;
4433 for (i = 0; i < array_class->rank; ++i) {
4434 bounds [i].length = lengths [i];
4436 bounds [i].lower_bound = lower_bounds [i];
4440 if (G_UNLIKELY (profile_allocs))
4441 mono_profiler_allocation (o, array_class);
4448 * @domain: domain where the object is created
4449 * @eclass: element class
4450 * @n: number of array elements
4452 * This routine creates a new szarray with @n elements of type @eclass.
4455 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4459 MONO_ARCH_SAVE_REGS;
4461 ac = mono_array_class_get (eclass, 1);
4464 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4468 * mono_array_new_specific:
4469 * @vtable: a vtable in the appropriate domain for an initialized class
4470 * @n: number of array elements
4472 * This routine is a fast alternative to mono_array_new() for code which
4473 * can be sure about the domain it operates in.
4476 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4482 MONO_ARCH_SAVE_REGS;
4484 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4489 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4490 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4493 #ifndef HAVE_SGEN_GC
4494 if (!vtable->klass->has_references) {
4495 o = mono_object_allocate_ptrfree (byte_len, vtable);
4496 #if NEED_TO_ZERO_PTRFREE
4497 ((MonoArray*)o)->bounds = NULL;
4498 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4500 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4501 o = mono_object_allocate_spec (byte_len, vtable);
4503 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4504 o = mono_object_allocate (byte_len, vtable);
4507 ao = (MonoArray *)o;
4510 o = mono_gc_alloc_vector (vtable, byte_len, n);
4512 mono_stats.new_object_count++;
4515 if (G_UNLIKELY (profile_allocs))
4516 mono_profiler_allocation (o, vtable->klass);
4522 * mono_string_new_utf16:
4523 * @text: a pointer to an utf16 string
4524 * @len: the length of the string
4526 * Returns: A newly created string object which contains @text.
4529 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4533 s = mono_string_new_size (domain, len);
4534 g_assert (s != NULL);
4536 memcpy (mono_string_chars (s), text, len * 2);
4542 * mono_string_new_size:
4543 * @text: a pointer to an utf16 string
4544 * @len: the length of the string
4546 * Returns: A newly created string object of @len
4549 mono_string_new_size (MonoDomain *domain, gint32 len)
4553 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4555 /* overflow ? can't fit it, can't allocate it! */
4557 mono_gc_out_of_memory (-1);
4559 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4562 s = mono_object_allocate_ptrfree (size, vtable);
4565 #if NEED_TO_ZERO_PTRFREE
4568 if (G_UNLIKELY (profile_allocs))
4569 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4575 * mono_string_new_len:
4576 * @text: a pointer to an utf8 string
4577 * @length: number of bytes in @text to consider
4579 * Returns: A newly created string object which contains @text.
4582 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4584 GError *error = NULL;
4585 MonoString *o = NULL;
4587 glong items_written;
4589 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4592 o = mono_string_new_utf16 (domain, ut, items_written);
4594 g_error_free (error);
4603 * @text: a pointer to an utf8 string
4605 * Returns: A newly created string object which contains @text.
4608 mono_string_new (MonoDomain *domain, const char *text)
4610 GError *error = NULL;
4611 MonoString *o = NULL;
4613 glong items_written;
4618 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4621 o = mono_string_new_utf16 (domain, ut, items_written);
4623 g_error_free (error);
4626 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4631 MonoString *o = NULL;
4633 if (!g_utf8_validate (text, -1, &end))
4636 len = g_utf8_strlen (text, -1);
4637 o = mono_string_new_size (domain, len);
4638 str = mono_string_chars (o);
4640 while (text < end) {
4641 *str++ = g_utf8_get_char (text);
4642 text = g_utf8_next_char (text);
4649 * mono_string_new_wrapper:
4650 * @text: pointer to utf8 characters.
4652 * Helper function to create a string object from @text in the current domain.
4655 mono_string_new_wrapper (const char *text)
4657 MonoDomain *domain = mono_domain_get ();
4659 MONO_ARCH_SAVE_REGS;
4662 return mono_string_new (domain, text);
4669 * @class: the class of the value
4670 * @value: a pointer to the unboxed data
4672 * Returns: A newly created object which contains @value.
4675 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4681 g_assert (class->valuetype);
4682 if (mono_class_is_nullable (class))
4683 return mono_nullable_box (value, class);
4685 vtable = mono_class_vtable (domain, class);
4688 size = mono_class_instance_size (class);
4689 res = mono_object_new_alloc_specific (vtable);
4690 if (G_UNLIKELY (profile_allocs))
4691 mono_profiler_allocation (res, class);
4693 size = size - sizeof (MonoObject);
4696 g_assert (size == mono_class_value_size (class, NULL));
4697 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4699 #if NO_UNALIGNED_ACCESS
4700 memcpy ((char *)res + sizeof (MonoObject), value, size);
4704 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4707 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4710 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4713 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4716 memcpy ((char *)res + sizeof (MonoObject), value, size);
4720 if (class->has_finalize)
4721 mono_object_register_finalizer (res);
4727 * @dest: destination pointer
4728 * @src: source pointer
4729 * @klass: a valuetype class
4731 * Copy a valuetype from @src to @dest. This function must be used
4732 * when @klass contains references fields.
4735 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4737 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4741 * mono_value_copy_array:
4742 * @dest: destination array
4743 * @dest_idx: index in the @dest array
4744 * @src: source pointer
4745 * @count: number of items
4747 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4748 * This function must be used when @klass contains references fields.
4749 * Overlap is handled.
4752 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4754 int size = mono_array_element_size (dest->obj.vtable->klass);
4755 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4756 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4757 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4761 * mono_object_get_domain:
4762 * @obj: object to query
4764 * Returns: the MonoDomain where the object is hosted
4767 mono_object_get_domain (MonoObject *obj)
4769 return mono_object_domain (obj);
4773 * mono_object_get_class:
4774 * @obj: object to query
4776 * Returns: the MonOClass of the object.
4779 mono_object_get_class (MonoObject *obj)
4781 return mono_object_class (obj);
4784 * mono_object_get_size:
4785 * @o: object to query
4787 * Returns: the size, in bytes, of @o
4790 mono_object_get_size (MonoObject* o)
4792 MonoClass* klass = mono_object_class (o);
4793 if (klass == mono_defaults.string_class) {
4794 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4795 } else if (o->vtable->rank) {
4796 MonoArray *array = (MonoArray*)o;
4797 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4798 if (array->bounds) {
4801 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4805 return mono_class_instance_size (klass);
4810 * mono_object_unbox:
4811 * @obj: object to unbox
4813 * Returns: a pointer to the start of the valuetype boxed in this
4816 * This method will assert if the object passed is not a valuetype.
4819 mono_object_unbox (MonoObject *obj)
4821 /* add assert for valuetypes? */
4822 g_assert (obj->vtable->klass->valuetype);
4823 return ((char*)obj) + sizeof (MonoObject);
4827 * mono_object_isinst:
4829 * @klass: a pointer to a class
4831 * Returns: @obj if @obj is derived from @klass
4834 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4837 mono_class_init (klass);
4839 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4840 return mono_object_isinst_mbyref (obj, klass);
4845 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4849 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4858 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4859 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4863 MonoClass *oklass = vt->klass;
4864 if ((oklass == mono_defaults.transparent_proxy_class))
4865 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4867 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4871 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4873 MonoDomain *domain = mono_domain_get ();
4875 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4876 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4877 MonoMethod *im = NULL;
4880 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4881 im = mono_object_get_virtual_method (rp, im);
4884 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4887 res = mono_runtime_invoke (im, rp, pa, NULL);
4889 if (*(MonoBoolean *) mono_object_unbox(res)) {
4890 /* Update the vtable of the remote type, so it can safely cast to this new type */
4891 mono_upgrade_remote_class (domain, obj, klass);
4900 * mono_object_castclass_mbyref:
4902 * @klass: a pointer to a class
4904 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4907 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4909 if (!obj) return NULL;
4910 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4912 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4914 "InvalidCastException"));
4919 MonoDomain *orig_domain;
4925 str_lookup (MonoDomain *domain, gpointer user_data)
4927 LDStrInfo *info = user_data;
4928 if (info->res || domain == info->orig_domain)
4930 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4936 mono_string_get_pinned (MonoString *str)
4940 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4941 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4942 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4943 news->length = mono_string_length (str);
4948 #define mono_string_get_pinned(str) (str)
4952 mono_string_is_interned_lookup (MonoString *str, int insert)
4954 MonoGHashTable *ldstr_table;
4958 domain = ((MonoObject *)str)->vtable->domain;
4959 ldstr_table = domain->ldstr_table;
4961 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4966 str = mono_string_get_pinned (str);
4967 mono_g_hash_table_insert (ldstr_table, str, str);
4971 LDStrInfo ldstr_info;
4972 ldstr_info.orig_domain = domain;
4973 ldstr_info.ins = str;
4974 ldstr_info.res = NULL;
4976 mono_domain_foreach (str_lookup, &ldstr_info);
4977 if (ldstr_info.res) {
4979 * the string was already interned in some other domain:
4980 * intern it in the current one as well.
4982 mono_g_hash_table_insert (ldstr_table, str, str);
4992 * mono_string_is_interned:
4993 * @o: String to probe
4995 * Returns whether the string has been interned.
4998 mono_string_is_interned (MonoString *o)
5000 return mono_string_is_interned_lookup (o, FALSE);
5004 * mono_string_intern:
5005 * @o: String to intern
5007 * Interns the string passed.
5008 * Returns: The interned string.
5011 mono_string_intern (MonoString *str)
5013 return mono_string_is_interned_lookup (str, TRUE);
5018 * @domain: the domain where the string will be used.
5019 * @image: a metadata context
5020 * @idx: index into the user string table.
5022 * Implementation for the ldstr opcode.
5023 * Returns: a loaded string from the @image/@idx combination.
5026 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5028 MONO_ARCH_SAVE_REGS;
5031 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5033 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5037 * mono_ldstr_metadata_sig
5038 * @domain: the domain for the string
5039 * @sig: the signature of a metadata string
5041 * Returns: a MonoString for a string stored in the metadata
5044 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5046 const char *str = sig;
5047 MonoString *o, *interned;
5050 len2 = mono_metadata_decode_blob_size (str, &str);
5053 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5054 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5057 guint16 *p2 = (guint16*)mono_string_chars (o);
5058 for (i = 0; i < len2; ++i) {
5059 *p2 = GUINT16_FROM_LE (*p2);
5065 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5067 /* o will get garbage collected */
5071 o = mono_string_get_pinned (o);
5072 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5079 * mono_string_to_utf8:
5080 * @s: a System.String
5082 * Return the UTF8 representation for @s.
5083 * the resulting buffer nedds to be freed with g_free().
5086 mono_string_to_utf8 (MonoString *s)
5090 GError *error = NULL;
5096 return g_strdup ("");
5098 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
5100 MonoException *exc = mono_get_exception_argument ("string", error->message);
5101 g_error_free (error);
5102 mono_raise_exception(exc);
5104 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5105 if (s->length > written) {
5106 /* allocate the total length and copy the part of the string that has been converted */
5107 char *as2 = g_malloc0 (s->length);
5108 memcpy (as2, as, written);
5117 * mono_string_to_utf16:
5120 * Return an null-terminated array of the utf-16 chars
5121 * contained in @s. The result must be freed with g_free().
5122 * This is a temporary helper until our string implementation
5123 * is reworked to always include the null terminating char.
5126 mono_string_to_utf16 (MonoString *s)
5133 as = g_malloc ((s->length * 2) + 2);
5134 as [(s->length * 2)] = '\0';
5135 as [(s->length * 2) + 1] = '\0';
5138 return (gunichar2 *)(as);
5141 memcpy (as, mono_string_chars(s), s->length * 2);
5142 return (gunichar2 *)(as);
5146 * mono_string_from_utf16:
5147 * @data: the UTF16 string (LPWSTR) to convert
5149 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5151 * Returns: a MonoString.
5154 mono_string_from_utf16 (gunichar2 *data)
5156 MonoDomain *domain = mono_domain_get ();
5162 while (data [len]) len++;
5164 return mono_string_new_utf16 (domain, data, len);
5169 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s)
5176 return mono_string_to_utf8 (s);
5178 r = mono_string_to_utf8 (s);
5182 len = strlen (r) + 1;
5184 mp_s = mono_mempool_alloc (mp, len);
5186 mp_s = mono_image_alloc (image, len);
5188 memcpy (mp_s, r, len);
5196 * mono_string_to_utf8_image:
5197 * @s: a System.String
5199 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5202 mono_string_to_utf8_image (MonoImage *image, MonoString *s)
5204 return mono_string_to_utf8_internal (NULL, image, s);
5208 * mono_string_to_utf8_mp:
5209 * @s: a System.String
5211 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5214 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
5216 return mono_string_to_utf8_internal (mp, NULL, s);
5220 default_ex_handler (MonoException *ex)
5222 MonoObject *o = (MonoObject*)ex;
5223 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5227 static MonoExceptionFunc ex_handler = default_ex_handler;
5230 * mono_install_handler:
5231 * @func: exception handler
5233 * This is an internal JIT routine used to install the handler for exceptions
5237 mono_install_handler (MonoExceptionFunc func)
5239 ex_handler = func? func: default_ex_handler;
5243 * mono_raise_exception:
5244 * @ex: exception object
5246 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5249 mono_raise_exception (MonoException *ex)
5252 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5253 * that will cause gcc to omit the function epilog, causing problems when
5254 * the JIT tries to walk the stack, since the return address on the stack
5255 * will point into the next function in the executable, not this one.
5258 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5259 MonoInternalThread *thread = mono_thread_internal_current ();
5260 g_assert (ex->object.vtable->domain == mono_domain_get ());
5261 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5268 * mono_wait_handle_new:
5269 * @domain: Domain where the object will be created
5270 * @handle: Handle for the wait handle
5272 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5275 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5277 MonoWaitHandle *res;
5278 gpointer params [1];
5279 static MonoMethod *handle_set;
5281 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5283 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5285 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5287 params [0] = &handle;
5288 mono_runtime_invoke (handle_set, res, params, NULL);
5294 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5296 static MonoClassField *f_os_handle;
5297 static MonoClassField *f_safe_handle;
5299 if (!f_os_handle && !f_safe_handle) {
5300 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5301 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5306 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5310 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5317 mono_runtime_capture_context (MonoDomain *domain)
5319 RuntimeInvokeFunction runtime_invoke;
5321 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5322 MonoMethod *method = mono_get_context_capture_method ();
5323 MonoMethod *wrapper;
5326 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5327 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5328 domain->capture_context_method = mono_compile_method (method);
5331 runtime_invoke = domain->capture_context_runtime_invoke;
5333 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5336 * mono_async_result_new:
5337 * @domain:domain where the object will be created.
5338 * @handle: wait handle.
5339 * @state: state to pass to AsyncResult
5340 * @data: C closure data.
5342 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5343 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5347 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5349 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5350 MonoObject *context = mono_runtime_capture_context (domain);
5351 /* we must capture the execution context from the original thread */
5353 MONO_OBJECT_SETREF (res, execution_context, context);
5354 /* note: result may be null if the flow is suppressed */
5358 MONO_OBJECT_SETREF (res, object_data, object_data);
5359 MONO_OBJECT_SETREF (res, async_state, state);
5361 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5363 res->sync_completed = FALSE;
5364 res->completed = FALSE;
5370 mono_message_init (MonoDomain *domain,
5371 MonoMethodMessage *this,
5372 MonoReflectionMethod *method,
5373 MonoArray *out_args)
5375 static MonoClass *object_array_klass;
5376 static MonoClass *byte_array_klass;
5377 static MonoClass *string_array_klass;
5378 MonoMethodSignature *sig = mono_method_signature (method->method);
5384 if (!object_array_klass) {
5387 klass = mono_array_class_get (mono_defaults.object_class, 1);
5390 mono_memory_barrier ();
5391 object_array_klass = klass;
5393 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5396 mono_memory_barrier ();
5397 byte_array_klass = klass;
5399 klass = mono_array_class_get (mono_defaults.string_class, 1);
5402 mono_memory_barrier ();
5403 string_array_klass = klass;
5406 MONO_OBJECT_SETREF (this, method, method);
5408 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5409 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5410 this->async_result = NULL;
5411 this->call_type = CallType_Sync;
5413 names = g_new (char *, sig->param_count);
5414 mono_method_get_param_names (method->method, (const char **) names);
5415 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5417 for (i = 0; i < sig->param_count; i++) {
5418 name = mono_string_new (domain, names [i]);
5419 mono_array_setref (this->names, i, name);
5423 for (i = 0, j = 0; i < sig->param_count; i++) {
5424 if (sig->params [i]->byref) {
5426 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5427 mono_array_setref (this->args, i, arg);
5431 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5435 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5438 mono_array_set (this->arg_types, guint8, i, arg_type);
5443 * mono_remoting_invoke:
5444 * @real_proxy: pointer to a RealProxy object
5445 * @msg: The MonoMethodMessage to execute
5446 * @exc: used to store exceptions
5447 * @out_args: used to store output arguments
5449 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5450 * IMessage interface and it is not trivial to extract results from there. So
5451 * we call an helper method PrivateInvoke instead of calling
5452 * RealProxy::Invoke() directly.
5454 * Returns: the result object.
5457 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5458 MonoObject **exc, MonoArray **out_args)
5460 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5463 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5466 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5468 real_proxy->vtable->domain->private_invoke_method = im;
5471 pa [0] = real_proxy;
5476 return mono_runtime_invoke (im, NULL, pa, exc);
5480 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5481 MonoObject **exc, MonoArray **out_args)
5483 static MonoClass *object_array_klass;
5486 MonoMethodSignature *sig;
5488 int i, j, outarg_count = 0;
5490 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5492 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5493 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5494 target = tp->rp->unwrapped_server;
5496 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5500 domain = mono_domain_get ();
5501 method = msg->method->method;
5502 sig = mono_method_signature (method);
5504 for (i = 0; i < sig->param_count; i++) {
5505 if (sig->params [i]->byref)
5509 if (!object_array_klass) {
5512 klass = mono_array_class_get (mono_defaults.object_class, 1);
5515 mono_memory_barrier ();
5516 object_array_klass = klass;
5519 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5520 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5523 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5525 for (i = 0, j = 0; i < sig->param_count; i++) {
5526 if (sig->params [i]->byref) {
5528 arg = mono_array_get (msg->args, gpointer, i);
5529 mono_array_setref (*out_args, j, arg);
5538 * mono_print_unhandled_exception:
5539 * @exc: The exception
5541 * Prints the unhandled exception.
5544 mono_print_unhandled_exception (MonoObject *exc)
5546 char *message = (char *) "";
5550 gboolean free_message = FALSE;
5552 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5553 klass = exc->vtable->klass;
5555 while (klass && method == NULL) {
5556 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5558 klass = klass->parent;
5563 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5565 message = mono_string_to_utf8 (str);
5566 free_message = TRUE;
5571 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5572 * exc->vtable->klass->name, message);
5574 g_printerr ("\nUnhandled Exception: %s\n", message);
5581 * mono_delegate_ctor:
5582 * @this: pointer to an uninitialized delegate object
5583 * @target: target object
5584 * @addr: pointer to native code
5587 * Initialize a delegate and sets a specific method, not the one
5588 * associated with addr. This is useful when sharing generic code.
5589 * In that case addr will most probably not be associated with the
5590 * correct instantiation of the method.
5593 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5595 MonoDelegate *delegate = (MonoDelegate *)this;
5602 delegate->method = method;
5604 class = this->vtable->klass;
5605 mono_stats.delegate_creations++;
5607 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5609 method = mono_marshal_get_remoting_invoke (method);
5610 delegate->method_ptr = mono_compile_method (method);
5611 MONO_OBJECT_SETREF (delegate, target, target);
5612 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5613 method = mono_marshal_get_unbox_wrapper (method);
5614 delegate->method_ptr = mono_compile_method (method);
5615 MONO_OBJECT_SETREF (delegate, target, target);
5617 delegate->method_ptr = addr;
5618 MONO_OBJECT_SETREF (delegate, target, target);
5621 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5625 * mono_delegate_ctor:
5626 * @this: pointer to an uninitialized delegate object
5627 * @target: target object
5628 * @addr: pointer to native code
5630 * This is used to initialize a delegate.
5633 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5635 MonoDomain *domain = mono_domain_get ();
5637 MonoMethod *method = NULL;
5641 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5642 method = ji->method;
5643 g_assert (!method->klass->generic_container);
5646 mono_delegate_ctor_with_method (this, target, addr, method);
5650 * mono_method_call_message_new:
5651 * @method: method to encapsulate
5652 * @params: parameters to the method
5653 * @invoke: optional, delegate invoke.
5654 * @cb: async callback delegate.
5655 * @state: state passed to the async callback.
5657 * Translates arguments pointers into a MonoMethodMessage.
5660 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5661 MonoDelegate **cb, MonoObject **state)
5663 MonoDomain *domain = mono_domain_get ();
5664 MonoMethodSignature *sig = mono_method_signature (method);
5665 MonoMethodMessage *msg;
5668 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5671 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5672 count = sig->param_count - 2;
5674 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5675 count = sig->param_count;
5678 for (i = 0; i < count; i++) {
5683 if (sig->params [i]->byref)
5684 vpos = *((gpointer *)params [i]);
5688 type = sig->params [i]->type;
5689 class = mono_class_from_mono_type (sig->params [i]);
5691 if (class->valuetype)
5692 arg = mono_value_box (domain, class, vpos);
5694 arg = *((MonoObject **)vpos);
5696 mono_array_setref (msg->args, i, arg);
5699 if (cb != NULL && state != NULL) {
5700 *cb = *((MonoDelegate **)params [i]);
5702 *state = *((MonoObject **)params [i]);
5709 * mono_method_return_message_restore:
5711 * Restore results from message based processing back to arguments pointers
5714 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5716 MonoMethodSignature *sig = mono_method_signature (method);
5717 int i, j, type, size, out_len;
5719 if (out_args == NULL)
5721 out_len = mono_array_length (out_args);
5725 for (i = 0, j = 0; i < sig->param_count; i++) {
5726 MonoType *pt = sig->params [i];
5731 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5733 arg = mono_array_get (out_args, gpointer, j);
5736 g_assert (type != MONO_TYPE_VOID);
5738 if (MONO_TYPE_IS_REFERENCE (pt)) {
5739 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5742 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5743 size = mono_class_value_size (class, NULL);
5744 if (class->has_references)
5745 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5747 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5749 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5750 memset (*((gpointer *)params [i]), 0, size);
5760 * mono_load_remote_field:
5761 * @this: pointer to an object
5762 * @klass: klass of the object containing @field
5763 * @field: the field to load
5764 * @res: a storage to store the result
5766 * This method is called by the runtime on attempts to load fields of
5767 * transparent proxy objects. @this points to such TP, @klass is the class of
5768 * the object containing @field. @res is a storage location which can be
5769 * used to store the result.
5771 * Returns: an address pointing to the value of field.
5774 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5776 static MonoMethod *getter = NULL;
5777 MonoDomain *domain = mono_domain_get ();
5778 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5779 MonoClass *field_class;
5780 MonoMethodMessage *msg;
5781 MonoArray *out_args;
5785 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5786 g_assert (res != NULL);
5788 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5789 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5794 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5798 field_class = mono_class_from_mono_type (field->type);
5800 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5801 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5802 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5804 full_name = mono_type_get_full_name (klass);
5805 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5806 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5809 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5811 if (exc) mono_raise_exception ((MonoException *)exc);
5813 if (mono_array_length (out_args) == 0)
5816 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5818 if (field_class->valuetype) {
5819 return ((char *)*res) + sizeof (MonoObject);
5825 * mono_load_remote_field_new:
5830 * Missing documentation.
5833 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5835 static MonoMethod *getter = NULL;
5836 MonoDomain *domain = mono_domain_get ();
5837 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5838 MonoClass *field_class;
5839 MonoMethodMessage *msg;
5840 MonoArray *out_args;
5841 MonoObject *exc, *res;
5844 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5846 field_class = mono_class_from_mono_type (field->type);
5848 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5850 if (field_class->valuetype) {
5851 res = mono_object_new (domain, field_class);
5852 val = ((gchar *) res) + sizeof (MonoObject);
5856 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5861 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5865 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5866 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5868 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5870 full_name = mono_type_get_full_name (klass);
5871 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5872 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5875 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5877 if (exc) mono_raise_exception ((MonoException *)exc);
5879 if (mono_array_length (out_args) == 0)
5882 res = mono_array_get (out_args, MonoObject *, 0);
5888 * mono_store_remote_field:
5889 * @this: pointer to an object
5890 * @klass: klass of the object containing @field
5891 * @field: the field to load
5892 * @val: the value/object to store
5894 * This method is called by the runtime on attempts to store fields of
5895 * transparent proxy objects. @this points to such TP, @klass is the class of
5896 * the object containing @field. @val is the new value to store in @field.
5899 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5901 static MonoMethod *setter = NULL;
5902 MonoDomain *domain = mono_domain_get ();
5903 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5904 MonoClass *field_class;
5905 MonoMethodMessage *msg;
5906 MonoArray *out_args;
5911 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5913 field_class = mono_class_from_mono_type (field->type);
5915 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5916 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5917 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5922 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5926 if (field_class->valuetype)
5927 arg = mono_value_box (domain, field_class, val);
5929 arg = *((MonoObject **)val);
5932 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5933 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5935 full_name = mono_type_get_full_name (klass);
5936 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5937 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5938 mono_array_setref (msg->args, 2, arg);
5941 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5943 if (exc) mono_raise_exception ((MonoException *)exc);
5947 * mono_store_remote_field_new:
5953 * Missing documentation
5956 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5958 static MonoMethod *setter = NULL;
5959 MonoDomain *domain = mono_domain_get ();
5960 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5961 MonoClass *field_class;
5962 MonoMethodMessage *msg;
5963 MonoArray *out_args;
5967 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5969 field_class = mono_class_from_mono_type (field->type);
5971 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5972 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5973 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5978 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5982 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5983 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5985 full_name = mono_type_get_full_name (klass);
5986 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5987 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5988 mono_array_setref (msg->args, 2, arg);
5991 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5993 if (exc) mono_raise_exception ((MonoException *)exc);
5997 * mono_create_ftnptr:
5999 * Given a function address, create a function descriptor for it.
6000 * This is only needed on some platforms.
6003 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6005 return callbacks.create_ftnptr (domain, addr);
6009 * mono_get_addr_from_ftnptr:
6011 * Given a pointer to a function descriptor, return the function address.
6012 * This is only needed on some platforms.
6015 mono_get_addr_from_ftnptr (gpointer descr)
6017 return callbacks.get_addr_from_ftnptr (descr);
6022 * mono_string_chars:
6025 * Returns a pointer to the UCS16 characters stored in the MonoString
6028 mono_string_chars(MonoString *s)
6030 /* This method is here only for documentation extraction, this is a macro */
6034 * mono_string_length:
6037 * Returns the lenght in characters of the string
6040 mono_string_length (MonoString *s)
6042 /* This method is here only for documentation extraction, this is a macro */