2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001-2004 Ximian, Inc.
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include "mono/metadata/security-manager.h"
35 #include "mono/metadata/mono-debug-debugger.h"
36 #include <mono/metadata/gc-internal.h>
37 #include <mono/utils/strenc.h>
40 #define NEED_TO_ZERO_PTRFREE 1
41 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
42 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
43 #ifdef HAVE_GC_GCJ_MALLOC
44 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
45 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
47 #define GC_NO_DESCRIPTOR (NULL)
48 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
52 #define GC_NO_DESCRIPTOR (NULL)
53 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
54 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
57 #define NEED_TO_ZERO_PTRFREE 1
58 #define GC_NO_DESCRIPTOR (NULL)
59 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
60 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
61 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
65 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
66 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
69 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
72 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
74 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
75 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
76 static CRITICAL_SECTION ldstr_section;
79 mono_runtime_object_init (MonoObject *this)
81 MonoMethod *method = NULL;
82 MonoClass *klass = this->vtable->klass;
84 method = mono_class_get_method_from_name (klass, ".ctor", 0);
87 if (method->klass->valuetype)
88 this = mono_object_unbox (this);
89 mono_runtime_invoke (method, this, NULL, NULL);
92 /* The pseudo algorithm for type initialization from the spec
93 Note it doesn't say anything about domains - only threads.
95 2. If the type is initialized you are done.
96 2.1. If the type is not yet initialized, try to take an
98 2.2. If successful, record this thread as responsible for
99 initializing the type and proceed to step 2.3.
100 2.2.1. If not, see whether this thread or any thread
101 waiting for this thread to complete already holds the lock.
102 2.2.2. If so, return since blocking would create a deadlock. This thread
103 will now see an incompletely initialized state for the type,
104 but no deadlock will arise.
105 2.2.3 If not, block until the type is initialized then return.
106 2.3 Initialize the parent type and then all interfaces implemented
108 2.4 Execute the type initialization code for this type.
109 2.5 Mark the type as initialized, release the initialization lock,
110 awaken any threads waiting for this type to be initialized,
117 guint32 initializing_tid;
118 guint32 waiting_count;
120 CRITICAL_SECTION initialization_section;
121 } TypeInitializationLock;
123 /* for locking access to type_initialization_hash and blocked_thread_hash */
124 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
125 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
126 static CRITICAL_SECTION type_initialization_section;
128 /* from vtable to lock */
129 static GHashTable *type_initialization_hash;
131 /* from thread id to thread id being waited on */
132 static GHashTable *blocked_thread_hash;
135 static MonoThread *main_thread;
138 * mono_thread_set_main:
139 * @thread: thread to set as the main thread
141 * This function can be used to instruct the runtime to treat @thread
142 * as the main thread, ie, the thread that would normally execute the Main()
143 * method. This basically means that at the end of @thread, the runtime will
144 * wait for the existing foreground threads to quit and other such details.
147 mono_thread_set_main (MonoThread *thread)
149 main_thread = thread;
153 mono_thread_get_main (void)
159 mono_type_initialization_init (void)
161 InitializeCriticalSection (&type_initialization_section);
162 type_initialization_hash = g_hash_table_new (NULL, NULL);
163 blocked_thread_hash = g_hash_table_new (NULL, NULL);
164 InitializeCriticalSection (&ldstr_section);
168 mono_type_initialization_cleanup (void)
171 /* This is causing race conditions with
172 * mono_release_type_locks
174 DeleteCriticalSection (&type_initialization_section);
176 DeleteCriticalSection (&ldstr_section);
180 * get_type_init_exception_for_vtable:
182 * Return the stored type initialization exception for VTABLE.
184 static MonoException*
185 get_type_init_exception_for_vtable (MonoVTable *vtable)
187 MonoDomain *domain = vtable->domain;
188 MonoClass *klass = vtable->klass;
192 g_assert (vtable->init_failed);
195 * If the initializing thread was rudely aborted, the exception is not stored
199 mono_domain_lock (domain);
200 if (domain->type_init_exception_hash)
201 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
202 mono_domain_unlock (domain);
205 if (klass->name_space && *klass->name_space)
206 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
208 full_name = g_strdup (klass->name);
209 ex = mono_get_exception_type_initialization (full_name, NULL);
217 * mono_runtime_class_init:
218 * @vtable: vtable that needs to be initialized
220 * This routine calls the class constructor for @vtable.
223 mono_runtime_class_init (MonoVTable *vtable)
226 MonoException *exc_to_throw;
227 MonoMethod *method = NULL;
233 if (vtable->initialized)
237 klass = vtable->klass;
239 if (!klass->image->checked_module_cctor) {
240 mono_image_check_for_module_cctor (klass->image);
241 if (klass->image->has_module_cctor) {
242 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
243 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
246 method = mono_class_get_cctor (klass);
249 MonoDomain *domain = vtable->domain;
250 TypeInitializationLock *lock;
251 guint32 tid = GetCurrentThreadId();
252 int do_initialization = 0;
253 MonoDomain *last_domain = NULL;
255 mono_type_initialization_lock ();
256 /* double check... */
257 if (vtable->initialized) {
258 mono_type_initialization_unlock ();
261 if (vtable->init_failed) {
262 mono_type_initialization_unlock ();
264 /* The type initialization already failed once, rethrow the same exception */
265 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
268 lock = g_hash_table_lookup (type_initialization_hash, vtable);
270 /* This thread will get to do the initialization */
271 if (mono_domain_get () != domain) {
272 /* Transfer into the target domain */
273 last_domain = mono_domain_get ();
274 if (!mono_domain_set (domain, FALSE)) {
275 vtable->initialized = 1;
276 mono_type_initialization_unlock ();
277 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
280 lock = g_malloc (sizeof(TypeInitializationLock));
281 InitializeCriticalSection (&lock->initialization_section);
282 lock->initializing_tid = tid;
283 lock->waiting_count = 1;
285 /* grab the vtable lock while this thread still owns type_initialization_section */
286 EnterCriticalSection (&lock->initialization_section);
287 g_hash_table_insert (type_initialization_hash, vtable, lock);
288 do_initialization = 1;
291 TypeInitializationLock *pending_lock;
293 if (lock->initializing_tid == tid || lock->done) {
294 mono_type_initialization_unlock ();
297 /* see if the thread doing the initialization is already blocked on this thread */
298 blocked = GUINT_TO_POINTER (lock->initializing_tid);
299 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
300 if (pending_lock->initializing_tid == tid) {
301 if (!pending_lock->done) {
302 mono_type_initialization_unlock ();
305 /* the thread doing the initialization is blocked on this thread,
306 but on a lock that has already been freed. It just hasn't got
311 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
313 ++lock->waiting_count;
314 /* record the fact that we are waiting on the initializing thread */
315 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
317 mono_type_initialization_unlock ();
319 if (do_initialization) {
320 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
322 /* If the initialization failed, mark the class as unusable. */
323 /* Avoid infinite loops */
325 (klass->image == mono_defaults.corlib &&
326 !strcmp (klass->name_space, "System") &&
327 !strcmp (klass->name, "TypeInitializationException")))) {
328 vtable->init_failed = 1;
330 if (klass->name_space && *klass->name_space)
331 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
333 full_name = g_strdup (klass->name);
334 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
338 * Store the exception object so it could be thrown on subsequent
341 mono_domain_lock (domain);
342 if (!domain->type_init_exception_hash)
343 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
344 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
345 mono_domain_unlock (domain);
349 mono_domain_set (last_domain, TRUE);
351 LeaveCriticalSection (&lock->initialization_section);
353 /* this just blocks until the initializing thread is done */
354 EnterCriticalSection (&lock->initialization_section);
355 LeaveCriticalSection (&lock->initialization_section);
358 mono_type_initialization_lock ();
359 if (lock->initializing_tid != tid)
360 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
361 --lock->waiting_count;
362 if (lock->waiting_count == 0) {
363 DeleteCriticalSection (&lock->initialization_section);
364 g_hash_table_remove (type_initialization_hash, vtable);
367 if (!vtable->init_failed)
368 vtable->initialized = 1;
369 mono_type_initialization_unlock ();
371 if (vtable->init_failed) {
372 /* Either we were the initializing thread or we waited for the initialization */
373 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
376 vtable->initialized = 1;
382 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
384 MonoVTable *vtable = (MonoVTable*)key;
386 TypeInitializationLock *lock = (TypeInitializationLock*) value;
387 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
390 * Have to set this since it cannot be set by the normal code in
391 * mono_runtime_class_init (). In this case, the exception object is not stored,
392 * and get_type_init_exception_for_class () needs to be aware of this.
394 vtable->init_failed = 1;
395 LeaveCriticalSection (&lock->initialization_section);
396 --lock->waiting_count;
397 if (lock->waiting_count == 0) {
398 DeleteCriticalSection (&lock->initialization_section);
407 mono_release_type_locks (MonoThread *thread)
409 mono_type_initialization_lock ();
410 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
411 mono_type_initialization_unlock ();
415 default_trampoline (MonoMethod *method)
421 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
423 g_assert_not_reached ();
429 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
431 g_error ("remoting not installed");
436 default_delegate_trampoline (MonoClass *klass)
438 g_assert_not_reached ();
442 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
443 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
444 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
445 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
446 static MonoImtThunkBuilder imt_thunk_builder = NULL;
447 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
448 #if (MONO_IMT_SIZE > 32)
449 #error "MONO_IMT_SIZE cannot be larger than 32"
453 mono_install_trampoline (MonoTrampoline func)
455 arch_create_jit_trampoline = func? func: default_trampoline;
459 mono_install_jump_trampoline (MonoJumpTrampoline func)
461 arch_create_jump_trampoline = func? func: default_jump_trampoline;
465 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
467 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
471 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
473 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
477 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
478 imt_thunk_builder = func;
481 static MonoCompileFunc default_mono_compile_method = NULL;
484 * mono_install_compile_method:
485 * @func: function to install
487 * This is a VM internal routine
490 mono_install_compile_method (MonoCompileFunc func)
492 default_mono_compile_method = func;
496 * mono_compile_method:
497 * @method: The method to compile.
499 * This JIT-compiles the method, and returns the pointer to the native code
503 mono_compile_method (MonoMethod *method)
505 if (!default_mono_compile_method) {
506 g_error ("compile method called on uninitialized runtime");
509 return default_mono_compile_method (method);
513 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
515 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
519 mono_runtime_create_delegate_trampoline (MonoClass *klass)
521 return arch_create_delegate_trampoline (klass);
524 static MonoFreeMethodFunc default_mono_free_method = NULL;
527 * mono_install_free_method:
528 * @func: pointer to the MonoFreeMethodFunc used to release a method
530 * This is an internal VM routine, it is used for the engines to
531 * register a handler to release the resources associated with a method.
533 * Methods are freed when no more references to the delegate that holds
537 mono_install_free_method (MonoFreeMethodFunc func)
539 default_mono_free_method = func;
543 * mono_runtime_free_method:
544 * @domain; domain where the method is hosted
545 * @method: method to release
547 * This routine is invoked to free the resources associated with
548 * a method that has been JIT compiled. This is used to discard
549 * methods that were used only temporarily (for example, used in marshalling)
553 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
555 if (default_mono_free_method != NULL)
556 default_mono_free_method (domain, method);
558 mono_free_method (method);
562 * The vtables in the root appdomain are assumed to be reachable by other
563 * roots, and we don't use typed allocation in the other domains.
566 /* The sync block is no longer a GC pointer */
567 #define GC_HEADER_BITMAP (0)
569 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
572 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
574 MonoClassField *field;
580 max_size = mono_class_data_size (class) / sizeof (gpointer);
582 max_size = class->instance_size / sizeof (gpointer);
583 if (max_size >= size) {
584 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
587 for (p = class; p != NULL; p = p->parent) {
588 gpointer iter = NULL;
589 while ((field = mono_class_get_fields (p, &iter))) {
593 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
595 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
598 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
601 /* FIXME: should not happen, flag as type load error */
602 if (field->type->byref)
605 pos = field->offset / sizeof (gpointer);
608 type = mono_type_get_underlying_type (field->type);
609 switch (type->type) {
612 case MONO_TYPE_FNPTR:
614 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
619 if (class->image != mono_defaults.corlib)
622 case MONO_TYPE_STRING:
623 case MONO_TYPE_SZARRAY:
624 case MONO_TYPE_CLASS:
625 case MONO_TYPE_OBJECT:
626 case MONO_TYPE_ARRAY:
627 g_assert ((field->offset % sizeof(gpointer)) == 0);
629 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
630 *max_set = MAX (*max_set, pos);
632 case MONO_TYPE_GENERICINST:
633 if (!mono_type_generic_inst_is_valuetype (type)) {
634 g_assert ((field->offset % sizeof(gpointer)) == 0);
636 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
637 *max_set = MAX (*max_set, pos);
642 case MONO_TYPE_VALUETYPE: {
643 MonoClass *fclass = mono_class_from_mono_type (field->type);
644 if (fclass->has_references) {
645 /* remove the object header */
646 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
660 case MONO_TYPE_BOOLEAN:
664 g_assert_not_reached ();
676 * similar to the above, but sets the bits in the bitmap for any non-ref field
677 * and ignores static fields
680 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
682 MonoClassField *field;
687 max_size = class->instance_size / sizeof (gpointer);
688 if (max_size >= size) {
689 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
692 for (p = class; p != NULL; p = p->parent) {
693 gpointer iter = NULL;
694 while ((field = mono_class_get_fields (p, &iter))) {
697 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
699 /* FIXME: should not happen, flag as type load error */
700 if (field->type->byref)
703 pos = field->offset / sizeof (gpointer);
706 type = mono_type_get_underlying_type (field->type);
707 switch (type->type) {
708 #if SIZEOF_VOID_P == 8
712 case MONO_TYPE_FNPTR:
717 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
718 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
719 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
722 #if SIZEOF_VOID_P == 4
726 case MONO_TYPE_FNPTR:
731 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
732 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
733 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
739 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
740 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
741 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
744 case MONO_TYPE_BOOLEAN:
747 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
749 case MONO_TYPE_STRING:
750 case MONO_TYPE_SZARRAY:
751 case MONO_TYPE_CLASS:
752 case MONO_TYPE_OBJECT:
753 case MONO_TYPE_ARRAY:
755 case MONO_TYPE_GENERICINST:
756 if (!mono_type_generic_inst_is_valuetype (type)) {
761 case MONO_TYPE_VALUETYPE: {
762 MonoClass *fclass = mono_class_from_mono_type (field->type);
763 /* remove the object header */
764 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
768 g_assert_not_reached ();
777 * mono_class_insecure_overlapping:
778 * check if a class with explicit layout has references and non-references
779 * fields overlapping.
781 * Returns: TRUE if it is insecure to load the type.
784 mono_class_insecure_overlapping (MonoClass *klass)
788 gsize default_bitmap [4] = {0};
790 gsize default_nrbitmap [4] = {0};
791 int i, insecure = FALSE;
794 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
795 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
797 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
798 int idx = i % (sizeof (bitmap [0]) * 8);
799 if (bitmap [idx] & nrbitmap [idx]) {
804 if (bitmap != default_bitmap)
806 if (nrbitmap != default_nrbitmap)
809 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
817 mono_string_alloc (int length)
819 return mono_string_new_size (mono_domain_get (), length);
823 mono_class_compute_gc_descriptor (MonoClass *class)
827 gsize default_bitmap [4] = {0};
828 static gboolean gcj_inited = FALSE;
833 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
834 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
835 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
836 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
838 #ifdef HAVE_GC_GCJ_MALLOC
840 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
844 #ifdef GC_REDIRECT_TO_LOCAL
845 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
846 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
848 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
849 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
854 mono_loader_unlock ();
858 mono_class_init (class);
860 if (class->gc_descr_inited)
863 class->gc_descr_inited = TRUE;
864 class->gc_descr = GC_NO_DESCRIPTOR;
866 bitmap = default_bitmap;
867 if (class == mono_defaults.string_class) {
868 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
869 } else if (class->rank) {
870 mono_class_compute_gc_descriptor (class->element_class);
871 if (!class->element_class->valuetype) {
873 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
874 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
875 class->name_space, class->name);*/
877 /* remove the object header */
878 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
879 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
880 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
881 class->name_space, class->name);*/
882 if (bitmap != default_bitmap)
886 /*static int count = 0;
889 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
890 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
892 if (class->gc_descr == GC_NO_DESCRIPTOR)
893 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
895 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
896 if (bitmap != default_bitmap)
902 * field_is_special_static:
903 * @fklass: The MonoClass to look up.
904 * @field: The MonoClassField describing the field.
906 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
907 * SPECIAL_STATIC_NONE otherwise.
910 field_is_special_static (MonoClass *fklass, MonoClassField *field)
912 MonoCustomAttrInfo *ainfo;
914 ainfo = mono_custom_attrs_from_field (fklass, field);
917 for (i = 0; i < ainfo->num_attrs; ++i) {
918 MonoClass *klass = ainfo->attrs [i].ctor->klass;
919 if (klass->image == mono_defaults.corlib) {
920 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
921 mono_custom_attrs_free (ainfo);
922 return SPECIAL_STATIC_THREAD;
924 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
925 mono_custom_attrs_free (ainfo);
926 return SPECIAL_STATIC_CONTEXT;
930 mono_custom_attrs_free (ainfo);
931 return SPECIAL_STATIC_NONE;
934 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
935 #define mix(a,b,c) { \
936 a -= c; a ^= rot(c, 4); c += b; \
937 b -= a; b ^= rot(a, 6); a += c; \
938 c -= b; c ^= rot(b, 8); b += a; \
939 a -= c; a ^= rot(c,16); c += b; \
940 b -= a; b ^= rot(a,19); a += c; \
941 c -= b; c ^= rot(b, 4); b += a; \
943 #define final(a,b,c) { \
944 c ^= b; c -= rot(b,14); \
945 a ^= c; a -= rot(c,11); \
946 b ^= a; b -= rot(a,25); \
947 c ^= b; c -= rot(b,16); \
948 a ^= c; a -= rot(c,4); \
949 b ^= a; b -= rot(a,14); \
950 c ^= b; c -= rot(b,24); \
954 mono_method_get_imt_slot (MonoMethod *method) {
955 MonoMethodSignature *sig;
957 guint32 *hashes_start, *hashes;
962 * We do this to simplify generic sharing. It will hurt
963 * performance in cases where a class implements two different
964 * instantiations of the same generic interface.
966 if (method->is_inflated)
967 method = ((MonoMethodInflated*)method)->declaring;
969 sig = mono_method_signature (method);
970 hashes_count = sig->param_count + 4;
971 hashes_start = malloc (hashes_count * sizeof (guint32));
972 hashes = hashes_start;
974 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
975 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
976 method->klass->name_space, method->klass->name, method->name);
977 g_assert_not_reached ();
980 /* Initialize hashes */
981 hashes [0] = g_str_hash (method->klass->name);
982 hashes [1] = g_str_hash (method->klass->name_space);
983 hashes [2] = g_str_hash (method->name);
984 hashes [3] = mono_metadata_type_hash (sig->ret);
985 for (i = 0; i < sig->param_count; i++) {
986 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
989 /* Setup internal state */
990 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
992 /* Handle most of the hashes */
993 while (hashes_count > 3) {
1002 /* Handle the last 3 hashes (all the case statements fall through) */
1003 switch (hashes_count) {
1004 case 3 : c += hashes [2];
1005 case 2 : b += hashes [1];
1006 case 1 : a += hashes [0];
1008 case 0: /* nothing left to add */
1012 free (hashes_start);
1013 /* Report the result */
1014 return c % MONO_IMT_SIZE;
1023 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1024 guint32 imt_slot = mono_method_get_imt_slot (method);
1025 MonoImtBuilderEntry *entry;
1027 if (slot_num >= 0 && imt_slot != slot_num) {
1028 /* we build just a single imt slot and this is not it */
1032 entry = malloc (sizeof (MonoImtBuilderEntry));
1033 entry->method = method;
1034 entry->vtable_slot = vtable_slot;
1035 entry->next = imt_builder [imt_slot];
1036 if (imt_builder [imt_slot] != NULL) {
1037 entry->children = imt_builder [imt_slot]->children + 1;
1038 if (entry->children == 1) {
1039 mono_stats.imt_slots_with_collisions++;
1040 *imt_collisions_bitmap |= (1 << imt_slot);
1043 entry->children = 0;
1044 mono_stats.imt_used_slots++;
1046 imt_builder [imt_slot] = entry;
1048 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1049 method, method->klass->name_space, method->klass->name,
1050 method->name, imt_slot, vtable_slot, entry->children);
1056 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1058 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1062 e->method->klass->name_space,
1063 e->method->klass->name,
1066 printf (" * %s: NULL\n", message);
1072 compare_imt_builder_entries (const void *p1, const void *p2) {
1073 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1074 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1076 return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
1080 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1082 int count = end - start;
1083 int chunk_start = out_array->len;
1086 for (i = start; i < end; ++i) {
1087 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1088 item->method = sorted_array [i]->method;
1089 item->vtable_slot = sorted_array [i]->vtable_slot;
1090 item->is_equals = TRUE;
1092 item->check_target_idx = out_array->len + 1;
1094 item->check_target_idx = 0;
1095 g_ptr_array_add (out_array, item);
1098 int middle = start + count / 2;
1099 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1101 item->method = sorted_array [middle]->method;
1102 item->is_equals = FALSE;
1103 g_ptr_array_add (out_array, item);
1104 imt_emit_ir (sorted_array, start, middle, out_array);
1105 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1111 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1112 int number_of_entries = entries->children + 1;
1113 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1114 GPtrArray *result = g_ptr_array_new ();
1115 MonoImtBuilderEntry *current_entry;
1118 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1119 sorted_array [i] = current_entry;
1121 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1123 /*for (i = 0; i < number_of_entries; i++) {
1124 print_imt_entry (" sorted array:", sorted_array [i], i);
1127 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1129 free (sorted_array);
1134 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1135 if (imt_builder_entry != NULL) {
1136 if (imt_builder_entry->children == 0) {
1137 /* No collision, return the vtable slot contents */
1138 return vtable->vtable [imt_builder_entry->vtable_slot];
1140 /* Collision, build the thunk */
1141 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1144 result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
1145 for (i = 0; i < imt_ir->len; ++i)
1146 g_free (g_ptr_array_index (imt_ir, i));
1147 g_ptr_array_free (imt_ir, TRUE);
1157 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1160 guint32 imt_collisions_bitmap = 0;
1161 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1162 int method_count = 0;
1163 gboolean record_method_count_for_max_collisions = FALSE;
1166 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1168 for (i = 0; i < klass->interface_offsets_count; ++i) {
1169 MonoClass *iface = klass->interfaces_packed [i];
1170 int interface_offset = klass->interface_offsets_packed [i];
1171 int method_slot_in_interface;
1172 mono_class_setup_methods (iface);
1173 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1174 MonoMethod *method = iface->methods [method_slot_in_interface];
1175 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1178 if (extra_interfaces) {
1179 int interface_offset = klass->vtable_size;
1181 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1182 MonoClass* iface = list_item->data;
1183 int method_slot_in_interface;
1184 mono_class_setup_methods (iface);
1185 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1186 MonoMethod *method = iface->methods [method_slot_in_interface];
1187 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1189 interface_offset += iface->method.count;
1192 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1193 /* overwrite the imt slot only if we're building all the entries or if
1194 * we're uilding this specific one
1196 if (slot_num < 0 || i == slot_num)
1197 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1199 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1201 if (imt_builder [i] != NULL) {
1202 int methods_in_slot = imt_builder [i]->children + 1;
1203 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1204 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1205 record_method_count_for_max_collisions = TRUE;
1207 method_count += methods_in_slot;
1211 mono_stats.imt_number_of_methods += method_count;
1212 if (record_method_count_for_max_collisions) {
1213 mono_stats.imt_method_count_when_max_collisions = method_count;
1216 for (i = 0; i < MONO_IMT_SIZE; i++) {
1217 MonoImtBuilderEntry* entry = imt_builder [i];
1218 while (entry != NULL) {
1219 MonoImtBuilderEntry* next = entry->next;
1225 /* we OR the bitmap since we may build just a single imt slot at a time */
1226 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1230 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1231 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1234 static gpointer imt_trampoline = NULL;
1237 mono_install_imt_trampoline (gpointer tramp_code)
1239 imt_trampoline = tramp_code;
1242 static gpointer vtable_trampoline = NULL;
1245 mono_install_vtable_trampoline (gpointer tramp_code)
1247 vtable_trampoline = tramp_code;
1251 * mono_vtable_build_imt_slot:
1252 * @vtable: virtual object table struct
1253 * @imt_slot: slot in the IMT table
1255 * Fill the given @imt_slot in the IMT table of @vtable with
1256 * a trampoline or a thunk for the case of collisions.
1257 * This is part of the internal mono API.
1260 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1262 gpointer *imt = (gpointer*)vtable;
1263 imt -= MONO_IMT_SIZE;
1264 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1266 /* no support for extra interfaces: the proxy objects will need
1267 * to build the complete IMT
1268 * Update and heck needs to ahppen inside the proper domain lock, as all
1269 * the changes made to a MonoVTable.
1271 mono_domain_lock (vtable->domain);
1272 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1273 if (imt [imt_slot] == imt_trampoline)
1274 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1275 mono_domain_unlock (vtable->domain);
1278 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1281 * mono_class_vtable:
1282 * @domain: the application domain
1283 * @class: the class to initialize
1285 * VTables are domain specific because we create domain specific code, and
1286 * they contain the domain specific static class data.
1287 * On failure, NULL is returned, and class->exception_type is set.
1290 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1292 MonoClassRuntimeInfo *runtime_info;
1296 /* this check can be inlined in jitted code, too */
1297 runtime_info = class->runtime_info;
1298 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1299 return runtime_info->domain_vtables [domain->domain_id];
1300 return mono_class_create_runtime_vtable (domain, class);
1304 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1307 MonoClassRuntimeInfo *runtime_info, *old_info;
1308 MonoClassField *field;
1311 int imt_table_bytes = 0;
1312 guint32 vtable_size, class_size;
1314 guint32 constant_cols [MONO_CONSTANT_SIZE];
1316 gpointer *interface_offsets;
1318 mono_domain_lock (domain);
1319 runtime_info = class->runtime_info;
1320 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1321 mono_domain_unlock (domain);
1322 return runtime_info->domain_vtables [domain->domain_id];
1324 if (!class->inited || class->exception_type) {
1325 if (!mono_class_init (class) || class->exception_type){
1327 mono_domain_unlock (domain);
1328 exc = mono_class_get_exception_for_failure (class);
1330 mono_raise_exception (exc);
1334 mono_class_init (class);
1337 * For some classes, mono_class_init () already computed class->vtable_size, and
1338 * that is all that is needed because of the vtable trampolines.
1340 if (!class->vtable_size)
1341 mono_class_setup_vtable (class);
1343 if (class->exception_type) {
1344 mono_domain_unlock (domain);
1349 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1350 if (class->interface_offsets_count) {
1351 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1352 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1353 mono_stats.imt_number_of_tables++;
1354 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1357 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1358 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1361 mono_stats.used_class_count++;
1362 mono_stats.class_vtable_size += vtable_size;
1363 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1366 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1368 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1370 vt->rank = class->rank;
1371 vt->domain = domain;
1373 mono_class_compute_gc_descriptor (class);
1375 * We can't use typed allocation in the non-root domains, since the
1376 * collector needs the GC descriptor stored in the vtable even after
1377 * the mempool containing the vtable is destroyed when the domain is
1378 * unloaded. An alternative might be to allocate vtables in the GC
1379 * heap, but this does not seem to work (it leads to crashes inside
1380 * libgc). If that approach is tried, two gc descriptors need to be
1381 * allocated for each class: one for the root domain, and one for all
1382 * other domains. The second descriptor should contain a bit for the
1383 * vtable field in MonoObject, since we can no longer assume the
1384 * vtable is reachable by other roots after the appdomain is unloaded.
1386 #ifdef HAVE_BOEHM_GC
1387 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1388 vt->gc_descr = GC_NO_DESCRIPTOR;
1391 vt->gc_descr = class->gc_descr;
1393 if ((class_size = mono_class_data_size (class))) {
1394 if (class->has_static_refs) {
1395 gpointer statics_gc_descr;
1397 gsize default_bitmap [4] = {0};
1400 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1401 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1402 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1403 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1404 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1405 if (bitmap != default_bitmap)
1408 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1410 mono_stats.class_static_data_size += class_size;
1415 while ((field = mono_class_get_fields (class, &iter))) {
1416 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1418 if (mono_field_is_deleted (field))
1420 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1421 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1422 if (special_static != SPECIAL_STATIC_NONE) {
1423 guint32 size, offset;
1425 size = mono_type_size (field->type, &align);
1426 offset = mono_alloc_special_static_data (special_static, size, align);
1427 if (!domain->special_static_fields)
1428 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1429 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1433 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1434 MonoClass *fklass = mono_class_from_mono_type (field->type);
1435 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1436 t = (char*)vt->data + field->offset;
1437 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1440 if (fklass->valuetype) {
1441 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1443 /* it's a pointer type: add check */
1444 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1445 *t = *(char *)field->data;
1449 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1452 /* later do this only on demand if needed */
1454 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1456 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1458 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1459 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1460 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1465 vt->max_interface_id = class->max_interface_id;
1466 vt->interface_bitmap = class->interface_bitmap;
1468 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1469 // class->name, class->interface_offsets_count);
1471 if (! ARCH_USE_IMT) {
1472 /* initialize interface offsets */
1473 for (i = 0; i < class->interface_offsets_count; ++i) {
1474 int interface_id = class->interfaces_packed [i]->interface_id;
1475 int slot = class->interface_offsets_packed [i];
1476 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1480 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1481 * as we change the code in appdomain.c to invalidate vtables by
1482 * looking at the possible MonoClasses created for the domain.
1484 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1485 /* class->runtime_info is protected by the loader lock, both when
1486 * it it enlarged and when it is stored info.
1488 mono_loader_lock ();
1489 old_info = class->runtime_info;
1490 if (old_info && old_info->max_domain >= domain->domain_id) {
1491 /* someone already created a large enough runtime info */
1492 mono_memory_barrier ();
1493 old_info->domain_vtables [domain->domain_id] = vt;
1495 int new_size = domain->domain_id;
1497 new_size = MAX (new_size, old_info->max_domain);
1499 /* make the new size a power of two */
1501 while (new_size > i)
1504 /* this is a bounded memory retention issue: may want to
1505 * handle it differently when we'll have a rcu-like system.
1507 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1508 runtime_info->max_domain = new_size - 1;
1509 /* copy the stuff from the older info */
1511 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1513 runtime_info->domain_vtables [domain->domain_id] = vt;
1515 mono_memory_barrier ();
1516 class->runtime_info = runtime_info;
1518 mono_loader_unlock ();
1520 /* Initialize vtable */
1521 if (vtable_trampoline) {
1522 // This also covers the AOT case
1523 for (i = 0; i < class->vtable_size; ++i) {
1524 vt->vtable [i] = vtable_trampoline;
1527 mono_class_setup_vtable (class);
1529 for (i = 0; i < class->vtable_size; ++i) {
1532 if ((cm = class->vtable [i])) {
1533 if (mono_method_signature (cm)->generic_param_count)
1534 /* FIXME: Why is this needed ? */
1535 vt->vtable [i] = cm;
1537 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1542 if (ARCH_USE_IMT && imt_table_bytes) {
1543 /* Now that the vtable is full, we can actually fill up the IMT */
1544 if (imt_trampoline) {
1545 /* lazy construction of the IMT entries enabled */
1546 for (i = 0; i < MONO_IMT_SIZE; ++i)
1547 interface_offsets [i] = imt_trampoline;
1549 build_imt (class, vt, domain, interface_offsets, NULL);
1553 mono_domain_unlock (domain);
1555 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1556 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1557 MonoException *exc = mono_class_get_exception_for_failure (class);
1559 mono_raise_exception (exc);
1562 /* make sure the parent is initialized */
1564 mono_class_vtable (domain, class->parent);
1566 vt->type = mono_type_get_object (domain, &class->byval_arg);
1567 if (class->contextbound)
1576 * mono_class_proxy_vtable:
1577 * @domain: the application domain
1578 * @remove_class: the remote class
1580 * Creates a vtable for transparent proxies. It is basically
1581 * a copy of the real vtable of the class wrapped in @remote_class,
1582 * but all function pointers invoke the remoting functions, and
1583 * vtable->klass points to the transparent proxy class, and not to @class.
1586 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1588 MonoVTable *vt, *pvt;
1589 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1591 GSList *extra_interfaces = NULL;
1592 MonoClass *class = remote_class->proxy_class;
1593 gpointer *interface_offsets;
1595 vt = mono_class_vtable (domain, class);
1596 max_interface_id = vt->max_interface_id;
1598 /* Calculate vtable space for extra interfaces */
1599 for (j = 0; j < remote_class->interface_count; j++) {
1600 MonoClass* iclass = remote_class->interfaces[j];
1604 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1605 continue; /* interface implemented by the class */
1606 if (g_slist_find (extra_interfaces, iclass))
1609 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1611 method_count = mono_class_num_methods (iclass);
1613 ifaces = mono_class_get_implemented_interfaces (iclass);
1615 for (i = 0; i < ifaces->len; ++i) {
1616 MonoClass *ic = g_ptr_array_index (ifaces, i);
1617 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1618 continue; /* interface implemented by the class */
1619 if (g_slist_find (extra_interfaces, ic))
1621 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1622 method_count += mono_class_num_methods (ic);
1624 g_ptr_array_free (ifaces, TRUE);
1627 extra_interface_vtsize += method_count * sizeof (gpointer);
1628 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1632 mono_stats.imt_number_of_tables++;
1633 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1634 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1635 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1637 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1638 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1641 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1643 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1645 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1647 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1648 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1650 pvt->klass = mono_defaults.transparent_proxy_class;
1651 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1652 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1654 /* initialize vtable */
1655 mono_class_setup_vtable (class);
1656 for (i = 0; i < class->vtable_size; ++i) {
1659 if ((cm = class->vtable [i]))
1660 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1661 ? cm : arch_create_remoting_trampoline (cm, target_type);
1663 pvt->vtable [i] = NULL;
1666 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1667 /* create trampolines for abstract methods */
1668 for (k = class; k; k = k->parent) {
1670 gpointer iter = NULL;
1671 while ((m = mono_class_get_methods (k, &iter)))
1672 if (!pvt->vtable [m->slot])
1673 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1677 pvt->max_interface_id = max_interface_id;
1678 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1680 if (! ARCH_USE_IMT) {
1681 /* initialize interface offsets */
1682 for (i = 0; i < class->interface_offsets_count; ++i) {
1683 int interface_id = class->interfaces_packed [i]->interface_id;
1684 int slot = class->interface_offsets_packed [i];
1685 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1688 for (i = 0; i < class->interface_offsets_count; ++i) {
1689 int interface_id = class->interfaces_packed [i]->interface_id;
1690 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1693 if (extra_interfaces) {
1694 int slot = class->vtable_size;
1700 /* Create trampolines for the methods of the interfaces */
1701 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1702 interf = list_item->data;
1704 if (! ARCH_USE_IMT) {
1705 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1707 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1711 while ((cm = mono_class_get_methods (interf, &iter)))
1712 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1714 slot += mono_class_num_methods (interf);
1716 if (! ARCH_USE_IMT) {
1717 g_slist_free (extra_interfaces);
1722 /* Now that the vtable is full, we can actually fill up the IMT */
1723 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1724 if (extra_interfaces) {
1725 g_slist_free (extra_interfaces);
1733 * mono_class_field_is_special_static:
1735 * Returns whether @field is a thread/context static field.
1738 mono_class_field_is_special_static (MonoClassField *field)
1740 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1742 if (mono_field_is_deleted (field))
1744 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1745 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
1752 * mono_class_has_special_static_fields:
1754 * Returns whenever @klass has any thread/context static fields.
1757 mono_class_has_special_static_fields (MonoClass *klass)
1759 MonoClassField *field;
1763 while ((field = mono_class_get_fields (klass, &iter))) {
1764 g_assert (field->parent == klass);
1765 if (mono_class_field_is_special_static (field))
1773 * create_remote_class_key:
1774 * Creates an array of pointers that can be used as a hash key for a remote class.
1775 * The first element of the array is the number of pointers.
1778 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1783 if (remote_class == NULL) {
1784 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1785 key = g_malloc (sizeof(gpointer) * 3);
1786 key [0] = GINT_TO_POINTER (2);
1787 key [1] = mono_defaults.marshalbyrefobject_class;
1788 key [2] = extra_class;
1790 key = g_malloc (sizeof(gpointer) * 2);
1791 key [0] = GINT_TO_POINTER (1);
1792 key [1] = extra_class;
1795 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1796 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1797 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1798 key [1] = remote_class->proxy_class;
1800 // Keep the list of interfaces sorted
1801 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1802 if (extra_class && remote_class->interfaces [i] > extra_class) {
1803 key [j++] = extra_class;
1806 key [j] = remote_class->interfaces [i];
1809 key [j] = extra_class;
1811 // Replace the old class. The interface list is the same
1812 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1813 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1814 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1815 for (i = 0; i < remote_class->interface_count; i++)
1816 key [2 + i] = remote_class->interfaces [i];
1824 * copy_remote_class_key:
1826 * Make a copy of KEY in the mempool MP and return the copy.
1829 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1831 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1832 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1834 memcpy (mp_key, key, key_size);
1840 * mono_remote_class:
1841 * @domain: the application domain
1842 * @class_name: name of the remote class
1844 * Creates and initializes a MonoRemoteClass object for a remote type.
1848 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1850 MonoRemoteClass *rc;
1851 gpointer* key, *mp_key;
1853 key = create_remote_class_key (NULL, proxy_class);
1855 mono_domain_lock (domain);
1856 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1860 mono_domain_unlock (domain);
1864 mp_key = copy_remote_class_key (domain->mp, key);
1868 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1869 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1870 rc->interface_count = 1;
1871 rc->interfaces [0] = proxy_class;
1872 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1874 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1875 rc->interface_count = 0;
1876 rc->proxy_class = proxy_class;
1879 rc->default_vtable = NULL;
1880 rc->xdomain_vtable = NULL;
1881 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1883 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1885 mono_domain_unlock (domain);
1890 * clone_remote_class:
1891 * Creates a copy of the remote_class, adding the provided class or interface
1893 static MonoRemoteClass*
1894 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1896 MonoRemoteClass *rc;
1897 gpointer* key, *mp_key;
1899 key = create_remote_class_key (remote_class, extra_class);
1900 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1906 mp_key = copy_remote_class_key (domain->mp, key);
1910 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1912 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1913 rc->proxy_class = remote_class->proxy_class;
1914 rc->interface_count = remote_class->interface_count + 1;
1916 // Keep the list of interfaces sorted, since the hash key of
1917 // the remote class depends on this
1918 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1919 if (remote_class->interfaces [i] > extra_class && i == j)
1920 rc->interfaces [j++] = extra_class;
1921 rc->interfaces [j] = remote_class->interfaces [i];
1924 rc->interfaces [j] = extra_class;
1926 // Replace the old class. The interface array is the same
1927 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1928 rc->proxy_class = extra_class;
1929 rc->interface_count = remote_class->interface_count;
1930 if (rc->interface_count > 0)
1931 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1934 rc->default_vtable = NULL;
1935 rc->xdomain_vtable = NULL;
1936 rc->proxy_class_name = remote_class->proxy_class_name;
1938 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1944 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1946 mono_domain_lock (domain);
1947 if (rp->target_domain_id != -1) {
1948 if (remote_class->xdomain_vtable == NULL)
1949 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1950 mono_domain_unlock (domain);
1951 return remote_class->xdomain_vtable;
1953 if (remote_class->default_vtable == NULL) {
1956 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1957 klass = mono_class_from_mono_type (type);
1958 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1959 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1961 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1964 mono_domain_unlock (domain);
1965 return remote_class->default_vtable;
1969 * mono_upgrade_remote_class:
1970 * @domain: the application domain
1971 * @tproxy: the proxy whose remote class has to be upgraded.
1972 * @klass: class to which the remote class can be casted.
1974 * Updates the vtable of the remote class by adding the necessary method slots
1975 * and interface offsets so it can be safely casted to klass. klass can be a
1976 * class or an interface.
1979 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1981 MonoTransparentProxy *tproxy;
1982 MonoRemoteClass *remote_class;
1983 gboolean redo_vtable;
1985 mono_domain_lock (domain);
1987 tproxy = (MonoTransparentProxy*) proxy_object;
1988 remote_class = tproxy->remote_class;
1990 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1993 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1994 if (remote_class->interfaces [i] == klass)
1995 redo_vtable = FALSE;
1998 redo_vtable = (remote_class->proxy_class != klass);
2002 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2003 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2006 mono_domain_unlock (domain);
2011 * mono_object_get_virtual_method:
2012 * @obj: object to operate on.
2015 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2016 * the instance of a callvirt of method.
2019 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2022 MonoMethod **vtable;
2024 MonoMethod *res = NULL;
2026 klass = mono_object_class (obj);
2027 if (klass == mono_defaults.transparent_proxy_class) {
2028 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2034 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2037 mono_class_setup_vtable (klass);
2038 vtable = klass->vtable;
2040 /* check method->slot is a valid index: perform isinstance? */
2041 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2043 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2045 if (method->slot != -1) {
2046 res = vtable [method->slot];
2048 /* method->slot might not be set for instances of generic methods in the AOT case */
2049 if (method->is_inflated) {
2050 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2051 res = vtable [((MonoMethodInflated*)method)->declaring->slot];
2057 /* It may be an interface, abstract class method or generic method */
2058 if (!res || mono_method_signature (res)->generic_param_count)
2061 /* generic methods demand invoke_with_check */
2062 if (mono_method_signature (res)->generic_param_count)
2063 res = mono_marshal_get_remoting_invoke_with_check (res);
2065 res = mono_marshal_get_remoting_invoke (res);
2067 if (method->is_inflated && !res->is_inflated) {
2068 /* Have to inflate the result */
2069 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2079 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2081 g_error ("runtime invoke called on uninitialized runtime");
2085 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2088 * mono_runtime_invoke:
2089 * @method: method to invoke
2090 * @obJ: object instance
2091 * @params: arguments to the method
2092 * @exc: exception information.
2094 * Invokes the method represented by @method on the object @obj.
2096 * obj is the 'this' pointer, it should be NULL for static
2097 * methods, a MonoObject* for object instances and a pointer to
2098 * the value type for value types.
2100 * The params array contains the arguments to the method with the
2101 * same convention: MonoObject* pointers for object instances and
2102 * pointers to the value type otherwise.
2104 * From unmanaged code you'll usually use the
2105 * mono_runtime_invoke() variant.
2107 * Note that this function doesn't handle virtual methods for
2108 * you, it will exec the exact method you pass: we still need to
2109 * expose a function to lookup the derived class implementation
2110 * of a virtual method (there are examples of this in the code,
2113 * You can pass NULL as the exc argument if you don't want to
2114 * catch exceptions, otherwise, *exc will be set to the exception
2115 * thrown, if any. if an exception is thrown, you can't use the
2116 * MonoObject* result from the function.
2118 * If the method returns a value type, it is boxed in an object
2122 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2124 return default_mono_runtime_invoke (method, obj, params, exc);
2128 * mono_method_get_unmanaged_thunk:
2129 * @method: method to generate a thunk for.
2131 * Returns an unmanaged->managed thunk that can be used to call
2132 * a managed method directly from C.
2134 * The thunk's C signature closely matches the managed signature:
2136 * C#: public bool Equals (object obj);
2137 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2138 * MonoObject*, MonoException**);
2140 * The 1st ("this") parameter must not be used with static methods:
2142 * C#: public static bool ReferenceEquals (object a, object b);
2143 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2146 * The last argument must be a non-null pointer of a MonoException* pointer.
2147 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2148 * exception has been thrown in managed code. Otherwise it will point
2149 * to the MonoException* caught by the thunk. In this case, the result of
2150 * the thunk is undefined:
2152 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2153 * MonoException *ex = NULL;
2154 * Equals func = mono_method_get_unmanaged_thunk (method);
2155 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2157 * // handle exception
2160 * The calling convention of the thunk matches the platform's default
2161 * convention. This means that under Windows, C declarations must
2162 * contain the __stdcall attribute:
2164 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2165 * MonoObject*, MonoException**);
2169 * Value type arguments and return values are treated as they were objects:
2171 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2172 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2174 * Arguments must be properly boxed upon trunk's invocation, while return
2175 * values must be unboxed.
2178 mono_method_get_unmanaged_thunk (MonoMethod *method)
2180 method = mono_marshal_get_thunk_invoke_wrapper (method);
2181 return mono_compile_method (method);
2185 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2189 gpointer *p = (gpointer*)dest;
2196 case MONO_TYPE_BOOLEAN:
2198 case MONO_TYPE_U1: {
2199 guint8 *p = (guint8*)dest;
2200 *p = value ? *(guint8*)value : 0;
2205 case MONO_TYPE_CHAR: {
2206 guint16 *p = (guint16*)dest;
2207 *p = value ? *(guint16*)value : 0;
2210 #if SIZEOF_VOID_P == 4
2215 case MONO_TYPE_U4: {
2216 gint32 *p = (gint32*)dest;
2217 *p = value ? *(gint32*)value : 0;
2220 #if SIZEOF_VOID_P == 8
2225 case MONO_TYPE_U8: {
2226 gint64 *p = (gint64*)dest;
2227 *p = value ? *(gint64*)value : 0;
2230 case MONO_TYPE_R4: {
2231 float *p = (float*)dest;
2232 *p = value ? *(float*)value : 0;
2235 case MONO_TYPE_R8: {
2236 double *p = (double*)dest;
2237 *p = value ? *(double*)value : 0;
2240 case MONO_TYPE_STRING:
2241 case MONO_TYPE_SZARRAY:
2242 case MONO_TYPE_CLASS:
2243 case MONO_TYPE_OBJECT:
2244 case MONO_TYPE_ARRAY:
2245 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2247 case MONO_TYPE_FNPTR:
2248 case MONO_TYPE_PTR: {
2249 gpointer *p = (gpointer*)dest;
2250 *p = deref_pointer? *(gpointer*)value: value;
2253 case MONO_TYPE_VALUETYPE:
2254 /* note that 't' and 'type->type' can be different */
2255 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2256 t = type->data.klass->enum_basetype->type;
2260 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2262 memset (dest, 0, size);
2264 memcpy (dest, value, size);
2267 case MONO_TYPE_GENERICINST:
2268 t = type->data.generic_class->container_class->byval_arg.type;
2271 g_warning ("got type %x", type->type);
2272 g_assert_not_reached ();
2277 * mono_field_set_value:
2278 * @obj: Instance object
2279 * @field: MonoClassField describing the field to set
2280 * @value: The value to be set
2282 * Sets the value of the field described by @field in the object instance @obj
2283 * to the value passed in @value. This method should only be used for instance
2284 * fields. For static fields, use mono_field_static_set_value.
2286 * The value must be on the native format of the field type.
2289 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2293 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2295 dest = (char*)obj + field->offset;
2296 set_value (field->type, dest, value, FALSE);
2300 * mono_field_static_set_value:
2301 * @field: MonoClassField describing the field to set
2302 * @value: The value to be set
2304 * Sets the value of the static field described by @field
2305 * to the value passed in @value.
2307 * The value must be on the native format of the field type.
2310 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2314 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2315 /* you cant set a constant! */
2316 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2318 dest = (char*)vt->data + field->offset;
2319 set_value (field->type, dest, value, FALSE);
2322 /* Used by the debugger */
2324 mono_vtable_get_static_field_data (MonoVTable *vt)
2330 * mono_field_get_value:
2331 * @obj: Object instance
2332 * @field: MonoClassField describing the field to fetch information from
2333 * @value: pointer to the location where the value will be stored
2335 * Use this routine to get the value of the field @field in the object
2338 * The pointer provided by value must be of the field type, for reference
2339 * types this is a MonoObject*, for value types its the actual pointer to
2344 * mono_field_get_value (obj, int_field, &i);
2347 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2351 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2353 src = (char*)obj + field->offset;
2354 set_value (field->type, value, src, TRUE);
2358 * mono_field_get_value_object:
2359 * @domain: domain where the object will be created (if boxing)
2360 * @field: MonoClassField describing the field to fetch information from
2361 * @obj: The object instance for the field.
2363 * Returns: a new MonoObject with the value from the given field. If the
2364 * field represents a value type, the value is boxed.
2368 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2372 MonoVTable *vtable = NULL;
2374 gboolean is_static = FALSE;
2375 gboolean is_ref = FALSE;
2377 switch (field->type->type) {
2378 case MONO_TYPE_STRING:
2379 case MONO_TYPE_OBJECT:
2380 case MONO_TYPE_CLASS:
2381 case MONO_TYPE_ARRAY:
2382 case MONO_TYPE_SZARRAY:
2387 case MONO_TYPE_BOOLEAN:
2390 case MONO_TYPE_CHAR:
2399 case MONO_TYPE_VALUETYPE:
2400 is_ref = field->type->byref;
2402 case MONO_TYPE_GENERICINST:
2403 is_ref = !field->type->data.generic_class->container_class->valuetype;
2406 g_error ("type 0x%x not handled in "
2407 "mono_field_get_value_object", field->type->type);
2411 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2413 vtable = mono_class_vtable (domain, field->parent);
2414 if (!vtable->initialized)
2415 mono_runtime_class_init (vtable);
2420 mono_field_static_get_value (vtable, field, &o);
2422 mono_field_get_value (obj, field, &o);
2427 /* boxed value type */
2428 klass = mono_class_from_mono_type (field->type);
2429 o = mono_object_new (domain, klass);
2430 v = ((gchar *) o) + sizeof (MonoObject);
2432 mono_field_static_get_value (vtable, field, v);
2434 mono_field_get_value (obj, field, v);
2441 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2444 const char *p = blob;
2445 mono_metadata_decode_blob_size (p, &p);
2448 case MONO_TYPE_BOOLEAN:
2451 *(guint8 *) value = *p;
2453 case MONO_TYPE_CHAR:
2456 *(guint16*) value = read16 (p);
2460 *(guint32*) value = read32 (p);
2464 *(guint64*) value = read64 (p);
2467 readr4 (p, (float*) value);
2470 readr8 (p, (double*) value);
2472 case MONO_TYPE_STRING:
2473 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2475 case MONO_TYPE_CLASS:
2476 *(gpointer*) value = NULL;
2480 g_warning ("type 0x%02x should not be in constant table", type);
2486 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2488 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2489 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2493 * mono_field_static_get_value:
2494 * @vt: vtable to the object
2495 * @field: MonoClassField describing the field to fetch information from
2496 * @value: where the value is returned
2498 * Use this routine to get the value of the static field @field value.
2500 * The pointer provided by value must be of the field type, for reference
2501 * types this is a MonoObject*, for value types its the actual pointer to
2506 * mono_field_static_get_value (vt, int_field, &i);
2509 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2513 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2515 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2516 get_default_field_value (vt->domain, field, value);
2520 src = (char*)vt->data + field->offset;
2521 set_value (field->type, value, src, TRUE);
2525 * mono_property_set_value:
2526 * @prop: MonoProperty to set
2527 * @obj: instance object on which to act
2528 * @params: parameters to pass to the propery
2529 * @exc: optional exception
2531 * Invokes the property's set method with the given arguments on the
2532 * object instance obj (or NULL for static properties).
2534 * You can pass NULL as the exc argument if you don't want to
2535 * catch exceptions, otherwise, *exc will be set to the exception
2536 * thrown, if any. if an exception is thrown, you can't use the
2537 * MonoObject* result from the function.
2540 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2542 default_mono_runtime_invoke (prop->set, obj, params, exc);
2546 * mono_property_get_value:
2547 * @prop: MonoProperty to fetch
2548 * @obj: instance object on which to act
2549 * @params: parameters to pass to the propery
2550 * @exc: optional exception
2552 * Invokes the property's get method with the given arguments on the
2553 * object instance obj (or NULL for static properties).
2555 * You can pass NULL as the exc argument if you don't want to
2556 * catch exceptions, otherwise, *exc will be set to the exception
2557 * thrown, if any. if an exception is thrown, you can't use the
2558 * MonoObject* result from the function.
2560 * Returns: the value from invoking the get method on the property.
2563 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2565 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2569 * mono_nullable_init:
2570 * @buf: The nullable structure to initialize.
2571 * @value: the value to initialize from
2572 * @klass: the type for the object
2574 * Initialize the nullable structure pointed to by @buf from @value which
2575 * should be a boxed value type. The size of @buf should be able to hold
2576 * as much data as the @klass->instance_size (which is the number of bytes
2577 * that will be copies).
2579 * Since Nullables have variable structure, we can not define a C
2580 * structure for them.
2583 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2585 MonoClass *param_class = klass->cast_class;
2587 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2588 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2590 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2592 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2594 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2598 * mono_nullable_box:
2599 * @buf: The buffer representing the data to be boxed
2600 * @klass: the type to box it as.
2602 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2606 mono_nullable_box (guint8 *buf, MonoClass *klass)
2608 MonoClass *param_class = klass->cast_class;
2610 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2611 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2613 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2614 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2615 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2623 * mono_get_delegate_invoke:
2624 * @klass: The delegate class
2626 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2629 mono_get_delegate_invoke (MonoClass *klass)
2633 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2640 * mono_runtime_delegate_invoke:
2641 * @delegate: pointer to a delegate object.
2642 * @params: parameters for the delegate.
2643 * @exc: Pointer to the exception result.
2645 * Invokes the delegate method @delegate with the parameters provided.
2647 * You can pass NULL as the exc argument if you don't want to
2648 * catch exceptions, otherwise, *exc will be set to the exception
2649 * thrown, if any. if an exception is thrown, you can't use the
2650 * MonoObject* result from the function.
2653 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2657 im = mono_get_delegate_invoke (delegate->vtable->klass);
2660 return mono_runtime_invoke (im, delegate, params, exc);
2663 static char **main_args = NULL;
2664 static int num_main_args;
2667 * mono_runtime_get_main_args:
2669 * Returns: a MonoArray with the arguments passed to the main program
2672 mono_runtime_get_main_args (void)
2676 MonoDomain *domain = mono_domain_get ();
2681 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2683 for (i = 0; i < num_main_args; ++i)
2684 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2690 fire_process_exit_event (void)
2692 MonoClassField *field;
2693 MonoDomain *domain = mono_domain_get ();
2695 MonoObject *delegate, *exc;
2697 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2700 if (domain != mono_get_root_domain ())
2703 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2704 if (delegate == NULL)
2709 mono_runtime_delegate_invoke (delegate, pa, &exc);
2713 * mono_runtime_run_main:
2714 * @method: the method to start the application with (usually Main)
2715 * @argc: number of arguments from the command line
2716 * @argv: array of strings from the command line
2717 * @exc: excetption results
2719 * Execute a standard Main() method (argc/argv contains the
2720 * executable name). This method also sets the command line argument value
2721 * needed by System.Environment.
2726 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2730 MonoArray *args = NULL;
2731 MonoDomain *domain = mono_domain_get ();
2732 gchar *utf8_fullpath;
2735 g_assert (method != NULL);
2737 mono_thread_set_main (mono_thread_current ());
2739 main_args = g_new0 (char*, argc);
2740 num_main_args = argc;
2742 if (!g_path_is_absolute (argv [0])) {
2743 gchar *basename = g_path_get_basename (argv [0]);
2744 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2748 utf8_fullpath = mono_utf8_from_external (fullpath);
2749 if(utf8_fullpath == NULL) {
2750 /* Printing the arg text will cause glib to
2751 * whinge about "Invalid UTF-8", but at least
2752 * its relevant, and shows the problem text
2755 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2756 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2763 utf8_fullpath = mono_utf8_from_external (argv[0]);
2764 if(utf8_fullpath == NULL) {
2765 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2766 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2771 main_args [0] = utf8_fullpath;
2773 for (i = 1; i < argc; ++i) {
2776 utf8_arg=mono_utf8_from_external (argv[i]);
2777 if(utf8_arg==NULL) {
2778 /* Ditto the comment about Invalid UTF-8 here */
2779 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2780 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2784 main_args [i] = utf8_arg;
2788 if (mono_method_signature (method)->param_count) {
2789 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2790 for (i = 0; i < argc; ++i) {
2791 /* The encodings should all work, given that
2792 * we've checked all these args for the
2795 gchar *str = mono_utf8_from_external (argv [i]);
2796 MonoString *arg = mono_string_new (domain, str);
2797 mono_array_setref (args, i, arg);
2801 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2804 mono_assembly_set_main (method->klass->image->assembly);
2806 result = mono_runtime_exec_main (method, args, exc);
2807 fire_process_exit_event ();
2811 /* Used in call_unhandled_exception_delegate */
2813 create_unhandled_exception_eventargs (MonoObject *exc)
2817 MonoMethod *method = NULL;
2818 MonoBoolean is_terminating = TRUE;
2821 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2824 mono_class_init (klass);
2826 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2827 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2831 args [1] = &is_terminating;
2833 obj = mono_object_new (mono_domain_get (), klass);
2834 mono_runtime_invoke (method, obj, args, NULL);
2839 /* Used in mono_unhandled_exception */
2841 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2842 MonoObject *e = NULL;
2845 pa [0] = domain->domain;
2846 pa [1] = create_unhandled_exception_eventargs (exc);
2847 mono_runtime_delegate_invoke (delegate, pa, &e);
2850 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2851 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2856 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2859 * mono_runtime_unhandled_exception_policy_set:
2860 * @policy: the new policy
2862 * This is a VM internal routine.
2864 * Sets the runtime policy for handling unhandled exceptions.
2867 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2868 runtime_unhandled_exception_policy = policy;
2872 * mono_runtime_unhandled_exception_policy_get:
2874 * This is a VM internal routine.
2876 * Gets the runtime policy for handling unhandled exceptions.
2878 MonoRuntimeUnhandledExceptionPolicy
2879 mono_runtime_unhandled_exception_policy_get (void) {
2880 return runtime_unhandled_exception_policy;
2884 * mono_unhandled_exception:
2885 * @exc: exception thrown
2887 * This is a VM internal routine.
2889 * We call this function when we detect an unhandled exception
2890 * in the default domain.
2892 * It invokes the * UnhandledException event in AppDomain or prints
2893 * a warning to the console
2896 mono_unhandled_exception (MonoObject *exc)
2898 MonoDomain *current_domain = mono_domain_get ();
2899 MonoDomain *root_domain = mono_get_root_domain ();
2900 MonoClassField *field;
2901 MonoObject *current_appdomain_delegate;
2902 MonoObject *root_appdomain_delegate;
2904 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2905 "UnhandledException");
2908 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2909 gboolean abort_process = (mono_thread_current () == main_thread) ||
2910 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2911 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2912 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2913 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2915 current_appdomain_delegate = NULL;
2918 /* set exitcode only if we will abort the process */
2920 mono_environment_exitcode_set (1);
2921 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2922 mono_print_unhandled_exception (exc);
2924 if (root_appdomain_delegate) {
2925 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2927 if (current_appdomain_delegate) {
2928 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2935 * Launch a new thread to execute a function
2937 * main_func is called back from the thread with main_args as the
2938 * parameter. The callback function is expected to start Main()
2939 * eventually. This function then waits for all managed threads to
2941 * It is not necesseray anymore to execute managed code in a subthread,
2942 * so this function should not be used anymore by default: just
2943 * execute the code and then call mono_thread_manage ().
2946 mono_runtime_exec_managed_code (MonoDomain *domain,
2947 MonoMainThreadFunc main_func,
2950 mono_thread_create (domain, main_func, main_args);
2952 mono_thread_manage ();
2956 * Execute a standard Main() method (args doesn't contain the
2960 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2965 MonoCustomAttrInfo* cinfo;
2966 gboolean has_stathread_attribute;
2967 MonoThread* thread = mono_thread_current ();
2973 domain = mono_object_domain (args);
2974 if (!domain->entry_assembly) {
2976 MonoAssembly *assembly;
2978 assembly = method->klass->image->assembly;
2979 domain->entry_assembly = assembly;
2980 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2982 str = g_strconcat (assembly->image->name, ".config", NULL);
2983 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2987 cinfo = mono_custom_attrs_from_method (method);
2989 static MonoClass *stathread_attribute = NULL;
2990 if (!stathread_attribute)
2991 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
2992 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
2994 mono_custom_attrs_free (cinfo);
2996 has_stathread_attribute = FALSE;
2998 if (has_stathread_attribute) {
2999 thread->apartment_state = ThreadApartmentState_STA;
3000 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
3001 thread->apartment_state = ThreadApartmentState_Unknown;
3003 thread->apartment_state = ThreadApartmentState_MTA;
3005 mono_thread_init_apartment_state ();
3007 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3009 /* FIXME: check signature of method */
3010 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3012 res = mono_runtime_invoke (method, NULL, pa, exc);
3014 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3018 mono_environment_exitcode_set (rval);
3020 mono_runtime_invoke (method, NULL, pa, exc);
3024 /* If the return type of Main is void, only
3025 * set the exitcode if an exception was thrown
3026 * (we don't want to blow away an
3027 * explicitly-set exit code)
3030 mono_environment_exitcode_set (rval);
3034 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3040 * mono_install_runtime_invoke:
3041 * @func: Function to install
3043 * This is a VM internal routine
3046 mono_install_runtime_invoke (MonoInvokeFunc func)
3048 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3053 * mono_runtime_invoke_array:
3054 * @method: method to invoke
3055 * @obJ: object instance
3056 * @params: arguments to the method
3057 * @exc: exception information.
3059 * Invokes the method represented by @method on the object @obj.
3061 * obj is the 'this' pointer, it should be NULL for static
3062 * methods, a MonoObject* for object instances and a pointer to
3063 * the value type for value types.
3065 * The params array contains the arguments to the method with the
3066 * same convention: MonoObject* pointers for object instances and
3067 * pointers to the value type otherwise. The _invoke_array
3068 * variant takes a C# object[] as the params argument (MonoArray
3069 * *params): in this case the value types are boxed inside the
3070 * respective reference representation.
3072 * From unmanaged code you'll usually use the
3073 * mono_runtime_invoke() variant.
3075 * Note that this function doesn't handle virtual methods for
3076 * you, it will exec the exact method you pass: we still need to
3077 * expose a function to lookup the derived class implementation
3078 * of a virtual method (there are examples of this in the code,
3081 * You can pass NULL as the exc argument if you don't want to
3082 * catch exceptions, otherwise, *exc will be set to the exception
3083 * thrown, if any. if an exception is thrown, you can't use the
3084 * MonoObject* result from the function.
3086 * If the method returns a value type, it is boxed in an object
3090 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3093 MonoMethodSignature *sig = mono_method_signature (method);
3094 gpointer *pa = NULL;
3097 if (NULL != params) {
3098 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3099 for (i = 0; i < mono_array_length (params); i++) {
3100 MonoType *t = sig->params [i];
3106 case MONO_TYPE_BOOLEAN:
3109 case MONO_TYPE_CHAR:
3118 case MONO_TYPE_VALUETYPE:
3119 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3122 g_assert_not_reached ();
3123 /* The runtime invoke wrapper needs the original boxed vtype */
3124 pa [i] = mono_array_get (params, MonoObject*, i);
3126 /* MS seems to create the objects if a null is passed in */
3127 if (!mono_array_get (params, MonoObject*, i))
3128 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3132 * We can't pass the unboxed vtype byref to the callee, since
3133 * that would mean the callee would be able to modify boxed
3134 * primitive types. So we (and MS) make a copy of the boxed
3135 * object, pass that to the callee, and replace the original
3136 * boxed object in the arg array with the copy.
3138 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3139 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3140 mono_array_setref (params, i, copy);
3143 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3146 case MONO_TYPE_STRING:
3147 case MONO_TYPE_OBJECT:
3148 case MONO_TYPE_CLASS:
3149 case MONO_TYPE_ARRAY:
3150 case MONO_TYPE_SZARRAY:
3152 pa [i] = mono_array_addr (params, MonoObject*, i);
3153 // FIXME: I need to check this code path
3155 pa [i] = mono_array_get (params, MonoObject*, i);
3157 case MONO_TYPE_GENERICINST:
3159 t = &t->data.generic_class->container_class->this_arg;
3161 t = &t->data.generic_class->container_class->byval_arg;
3164 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3169 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3172 if (mono_class_is_nullable (method->klass)) {
3173 /* Need to create a boxed vtype instead */
3179 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3183 obj = mono_object_new (mono_domain_get (), method->klass);
3184 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3185 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3187 if (method->klass->valuetype)
3188 o = mono_object_unbox (obj);
3191 } else if (method->klass->valuetype) {
3192 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3195 mono_runtime_invoke (method, o, pa, exc);
3198 if (mono_class_is_nullable (method->klass)) {
3199 MonoObject *nullable;
3201 /* Convert the unboxed vtype into a Nullable structure */
3202 nullable = mono_object_new (mono_domain_get (), method->klass);
3204 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3205 obj = mono_object_unbox (nullable);
3208 /* obj must be already unboxed if needed */
3209 return mono_runtime_invoke (method, obj, pa, exc);
3214 arith_overflow (void)
3216 mono_raise_exception (mono_get_exception_overflow ());
3220 * mono_object_allocate:
3221 * @size: number of bytes to allocate
3223 * This is a very simplistic routine until we have our GC-aware
3226 * Returns: an allocated object of size @size, or NULL on failure.
3228 static inline void *
3229 mono_object_allocate (size_t size, MonoVTable *vtable)
3232 mono_stats.new_object_count++;
3233 ALLOC_OBJECT (o, vtable, size);
3239 * mono_object_allocate_ptrfree:
3240 * @size: number of bytes to allocate
3242 * Note that the memory allocated is not zeroed.
3243 * Returns: an allocated object of size @size, or NULL on failure.
3245 static inline void *
3246 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3249 mono_stats.new_object_count++;
3250 ALLOC_PTRFREE (o, vtable, size);
3254 static inline void *
3255 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3258 ALLOC_TYPED (o, size, vtable);
3259 mono_stats.new_object_count++;
3266 * @klass: the class of the object that we want to create
3268 * Returns: a newly created object whose definition is
3269 * looked up using @klass. This will not invoke any constructors,
3270 * so the consumer of this routine has to invoke any constructors on
3271 * its own to initialize the object.
3274 mono_object_new (MonoDomain *domain, MonoClass *klass)
3276 MONO_ARCH_SAVE_REGS;
3277 return mono_object_new_specific (mono_class_vtable (domain, klass));
3281 * mono_object_new_specific:
3282 * @vtable: the vtable of the object that we want to create
3284 * Returns: A newly created object with class and domain specified
3288 mono_object_new_specific (MonoVTable *vtable)
3292 MONO_ARCH_SAVE_REGS;
3294 /* check for is_com_object for COM Interop */
3295 if (vtable->remote || vtable->klass->is_com_object)
3298 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3301 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3304 mono_class_init (klass);
3306 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3308 vtable->domain->create_proxy_for_type_method = im;
3311 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3313 o = mono_runtime_invoke (im, NULL, pa, NULL);
3314 if (o != NULL) return o;
3317 return mono_object_new_alloc_specific (vtable);
3321 mono_object_new_alloc_specific (MonoVTable *vtable)
3325 if (!vtable->klass->has_references) {
3326 o = mono_object_new_ptrfree (vtable);
3327 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3328 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3330 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3331 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3333 if (vtable->klass->has_finalize)
3334 mono_object_register_finalizer (o);
3336 mono_profiler_allocation (o, vtable->klass);
3341 mono_object_new_fast (MonoVTable *vtable)
3344 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3349 mono_object_new_ptrfree (MonoVTable *vtable)
3352 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3353 #if NEED_TO_ZERO_PTRFREE
3354 /* an inline memset is much faster for the common vcase of small objects
3355 * note we assume the allocated size is a multiple of sizeof (void*).
3357 if (vtable->klass->instance_size < 128) {
3359 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3360 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3366 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3373 mono_object_new_ptrfree_box (MonoVTable *vtable)
3376 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3377 /* the object will be boxed right away, no need to memzero it */
3382 * mono_class_get_allocation_ftn:
3384 * @for_box: the object will be used for boxing
3385 * @pass_size_in_words:
3387 * Return the allocation function appropriate for the given class.
3391 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3393 *pass_size_in_words = FALSE;
3395 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3396 return mono_object_new_specific;
3398 if (!vtable->klass->has_references) {
3399 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3401 return mono_object_new_ptrfree_box;
3402 return mono_object_new_ptrfree;
3405 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3407 return mono_object_new_fast;
3410 * FIXME: This is actually slower than mono_object_new_fast, because
3411 * of the overhead of parameter passing.
3414 *pass_size_in_words = TRUE;
3415 #ifdef GC_REDIRECT_TO_LOCAL
3416 return GC_local_gcj_fast_malloc;
3418 return GC_gcj_fast_malloc;
3423 return mono_object_new_specific;
3427 * mono_object_new_from_token:
3428 * @image: Context where the type_token is hosted
3429 * @token: a token of the type that we want to create
3431 * Returns: A newly created object whose definition is
3432 * looked up using @token in the @image image
3435 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3439 class = mono_class_get (image, token);
3441 return mono_object_new (domain, class);
3446 * mono_object_clone:
3447 * @obj: the object to clone
3449 * Returns: A newly created object who is a shallow copy of @obj
3452 mono_object_clone (MonoObject *obj)
3457 size = obj->vtable->klass->instance_size;
3458 o = mono_object_allocate (size, obj->vtable);
3459 /* do not copy the sync state */
3460 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3463 if (obj->vtable->klass->has_references)
3464 mono_gc_wbarrier_object (o);
3466 mono_profiler_allocation (o, obj->vtable->klass);
3468 if (obj->vtable->klass->has_finalize)
3469 mono_object_register_finalizer (o);
3474 * mono_array_full_copy:
3475 * @src: source array to copy
3476 * @dest: destination array
3478 * Copies the content of one array to another with exactly the same type and size.
3481 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3483 mono_array_size_t size;
3484 MonoClass *klass = src->obj.vtable->klass;
3486 MONO_ARCH_SAVE_REGS;
3488 g_assert (klass == dest->obj.vtable->klass);
3490 size = mono_array_length (src);
3491 g_assert (size == mono_array_length (dest));
3492 size *= mono_array_element_size (klass);
3494 if (klass->element_class->valuetype) {
3495 if (klass->element_class->has_references)
3496 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3498 memcpy (&dest->vector, &src->vector, size);
3500 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3503 memcpy (&dest->vector, &src->vector, size);
3508 * mono_array_clone_in_domain:
3509 * @domain: the domain in which the array will be cloned into
3510 * @array: the array to clone
3512 * This routine returns a copy of the array that is hosted on the
3513 * specified MonoDomain.
3516 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3519 mono_array_size_t size, i;
3520 mono_array_size_t *sizes;
3521 MonoClass *klass = array->obj.vtable->klass;
3523 MONO_ARCH_SAVE_REGS;
3525 if (array->bounds == NULL) {
3526 size = mono_array_length (array);
3527 o = mono_array_new_full (domain, klass, &size, NULL);
3529 size *= mono_array_element_size (klass);
3531 if (klass->element_class->valuetype) {
3532 if (klass->element_class->has_references)
3533 mono_value_copy_array (o, 0, array, mono_array_length (array));
3535 memcpy (&o->vector, &array->vector, size);
3537 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3540 memcpy (&o->vector, &array->vector, size);
3545 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3546 size = mono_array_element_size (klass);
3547 for (i = 0; i < klass->rank; ++i) {
3548 sizes [i] = array->bounds [i].length;
3549 size *= array->bounds [i].length;
3550 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3552 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3554 if (klass->element_class->valuetype) {
3555 if (klass->element_class->has_references)
3556 mono_value_copy_array (o, 0, array, mono_array_length (array));
3558 memcpy (&o->vector, &array->vector, size);
3560 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3563 memcpy (&o->vector, &array->vector, size);
3571 * @array: the array to clone
3573 * Returns: A newly created array who is a shallow copy of @array
3576 mono_array_clone (MonoArray *array)
3578 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3581 /* helper macros to check for overflow when calculating the size of arrays */
3582 #ifdef MONO_BIG_ARRAYS
3583 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3584 #define MYGUINT_MAX MYGUINT64_MAX
3585 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3586 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
3587 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3588 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
3589 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
3591 #define MYGUINT32_MAX 4294967295U
3592 #define MYGUINT_MAX MYGUINT32_MAX
3593 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3594 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
3595 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3596 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
3597 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
3601 * mono_array_new_full:
3602 * @domain: domain where the object is created
3603 * @array_class: array class
3604 * @lengths: lengths for each dimension in the array
3605 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3607 * This routine creates a new array objects with the given dimensions,
3608 * lower bounds and type.
3611 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3613 mono_array_size_t byte_len, len, bounds_size;
3619 if (!array_class->inited)
3620 mono_class_init (array_class);
3622 byte_len = mono_array_element_size (array_class);
3625 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3626 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3628 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3632 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3634 for (i = 0; i < array_class->rank; ++i) {
3635 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3637 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3638 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3643 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3644 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3646 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3647 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3648 byte_len += sizeof (MonoArray);
3651 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3652 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3653 byte_len = (byte_len + 3) & ~3;
3654 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3655 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3656 byte_len += bounds_size;
3659 * Following three lines almost taken from mono_object_new ():
3660 * they need to be kept in sync.
3662 vtable = mono_class_vtable (domain, array_class);
3663 if (!array_class->has_references) {
3664 o = mono_object_allocate_ptrfree (byte_len, vtable);
3665 #if NEED_TO_ZERO_PTRFREE
3666 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3668 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3669 o = mono_object_allocate_spec (byte_len, vtable);
3671 o = mono_object_allocate (byte_len, vtable);
3674 array = (MonoArray*)o;
3675 array->max_length = len;
3678 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3679 array->bounds = bounds;
3680 for (i = 0; i < array_class->rank; ++i) {
3681 bounds [i].length = lengths [i];
3683 bounds [i].lower_bound = lower_bounds [i];
3687 mono_profiler_allocation (o, array_class);
3694 * @domain: domain where the object is created
3695 * @eclass: element class
3696 * @n: number of array elements
3698 * This routine creates a new szarray with @n elements of type @eclass.
3701 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3705 MONO_ARCH_SAVE_REGS;
3707 ac = mono_array_class_get (eclass, 1);
3708 g_assert (ac != NULL);
3710 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3714 * mono_array_new_specific:
3715 * @vtable: a vtable in the appropriate domain for an initialized class
3716 * @n: number of array elements
3718 * This routine is a fast alternative to mono_array_new() for code which
3719 * can be sure about the domain it operates in.
3722 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
3726 guint32 byte_len, elem_size;
3728 MONO_ARCH_SAVE_REGS;
3730 if (n > MONO_ARRAY_MAX_INDEX)
3733 elem_size = mono_array_element_size (vtable->klass);
3734 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
3735 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3736 byte_len = n * elem_size;
3737 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3738 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3739 byte_len += sizeof (MonoArray);
3740 if (!vtable->klass->has_references) {
3741 o = mono_object_allocate_ptrfree (byte_len, vtable);
3742 #if NEED_TO_ZERO_PTRFREE
3743 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3745 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3746 o = mono_object_allocate_spec (byte_len, vtable);
3748 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3749 o = mono_object_allocate (byte_len, vtable);
3752 ao = (MonoArray *)o;
3755 mono_profiler_allocation (o, vtable->klass);
3761 * mono_string_new_utf16:
3762 * @text: a pointer to an utf16 string
3763 * @len: the length of the string
3765 * Returns: A newly created string object which contains @text.
3768 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3772 s = mono_string_new_size (domain, len);
3773 g_assert (s != NULL);
3775 memcpy (mono_string_chars (s), text, len * 2);
3781 * mono_string_new_size:
3782 * @text: a pointer to an utf16 string
3783 * @len: the length of the string
3785 * Returns: A newly created string object of @len
3788 mono_string_new_size (MonoDomain *domain, gint32 len)
3792 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3794 /* overflow ? can't fit it, can't allocate it! */
3796 mono_gc_out_of_memory (-1);
3798 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3800 s = mono_object_allocate_ptrfree (size, vtable);
3803 #if NEED_TO_ZERO_PTRFREE
3806 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3812 * mono_string_new_len:
3813 * @text: a pointer to an utf8 string
3814 * @length: number of bytes in @text to consider
3816 * Returns: A newly created string object which contains @text.
3819 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3821 GError *error = NULL;
3822 MonoString *o = NULL;
3824 glong items_written;
3826 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3829 o = mono_string_new_utf16 (domain, ut, items_written);
3831 g_error_free (error);
3840 * @text: a pointer to an utf8 string
3842 * Returns: A newly created string object which contains @text.
3845 mono_string_new (MonoDomain *domain, const char *text)
3847 GError *error = NULL;
3848 MonoString *o = NULL;
3850 glong items_written;
3855 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3858 o = mono_string_new_utf16 (domain, ut, items_written);
3860 g_error_free (error);
3868 * mono_string_new_wrapper:
3869 * @text: pointer to utf8 characters.
3871 * Helper function to create a string object from @text in the current domain.
3874 mono_string_new_wrapper (const char *text)
3876 MonoDomain *domain = mono_domain_get ();
3878 MONO_ARCH_SAVE_REGS;
3881 return mono_string_new (domain, text);
3888 * @class: the class of the value
3889 * @value: a pointer to the unboxed data
3891 * Returns: A newly created object which contains @value.
3894 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3900 g_assert (class->valuetype);
3901 if (mono_class_is_nullable (class))
3902 return mono_nullable_box (value, class);
3904 vtable = mono_class_vtable (domain, class);
3905 size = mono_class_instance_size (class);
3906 res = mono_object_new_alloc_specific (vtable);
3907 mono_profiler_allocation (res, class);
3909 size = size - sizeof (MonoObject);
3912 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3915 #if NO_UNALIGNED_ACCESS
3916 memcpy ((char *)res + sizeof (MonoObject), value, size);
3920 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3923 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3926 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3929 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3932 memcpy ((char *)res + sizeof (MonoObject), value, size);
3935 if (class->has_finalize)
3936 mono_object_register_finalizer (res);
3942 * @dest: destination pointer
3943 * @src: source pointer
3944 * @klass: a valuetype class
3946 * Copy a valuetype from @src to @dest. This function must be used
3947 * when @klass contains references fields.
3950 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3952 int size = mono_class_value_size (klass, NULL);
3953 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3954 memcpy (dest, src, size);
3958 * mono_value_copy_array:
3959 * @dest: destination array
3960 * @dest_idx: index in the @dest array
3961 * @src: source pointer
3962 * @count: number of items
3964 * Copy @count valuetype items from @src to @dest. This function must be used
3965 * when @klass contains references fields.
3966 * Overlap is handled.
3969 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3971 int size = mono_array_element_size (dest->obj.vtable->klass);
3972 char *d = mono_array_addr_with_size (dest, size, dest_idx);
3973 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3974 memmove (d, src, size * count);
3978 * mono_object_get_domain:
3979 * @obj: object to query
3981 * Returns: the MonoDomain where the object is hosted
3984 mono_object_get_domain (MonoObject *obj)
3986 return mono_object_domain (obj);
3990 * mono_object_get_class:
3991 * @obj: object to query
3993 * Returns: the MonOClass of the object.
3996 mono_object_get_class (MonoObject *obj)
3998 return mono_object_class (obj);
4001 * mono_object_get_size:
4002 * @o: object to query
4004 * Returns: the size, in bytes, of @o
4007 mono_object_get_size (MonoObject* o)
4009 MonoClass* klass = mono_object_class (o);
4010 if (klass == mono_defaults.string_class) {
4011 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4012 } else if (o->vtable->rank) {
4013 MonoArray *array = (MonoArray*)o;
4014 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4015 if (array->bounds) {
4018 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4022 return mono_class_instance_size (klass);
4027 * mono_object_unbox:
4028 * @obj: object to unbox
4030 * Returns: a pointer to the start of the valuetype boxed in this
4033 * This method will assert if the object passed is not a valuetype.
4036 mono_object_unbox (MonoObject *obj)
4038 /* add assert for valuetypes? */
4039 g_assert (obj->vtable->klass->valuetype);
4040 return ((char*)obj) + sizeof (MonoObject);
4044 * mono_object_isinst:
4046 * @klass: a pointer to a class
4048 * Returns: @obj if @obj is derived from @klass
4051 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4054 mono_class_init (klass);
4056 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4057 return mono_object_isinst_mbyref (obj, klass);
4062 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4066 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4075 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4076 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4080 MonoClass *oklass = vt->klass;
4081 if ((oklass == mono_defaults.transparent_proxy_class))
4082 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4084 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4088 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4090 MonoDomain *domain = mono_domain_get ();
4092 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4093 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4094 MonoMethod *im = NULL;
4097 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4098 im = mono_object_get_virtual_method (rp, im);
4101 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4104 res = mono_runtime_invoke (im, rp, pa, NULL);
4106 if (*(MonoBoolean *) mono_object_unbox(res)) {
4107 /* Update the vtable of the remote type, so it can safely cast to this new type */
4108 mono_upgrade_remote_class (domain, obj, klass);
4117 * mono_object_castclass_mbyref:
4119 * @klass: a pointer to a class
4121 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4124 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4126 if (!obj) return NULL;
4127 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4129 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4131 "InvalidCastException"));
4136 MonoDomain *orig_domain;
4142 str_lookup (MonoDomain *domain, gpointer user_data)
4144 LDStrInfo *info = user_data;
4145 if (info->res || domain == info->orig_domain)
4147 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4153 mono_string_get_pinned (MonoString *str)
4157 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4158 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4159 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4160 news->length = mono_string_length (str);
4165 #define mono_string_get_pinned(str) (str)
4169 mono_string_is_interned_lookup (MonoString *str, int insert)
4171 MonoGHashTable *ldstr_table;
4175 domain = ((MonoObject *)str)->vtable->domain;
4176 ldstr_table = domain->ldstr_table;
4178 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4183 str = mono_string_get_pinned (str);
4184 mono_g_hash_table_insert (ldstr_table, str, str);
4188 LDStrInfo ldstr_info;
4189 ldstr_info.orig_domain = domain;
4190 ldstr_info.ins = str;
4191 ldstr_info.res = NULL;
4193 mono_domain_foreach (str_lookup, &ldstr_info);
4194 if (ldstr_info.res) {
4196 * the string was already interned in some other domain:
4197 * intern it in the current one as well.
4199 mono_g_hash_table_insert (ldstr_table, str, str);
4209 * mono_string_is_interned:
4210 * @o: String to probe
4212 * Returns whether the string has been interned.
4215 mono_string_is_interned (MonoString *o)
4217 return mono_string_is_interned_lookup (o, FALSE);
4221 * mono_string_intern:
4222 * @o: String to intern
4224 * Interns the string passed.
4225 * Returns: The interned string.
4228 mono_string_intern (MonoString *str)
4230 return mono_string_is_interned_lookup (str, TRUE);
4235 * @domain: the domain where the string will be used.
4236 * @image: a metadata context
4237 * @idx: index into the user string table.
4239 * Implementation for the ldstr opcode.
4240 * Returns: a loaded string from the @image/@idx combination.
4243 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4245 MONO_ARCH_SAVE_REGS;
4248 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4250 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4254 * mono_ldstr_metdata_sig
4255 * @domain: the domain for the string
4256 * @sig: the signature of a metadata string
4258 * Returns: a MonoString for a string stored in the metadata
4261 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4263 const char *str = sig;
4264 MonoString *o, *interned;
4267 len2 = mono_metadata_decode_blob_size (str, &str);
4270 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4271 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4274 guint16 *p2 = (guint16*)mono_string_chars (o);
4275 for (i = 0; i < len2; ++i) {
4276 *p2 = GUINT16_FROM_LE (*p2);
4282 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4284 /* o will get garbage collected */
4288 o = mono_string_get_pinned (o);
4289 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4296 * mono_string_to_utf8:
4297 * @s: a System.String
4299 * Return the UTF8 representation for @s.
4300 * the resulting buffer nedds to be freed with g_free().
4303 mono_string_to_utf8 (MonoString *s)
4307 GError *error = NULL;
4313 return g_strdup ("");
4315 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4317 MonoException *exc = mono_get_exception_argument ("string", error->message);
4318 g_error_free (error);
4319 mono_raise_exception(exc);
4321 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4322 if (s->length > written) {
4323 /* allocate the total length and copy the part of the string that has been converted */
4324 char *as2 = g_malloc0 (s->length);
4325 memcpy (as2, as, written);
4334 * mono_string_to_utf16:
4337 * Return an null-terminated array of the utf-16 chars
4338 * contained in @s. The result must be freed with g_free().
4339 * This is a temporary helper until our string implementation
4340 * is reworked to always include the null terminating char.
4343 mono_string_to_utf16 (MonoString *s)
4350 as = g_malloc ((s->length * 2) + 2);
4351 as [(s->length * 2)] = '\0';
4352 as [(s->length * 2) + 1] = '\0';
4355 return (gunichar2 *)(as);
4358 memcpy (as, mono_string_chars(s), s->length * 2);
4359 return (gunichar2 *)(as);
4363 * mono_string_from_utf16:
4364 * @data: the UTF16 string (LPWSTR) to convert
4366 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4368 * Returns: a MonoString.
4371 mono_string_from_utf16 (gunichar2 *data)
4373 MonoDomain *domain = mono_domain_get ();
4379 while (data [len]) len++;
4381 return mono_string_new_utf16 (domain, data, len);
4385 * mono_string_to_utf8_mp:
4386 * @s: a System.String
4388 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4391 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4393 char *r = mono_string_to_utf8 (s);
4400 len = strlen (r) + 1;
4401 mp_s = mono_mempool_alloc (mp, len);
4402 memcpy (mp_s, r, len);
4410 default_ex_handler (MonoException *ex)
4412 MonoObject *o = (MonoObject*)ex;
4413 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4417 static MonoExceptionFunc ex_handler = default_ex_handler;
4420 * mono_install_handler:
4421 * @func: exception handler
4423 * This is an internal JIT routine used to install the handler for exceptions
4427 mono_install_handler (MonoExceptionFunc func)
4429 ex_handler = func? func: default_ex_handler;
4433 * mono_raise_exception:
4434 * @ex: exception object
4436 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4439 mono_raise_exception (MonoException *ex)
4442 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4443 * that will cause gcc to omit the function epilog, causing problems when
4444 * the JIT tries to walk the stack, since the return address on the stack
4445 * will point into the next function in the executable, not this one.
4448 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4449 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4455 * mono_wait_handle_new:
4456 * @domain: Domain where the object will be created
4457 * @handle: Handle for the wait handle
4459 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4462 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4464 MonoWaitHandle *res;
4465 gpointer params [1];
4466 static MonoMethod *handle_set;
4468 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4470 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4472 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4474 params [0] = &handle;
4475 mono_runtime_invoke (handle_set, res, params, NULL);
4481 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4483 static MonoClassField *f_os_handle;
4484 static MonoClassField *f_safe_handle;
4486 if (!f_os_handle && !f_safe_handle) {
4487 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4488 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4493 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4497 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4503 * mono_async_result_new:
4504 * @domain:domain where the object will be created.
4505 * @handle: wait handle.
4506 * @state: state to pass to AsyncResult
4507 * @data: C closure data.
4509 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4510 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4514 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4516 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4517 MonoMethod *method = mono_get_context_capture_method ();
4519 /* we must capture the execution context from the original thread */
4521 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4522 /* note: result may be null if the flow is suppressed */
4526 MONO_OBJECT_SETREF (res, object_data, object_data);
4527 MONO_OBJECT_SETREF (res, async_state, state);
4529 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4531 res->sync_completed = FALSE;
4532 res->completed = FALSE;
4538 mono_message_init (MonoDomain *domain,
4539 MonoMethodMessage *this,
4540 MonoReflectionMethod *method,
4541 MonoArray *out_args)
4543 static MonoClass *object_array_klass;
4544 static MonoClass *byte_array_klass;
4545 static MonoClass *string_array_klass;
4546 MonoMethodSignature *sig = mono_method_signature (method->method);
4552 if (!object_array_klass) {
4555 klass = mono_array_class_get (mono_defaults.object_class, 1);
4558 mono_memory_barrier ();
4559 object_array_klass = klass;
4561 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4564 mono_memory_barrier ();
4565 byte_array_klass = klass;
4567 klass = mono_array_class_get (mono_defaults.string_class, 1);
4570 mono_memory_barrier ();
4571 string_array_klass = klass;
4574 MONO_OBJECT_SETREF (this, method, method);
4576 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4577 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4578 this->async_result = NULL;
4579 this->call_type = CallType_Sync;
4581 names = g_new (char *, sig->param_count);
4582 mono_method_get_param_names (method->method, (const char **) names);
4583 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4585 for (i = 0; i < sig->param_count; i++) {
4586 name = mono_string_new (domain, names [i]);
4587 mono_array_setref (this->names, i, name);
4591 for (i = 0, j = 0; i < sig->param_count; i++) {
4592 if (sig->params [i]->byref) {
4594 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4595 mono_array_setref (this->args, i, arg);
4599 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4603 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4606 mono_array_set (this->arg_types, guint8, i, arg_type);
4611 * mono_remoting_invoke:
4612 * @real_proxy: pointer to a RealProxy object
4613 * @msg: The MonoMethodMessage to execute
4614 * @exc: used to store exceptions
4615 * @out_args: used to store output arguments
4617 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4618 * IMessage interface and it is not trivial to extract results from there. So
4619 * we call an helper method PrivateInvoke instead of calling
4620 * RealProxy::Invoke() directly.
4622 * Returns: the result object.
4625 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4626 MonoObject **exc, MonoArray **out_args)
4628 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4631 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4634 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4636 real_proxy->vtable->domain->private_invoke_method = im;
4639 pa [0] = real_proxy;
4644 return mono_runtime_invoke (im, NULL, pa, exc);
4648 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4649 MonoObject **exc, MonoArray **out_args)
4651 static MonoClass *object_array_klass;
4654 MonoMethodSignature *sig;
4656 int i, j, outarg_count = 0;
4658 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4660 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4661 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4662 target = tp->rp->unwrapped_server;
4664 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4668 domain = mono_domain_get ();
4669 method = msg->method->method;
4670 sig = mono_method_signature (method);
4672 for (i = 0; i < sig->param_count; i++) {
4673 if (sig->params [i]->byref)
4677 if (!object_array_klass) {
4680 klass = mono_array_class_get (mono_defaults.object_class, 1);
4683 mono_memory_barrier ();
4684 object_array_klass = klass;
4687 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4688 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
4691 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4693 for (i = 0, j = 0; i < sig->param_count; i++) {
4694 if (sig->params [i]->byref) {
4696 arg = mono_array_get (msg->args, gpointer, i);
4697 mono_array_setref (*out_args, j, arg);
4706 * mono_print_unhandled_exception:
4707 * @exc: The exception
4709 * Prints the unhandled exception.
4712 mono_print_unhandled_exception (MonoObject *exc)
4714 char *message = (char *) "";
4718 gboolean free_message = FALSE;
4720 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4721 klass = exc->vtable->klass;
4723 while (klass && method == NULL) {
4724 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4726 klass = klass->parent;
4731 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4733 message = mono_string_to_utf8 (str);
4734 free_message = TRUE;
4739 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4740 * exc->vtable->klass->name, message);
4742 g_printerr ("\nUnhandled Exception: %s\n", message);
4749 * mono_delegate_ctor:
4750 * @this: pointer to an uninitialized delegate object
4751 * @target: target object
4752 * @addr: pointer to native code
4754 * This is used to initialize a delegate.
4757 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4759 MonoDomain *domain = mono_domain_get ();
4760 MonoDelegate *delegate = (MonoDelegate *)this;
4761 MonoMethod *method = NULL;
4768 class = this->vtable->klass;
4769 mono_stats.delegate_creations++;
4771 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4772 method = ji->method;
4773 delegate->method = method;
4776 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4778 method = mono_marshal_get_remoting_invoke (method);
4779 delegate->method_ptr = mono_compile_method (method);
4780 MONO_OBJECT_SETREF (delegate, target, target);
4781 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4782 method = mono_marshal_get_unbox_wrapper (method);
4783 delegate->method_ptr = mono_compile_method (method);
4784 MONO_OBJECT_SETREF (delegate, target, target);
4786 delegate->method_ptr = addr;
4787 MONO_OBJECT_SETREF (delegate, target, target);
4790 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4794 * mono_method_call_message_new:
4795 * @method: method to encapsulate
4796 * @params: parameters to the method
4797 * @invoke: optional, delegate invoke.
4798 * @cb: async callback delegate.
4799 * @state: state passed to the async callback.
4801 * Translates arguments pointers into a MonoMethodMessage.
4804 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4805 MonoDelegate **cb, MonoObject **state)
4807 MonoDomain *domain = mono_domain_get ();
4808 MonoMethodSignature *sig = mono_method_signature (method);
4809 MonoMethodMessage *msg;
4812 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4815 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4816 count = sig->param_count - 2;
4818 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4819 count = sig->param_count;
4822 for (i = 0; i < count; i++) {
4827 if (sig->params [i]->byref)
4828 vpos = *((gpointer *)params [i]);
4832 type = sig->params [i]->type;
4833 class = mono_class_from_mono_type (sig->params [i]);
4835 if (class->valuetype)
4836 arg = mono_value_box (domain, class, vpos);
4838 arg = *((MonoObject **)vpos);
4840 mono_array_setref (msg->args, i, arg);
4843 if (cb != NULL && state != NULL) {
4844 *cb = *((MonoDelegate **)params [i]);
4846 *state = *((MonoObject **)params [i]);
4853 * mono_method_return_message_restore:
4855 * Restore results from message based processing back to arguments pointers
4858 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4860 MonoMethodSignature *sig = mono_method_signature (method);
4861 int i, j, type, size, out_len;
4863 if (out_args == NULL)
4865 out_len = mono_array_length (out_args);
4869 for (i = 0, j = 0; i < sig->param_count; i++) {
4870 MonoType *pt = sig->params [i];
4875 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4877 arg = mono_array_get (out_args, gpointer, j);
4881 case MONO_TYPE_VOID:
4882 g_assert_not_reached ();
4886 case MONO_TYPE_BOOLEAN:
4889 case MONO_TYPE_CHAR:
4896 case MONO_TYPE_VALUETYPE: {
4898 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4899 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4902 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4903 memset (*((gpointer *)params [i]), 0, size);
4907 case MONO_TYPE_STRING:
4908 case MONO_TYPE_CLASS:
4909 case MONO_TYPE_ARRAY:
4910 case MONO_TYPE_SZARRAY:
4911 case MONO_TYPE_OBJECT:
4912 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4915 g_assert_not_reached ();
4924 * mono_load_remote_field:
4925 * @this: pointer to an object
4926 * @klass: klass of the object containing @field
4927 * @field: the field to load
4928 * @res: a storage to store the result
4930 * This method is called by the runtime on attempts to load fields of
4931 * transparent proxy objects. @this points to such TP, @klass is the class of
4932 * the object containing @field. @res is a storage location which can be
4933 * used to store the result.
4935 * Returns: an address pointing to the value of field.
4938 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4940 static MonoMethod *getter = NULL;
4941 MonoDomain *domain = mono_domain_get ();
4942 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4943 MonoClass *field_class;
4944 MonoMethodMessage *msg;
4945 MonoArray *out_args;
4949 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4950 g_assert (res != NULL);
4952 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4953 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4958 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4962 field_class = mono_class_from_mono_type (field->type);
4964 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4965 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4966 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4968 full_name = mono_type_get_full_name (klass);
4969 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4970 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4973 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4975 if (exc) mono_raise_exception ((MonoException *)exc);
4977 if (mono_array_length (out_args) == 0)
4980 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4982 if (field_class->valuetype) {
4983 return ((char *)*res) + sizeof (MonoObject);
4989 * mono_load_remote_field_new:
4994 * Missing documentation.
4997 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
4999 static MonoMethod *getter = NULL;
5000 MonoDomain *domain = mono_domain_get ();
5001 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5002 MonoClass *field_class;
5003 MonoMethodMessage *msg;
5004 MonoArray *out_args;
5005 MonoObject *exc, *res;
5008 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5010 field_class = mono_class_from_mono_type (field->type);
5012 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5014 if (field_class->valuetype) {
5015 res = mono_object_new (domain, field_class);
5016 val = ((gchar *) res) + sizeof (MonoObject);
5020 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5025 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5029 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5030 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5032 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5034 full_name = mono_type_get_full_name (klass);
5035 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5036 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5039 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5041 if (exc) mono_raise_exception ((MonoException *)exc);
5043 if (mono_array_length (out_args) == 0)
5046 res = mono_array_get (out_args, MonoObject *, 0);
5052 * mono_store_remote_field:
5053 * @this: pointer to an object
5054 * @klass: klass of the object containing @field
5055 * @field: the field to load
5056 * @val: the value/object to store
5058 * This method is called by the runtime on attempts to store fields of
5059 * transparent proxy objects. @this points to such TP, @klass is the class of
5060 * the object containing @field. @val is the new value to store in @field.
5063 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5065 static MonoMethod *setter = NULL;
5066 MonoDomain *domain = mono_domain_get ();
5067 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5068 MonoClass *field_class;
5069 MonoMethodMessage *msg;
5070 MonoArray *out_args;
5075 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5077 field_class = mono_class_from_mono_type (field->type);
5079 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5080 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5081 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5086 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5090 if (field_class->valuetype)
5091 arg = mono_value_box (domain, field_class, val);
5093 arg = *((MonoObject **)val);
5096 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5097 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5099 full_name = mono_type_get_full_name (klass);
5100 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5101 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5102 mono_array_setref (msg->args, 2, arg);
5105 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5107 if (exc) mono_raise_exception ((MonoException *)exc);
5111 * mono_store_remote_field_new:
5117 * Missing documentation
5120 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5122 static MonoMethod *setter = NULL;
5123 MonoDomain *domain = mono_domain_get ();
5124 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5125 MonoClass *field_class;
5126 MonoMethodMessage *msg;
5127 MonoArray *out_args;
5131 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5133 field_class = mono_class_from_mono_type (field->type);
5135 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5136 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5137 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5142 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5146 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5147 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5149 full_name = mono_type_get_full_name (klass);
5150 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5151 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5152 mono_array_setref (msg->args, 2, arg);
5155 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5157 if (exc) mono_raise_exception ((MonoException *)exc);
5161 * mono_create_ftnptr:
5163 * Given a function address, create a function descriptor for it.
5164 * This is only needed on IA64 and PPC64.
5167 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5172 mono_domain_lock (domain);
5173 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5174 mono_domain_unlock (domain);
5180 #elif defined(__ppc64__) || defined(__powerpc64__)
5183 mono_domain_lock (domain);
5184 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5185 mono_domain_unlock (domain);
5198 * mono_get_addr_from_ftnptr:
5200 * Given a pointer to a function descriptor, return the function address.
5201 * This is only needed on IA64 and PPC64.
5204 mono_get_addr_from_ftnptr (gpointer descr)
5206 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5207 return *(gpointer*)descr;
5215 * mono_string_chars:
5218 * Returns a pointer to the UCS16 characters stored in the MonoString
5221 mono_string_chars(MonoString *s)
5223 /* This method is here only for documentation extraction, this is a macro */
5227 * mono_string_length:
5230 * Returns the lenght in characters of the string
5233 mono_string_length (MonoString *s)
5235 /* This method is here only for documentation extraction, this is a macro */