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;
78 static gboolean profile_allocs = TRUE;
81 mono_runtime_object_init (MonoObject *this)
83 MonoMethod *method = NULL;
84 MonoClass *klass = this->vtable->klass;
86 method = mono_class_get_method_from_name (klass, ".ctor", 0);
89 if (method->klass->valuetype)
90 this = mono_object_unbox (this);
91 mono_runtime_invoke (method, this, NULL, NULL);
94 /* The pseudo algorithm for type initialization from the spec
95 Note it doesn't say anything about domains - only threads.
97 2. If the type is initialized you are done.
98 2.1. If the type is not yet initialized, try to take an
100 2.2. If successful, record this thread as responsible for
101 initializing the type and proceed to step 2.3.
102 2.2.1. If not, see whether this thread or any thread
103 waiting for this thread to complete already holds the lock.
104 2.2.2. If so, return since blocking would create a deadlock. This thread
105 will now see an incompletely initialized state for the type,
106 but no deadlock will arise.
107 2.2.3 If not, block until the type is initialized then return.
108 2.3 Initialize the parent type and then all interfaces implemented
110 2.4 Execute the type initialization code for this type.
111 2.5 Mark the type as initialized, release the initialization lock,
112 awaken any threads waiting for this type to be initialized,
119 guint32 initializing_tid;
120 guint32 waiting_count;
122 CRITICAL_SECTION initialization_section;
123 } TypeInitializationLock;
125 /* for locking access to type_initialization_hash and blocked_thread_hash */
126 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
127 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
128 static CRITICAL_SECTION type_initialization_section;
130 /* from vtable to lock */
131 static GHashTable *type_initialization_hash;
133 /* from thread id to thread id being waited on */
134 static GHashTable *blocked_thread_hash;
137 static MonoThread *main_thread;
140 * mono_thread_set_main:
141 * @thread: thread to set as the main thread
143 * This function can be used to instruct the runtime to treat @thread
144 * as the main thread, ie, the thread that would normally execute the Main()
145 * method. This basically means that at the end of @thread, the runtime will
146 * wait for the existing foreground threads to quit and other such details.
149 mono_thread_set_main (MonoThread *thread)
151 main_thread = thread;
155 mono_thread_get_main (void)
161 mono_type_initialization_init (void)
163 InitializeCriticalSection (&type_initialization_section);
164 type_initialization_hash = g_hash_table_new (NULL, NULL);
165 blocked_thread_hash = g_hash_table_new (NULL, NULL);
166 InitializeCriticalSection (&ldstr_section);
170 mono_type_initialization_cleanup (void)
173 /* This is causing race conditions with
174 * mono_release_type_locks
176 DeleteCriticalSection (&type_initialization_section);
178 DeleteCriticalSection (&ldstr_section);
182 * get_type_init_exception_for_vtable:
184 * Return the stored type initialization exception for VTABLE.
186 static MonoException*
187 get_type_init_exception_for_vtable (MonoVTable *vtable)
189 MonoDomain *domain = vtable->domain;
190 MonoClass *klass = vtable->klass;
194 g_assert (vtable->init_failed);
197 * If the initializing thread was rudely aborted, the exception is not stored
201 mono_domain_lock (domain);
202 if (domain->type_init_exception_hash)
203 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
204 mono_domain_unlock (domain);
207 if (klass->name_space && *klass->name_space)
208 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
210 full_name = g_strdup (klass->name);
211 ex = mono_get_exception_type_initialization (full_name, NULL);
219 * mono_runtime_class_init:
220 * @vtable: vtable that needs to be initialized
222 * This routine calls the class constructor for @vtable.
225 mono_runtime_class_init (MonoVTable *vtable)
228 MonoException *exc_to_throw;
229 MonoMethod *method = NULL;
235 if (vtable->initialized)
239 klass = vtable->klass;
241 if (!klass->image->checked_module_cctor) {
242 mono_image_check_for_module_cctor (klass->image);
243 if (klass->image->has_module_cctor) {
244 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
245 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
248 method = mono_class_get_cctor (klass);
251 MonoDomain *domain = vtable->domain;
252 TypeInitializationLock *lock;
253 guint32 tid = GetCurrentThreadId();
254 int do_initialization = 0;
255 MonoDomain *last_domain = NULL;
257 mono_type_initialization_lock ();
258 /* double check... */
259 if (vtable->initialized) {
260 mono_type_initialization_unlock ();
263 if (vtable->init_failed) {
264 mono_type_initialization_unlock ();
266 /* The type initialization already failed once, rethrow the same exception */
267 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
270 lock = g_hash_table_lookup (type_initialization_hash, vtable);
272 /* This thread will get to do the initialization */
273 if (mono_domain_get () != domain) {
274 /* Transfer into the target domain */
275 last_domain = mono_domain_get ();
276 if (!mono_domain_set (domain, FALSE)) {
277 vtable->initialized = 1;
278 mono_type_initialization_unlock ();
279 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
282 lock = g_malloc (sizeof(TypeInitializationLock));
283 InitializeCriticalSection (&lock->initialization_section);
284 lock->initializing_tid = tid;
285 lock->waiting_count = 1;
287 /* grab the vtable lock while this thread still owns type_initialization_section */
288 EnterCriticalSection (&lock->initialization_section);
289 g_hash_table_insert (type_initialization_hash, vtable, lock);
290 do_initialization = 1;
293 TypeInitializationLock *pending_lock;
295 if (lock->initializing_tid == tid || lock->done) {
296 mono_type_initialization_unlock ();
299 /* see if the thread doing the initialization is already blocked on this thread */
300 blocked = GUINT_TO_POINTER (lock->initializing_tid);
301 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
302 if (pending_lock->initializing_tid == tid) {
303 if (!pending_lock->done) {
304 mono_type_initialization_unlock ();
307 /* the thread doing the initialization is blocked on this thread,
308 but on a lock that has already been freed. It just hasn't got
313 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
315 ++lock->waiting_count;
316 /* record the fact that we are waiting on the initializing thread */
317 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
319 mono_type_initialization_unlock ();
321 if (do_initialization) {
322 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
324 /* If the initialization failed, mark the class as unusable. */
325 /* Avoid infinite loops */
327 (klass->image == mono_defaults.corlib &&
328 !strcmp (klass->name_space, "System") &&
329 !strcmp (klass->name, "TypeInitializationException")))) {
330 vtable->init_failed = 1;
332 if (klass->name_space && *klass->name_space)
333 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
335 full_name = g_strdup (klass->name);
336 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
340 * Store the exception object so it could be thrown on subsequent
343 mono_domain_lock (domain);
344 if (!domain->type_init_exception_hash)
345 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
346 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
347 mono_domain_unlock (domain);
351 mono_domain_set (last_domain, TRUE);
353 LeaveCriticalSection (&lock->initialization_section);
355 /* this just blocks until the initializing thread is done */
356 EnterCriticalSection (&lock->initialization_section);
357 LeaveCriticalSection (&lock->initialization_section);
360 mono_type_initialization_lock ();
361 if (lock->initializing_tid != tid)
362 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
363 --lock->waiting_count;
364 if (lock->waiting_count == 0) {
365 DeleteCriticalSection (&lock->initialization_section);
366 g_hash_table_remove (type_initialization_hash, vtable);
369 if (!vtable->init_failed)
370 vtable->initialized = 1;
371 mono_type_initialization_unlock ();
373 if (vtable->init_failed) {
374 /* Either we were the initializing thread or we waited for the initialization */
375 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
378 vtable->initialized = 1;
384 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
386 MonoVTable *vtable = (MonoVTable*)key;
388 TypeInitializationLock *lock = (TypeInitializationLock*) value;
389 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
392 * Have to set this since it cannot be set by the normal code in
393 * mono_runtime_class_init (). In this case, the exception object is not stored,
394 * and get_type_init_exception_for_class () needs to be aware of this.
396 vtable->init_failed = 1;
397 LeaveCriticalSection (&lock->initialization_section);
398 --lock->waiting_count;
399 if (lock->waiting_count == 0) {
400 DeleteCriticalSection (&lock->initialization_section);
409 mono_release_type_locks (MonoThread *thread)
411 mono_type_initialization_lock ();
412 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
413 mono_type_initialization_unlock ();
417 default_trampoline (MonoMethod *method)
423 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
425 g_assert_not_reached ();
431 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
433 g_error ("remoting not installed");
438 default_delegate_trampoline (MonoClass *klass)
440 g_assert_not_reached ();
444 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
445 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
446 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
447 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
448 static MonoImtThunkBuilder imt_thunk_builder = NULL;
449 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
450 #if (MONO_IMT_SIZE > 32)
451 #error "MONO_IMT_SIZE cannot be larger than 32"
455 mono_install_trampoline (MonoTrampoline func)
457 arch_create_jit_trampoline = func? func: default_trampoline;
461 mono_install_jump_trampoline (MonoJumpTrampoline func)
463 arch_create_jump_trampoline = func? func: default_jump_trampoline;
467 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
469 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
473 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
475 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
479 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
480 imt_thunk_builder = func;
483 static MonoCompileFunc default_mono_compile_method = NULL;
486 * mono_install_compile_method:
487 * @func: function to install
489 * This is a VM internal routine
492 mono_install_compile_method (MonoCompileFunc func)
494 default_mono_compile_method = func;
498 * mono_compile_method:
499 * @method: The method to compile.
501 * This JIT-compiles the method, and returns the pointer to the native code
505 mono_compile_method (MonoMethod *method)
507 if (!default_mono_compile_method) {
508 g_error ("compile method called on uninitialized runtime");
511 return default_mono_compile_method (method);
515 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
517 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
521 mono_runtime_create_delegate_trampoline (MonoClass *klass)
523 return arch_create_delegate_trampoline (klass);
526 static MonoFreeMethodFunc default_mono_free_method = NULL;
529 * mono_install_free_method:
530 * @func: pointer to the MonoFreeMethodFunc used to release a method
532 * This is an internal VM routine, it is used for the engines to
533 * register a handler to release the resources associated with a method.
535 * Methods are freed when no more references to the delegate that holds
539 mono_install_free_method (MonoFreeMethodFunc func)
541 default_mono_free_method = func;
545 * mono_runtime_free_method:
546 * @domain; domain where the method is hosted
547 * @method: method to release
549 * This routine is invoked to free the resources associated with
550 * a method that has been JIT compiled. This is used to discard
551 * methods that were used only temporarily (for example, used in marshalling)
555 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
557 if (default_mono_free_method != NULL)
558 default_mono_free_method (domain, method);
560 mono_free_method (method);
564 * The vtables in the root appdomain are assumed to be reachable by other
565 * roots, and we don't use typed allocation in the other domains.
568 /* The sync block is no longer a GC pointer */
569 #define GC_HEADER_BITMAP (0)
571 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
574 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
576 MonoClassField *field;
582 max_size = mono_class_data_size (class) / sizeof (gpointer);
584 max_size = class->instance_size / sizeof (gpointer);
585 if (max_size >= size) {
586 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
589 for (p = class; p != NULL; p = p->parent) {
590 gpointer iter = NULL;
591 while ((field = mono_class_get_fields (p, &iter))) {
595 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
597 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
600 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
603 /* FIXME: should not happen, flag as type load error */
604 if (field->type->byref)
607 pos = field->offset / sizeof (gpointer);
610 type = mono_type_get_underlying_type (field->type);
611 switch (type->type) {
614 case MONO_TYPE_FNPTR:
616 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
621 if (class->image != mono_defaults.corlib)
624 case MONO_TYPE_STRING:
625 case MONO_TYPE_SZARRAY:
626 case MONO_TYPE_CLASS:
627 case MONO_TYPE_OBJECT:
628 case MONO_TYPE_ARRAY:
629 g_assert ((field->offset % sizeof(gpointer)) == 0);
631 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
632 *max_set = MAX (*max_set, pos);
634 case MONO_TYPE_GENERICINST:
635 if (!mono_type_generic_inst_is_valuetype (type)) {
636 g_assert ((field->offset % sizeof(gpointer)) == 0);
638 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
639 *max_set = MAX (*max_set, pos);
644 case MONO_TYPE_VALUETYPE: {
645 MonoClass *fclass = mono_class_from_mono_type (field->type);
646 if (fclass->has_references) {
647 /* remove the object header */
648 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
662 case MONO_TYPE_BOOLEAN:
666 g_assert_not_reached ();
678 * similar to the above, but sets the bits in the bitmap for any non-ref field
679 * and ignores static fields
682 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
684 MonoClassField *field;
689 max_size = class->instance_size / sizeof (gpointer);
690 if (max_size >= size) {
691 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
694 for (p = class; p != NULL; p = p->parent) {
695 gpointer iter = NULL;
696 while ((field = mono_class_get_fields (p, &iter))) {
699 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
701 /* FIXME: should not happen, flag as type load error */
702 if (field->type->byref)
705 pos = field->offset / sizeof (gpointer);
708 type = mono_type_get_underlying_type (field->type);
709 switch (type->type) {
710 #if SIZEOF_VOID_P == 8
714 case MONO_TYPE_FNPTR:
719 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
720 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
721 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
724 #if SIZEOF_VOID_P == 4
728 case MONO_TYPE_FNPTR:
733 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
734 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
735 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
741 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
742 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
743 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
746 case MONO_TYPE_BOOLEAN:
749 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
751 case MONO_TYPE_STRING:
752 case MONO_TYPE_SZARRAY:
753 case MONO_TYPE_CLASS:
754 case MONO_TYPE_OBJECT:
755 case MONO_TYPE_ARRAY:
757 case MONO_TYPE_GENERICINST:
758 if (!mono_type_generic_inst_is_valuetype (type)) {
763 case MONO_TYPE_VALUETYPE: {
764 MonoClass *fclass = mono_class_from_mono_type (field->type);
765 /* remove the object header */
766 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
770 g_assert_not_reached ();
779 * mono_class_insecure_overlapping:
780 * check if a class with explicit layout has references and non-references
781 * fields overlapping.
783 * Returns: TRUE if it is insecure to load the type.
786 mono_class_insecure_overlapping (MonoClass *klass)
790 gsize default_bitmap [4] = {0};
792 gsize default_nrbitmap [4] = {0};
793 int i, insecure = FALSE;
796 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
797 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
799 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
800 int idx = i % (sizeof (bitmap [0]) * 8);
801 if (bitmap [idx] & nrbitmap [idx]) {
806 if (bitmap != default_bitmap)
808 if (nrbitmap != default_nrbitmap)
811 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
819 mono_string_alloc (int length)
821 return mono_string_new_size (mono_domain_get (), length);
825 mono_class_compute_gc_descriptor (MonoClass *class)
829 gsize default_bitmap [4] = {0};
830 static gboolean gcj_inited = FALSE;
835 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
836 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
837 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
838 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
840 #ifdef HAVE_GC_GCJ_MALLOC
842 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
846 #ifdef GC_REDIRECT_TO_LOCAL
847 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
848 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
850 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
851 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
856 mono_loader_unlock ();
860 mono_class_init (class);
862 if (class->gc_descr_inited)
865 class->gc_descr_inited = TRUE;
866 class->gc_descr = GC_NO_DESCRIPTOR;
868 bitmap = default_bitmap;
869 if (class == mono_defaults.string_class) {
870 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
871 } else if (class->rank) {
872 mono_class_compute_gc_descriptor (class->element_class);
873 if (!class->element_class->valuetype) {
875 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
876 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
877 class->name_space, class->name);*/
879 /* remove the object header */
880 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
881 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
882 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
883 class->name_space, class->name);*/
884 if (bitmap != default_bitmap)
888 /*static int count = 0;
891 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
892 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
894 if (class->gc_descr == GC_NO_DESCRIPTOR)
895 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
897 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
898 if (bitmap != default_bitmap)
904 * field_is_special_static:
905 * @fklass: The MonoClass to look up.
906 * @field: The MonoClassField describing the field.
908 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
909 * SPECIAL_STATIC_NONE otherwise.
912 field_is_special_static (MonoClass *fklass, MonoClassField *field)
914 MonoCustomAttrInfo *ainfo;
916 ainfo = mono_custom_attrs_from_field (fklass, field);
919 for (i = 0; i < ainfo->num_attrs; ++i) {
920 MonoClass *klass = ainfo->attrs [i].ctor->klass;
921 if (klass->image == mono_defaults.corlib) {
922 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
923 mono_custom_attrs_free (ainfo);
924 return SPECIAL_STATIC_THREAD;
926 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
927 mono_custom_attrs_free (ainfo);
928 return SPECIAL_STATIC_CONTEXT;
932 mono_custom_attrs_free (ainfo);
933 return SPECIAL_STATIC_NONE;
936 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
937 #define mix(a,b,c) { \
938 a -= c; a ^= rot(c, 4); c += b; \
939 b -= a; b ^= rot(a, 6); a += c; \
940 c -= b; c ^= rot(b, 8); b += a; \
941 a -= c; a ^= rot(c,16); c += b; \
942 b -= a; b ^= rot(a,19); a += c; \
943 c -= b; c ^= rot(b, 4); b += a; \
945 #define final(a,b,c) { \
946 c ^= b; c -= rot(b,14); \
947 a ^= c; a -= rot(c,11); \
948 b ^= a; b -= rot(a,25); \
949 c ^= b; c -= rot(b,16); \
950 a ^= c; a -= rot(c,4); \
951 b ^= a; b -= rot(a,14); \
952 c ^= b; c -= rot(b,24); \
956 mono_method_get_imt_slot (MonoMethod *method) {
957 MonoMethodSignature *sig;
959 guint32 *hashes_start, *hashes;
964 * We do this to simplify generic sharing. It will hurt
965 * performance in cases where a class implements two different
966 * instantiations of the same generic interface.
968 if (method->is_inflated)
969 method = ((MonoMethodInflated*)method)->declaring;
971 sig = mono_method_signature (method);
972 hashes_count = sig->param_count + 4;
973 hashes_start = malloc (hashes_count * sizeof (guint32));
974 hashes = hashes_start;
976 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
977 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
978 method->klass->name_space, method->klass->name, method->name);
979 g_assert_not_reached ();
982 /* Initialize hashes */
983 hashes [0] = g_str_hash (method->klass->name);
984 hashes [1] = g_str_hash (method->klass->name_space);
985 hashes [2] = g_str_hash (method->name);
986 hashes [3] = mono_metadata_type_hash (sig->ret);
987 for (i = 0; i < sig->param_count; i++) {
988 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
991 /* Setup internal state */
992 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
994 /* Handle most of the hashes */
995 while (hashes_count > 3) {
1004 /* Handle the last 3 hashes (all the case statements fall through) */
1005 switch (hashes_count) {
1006 case 3 : c += hashes [2];
1007 case 2 : b += hashes [1];
1008 case 1 : a += hashes [0];
1010 case 0: /* nothing left to add */
1014 free (hashes_start);
1015 /* Report the result */
1016 return c % MONO_IMT_SIZE;
1025 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1026 guint32 imt_slot = mono_method_get_imt_slot (method);
1027 MonoImtBuilderEntry *entry;
1029 if (slot_num >= 0 && imt_slot != slot_num) {
1030 /* we build just a single imt slot and this is not it */
1034 entry = malloc (sizeof (MonoImtBuilderEntry));
1035 entry->method = method;
1036 entry->vtable_slot = vtable_slot;
1037 entry->next = imt_builder [imt_slot];
1038 if (imt_builder [imt_slot] != NULL) {
1039 entry->children = imt_builder [imt_slot]->children + 1;
1040 if (entry->children == 1) {
1041 mono_stats.imt_slots_with_collisions++;
1042 *imt_collisions_bitmap |= (1 << imt_slot);
1045 entry->children = 0;
1046 mono_stats.imt_used_slots++;
1048 imt_builder [imt_slot] = entry;
1050 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1051 method, method->klass->name_space, method->klass->name,
1052 method->name, imt_slot, vtable_slot, entry->children);
1058 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1060 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1064 e->method->klass->name_space,
1065 e->method->klass->name,
1068 printf (" * %s: NULL\n", message);
1074 compare_imt_builder_entries (const void *p1, const void *p2) {
1075 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1076 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1078 return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
1082 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1084 int count = end - start;
1085 int chunk_start = out_array->len;
1088 for (i = start; i < end; ++i) {
1089 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1090 item->method = sorted_array [i]->method;
1091 item->vtable_slot = sorted_array [i]->vtable_slot;
1092 item->is_equals = TRUE;
1094 item->check_target_idx = out_array->len + 1;
1096 item->check_target_idx = 0;
1097 g_ptr_array_add (out_array, item);
1100 int middle = start + count / 2;
1101 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1103 item->method = sorted_array [middle]->method;
1104 item->is_equals = FALSE;
1105 g_ptr_array_add (out_array, item);
1106 imt_emit_ir (sorted_array, start, middle, out_array);
1107 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1113 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1114 int number_of_entries = entries->children + 1;
1115 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1116 GPtrArray *result = g_ptr_array_new ();
1117 MonoImtBuilderEntry *current_entry;
1120 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1121 sorted_array [i] = current_entry;
1123 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1125 /*for (i = 0; i < number_of_entries; i++) {
1126 print_imt_entry (" sorted array:", sorted_array [i], i);
1129 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1131 free (sorted_array);
1136 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1137 if (imt_builder_entry != NULL) {
1138 if (imt_builder_entry->children == 0) {
1139 /* No collision, return the vtable slot contents */
1140 return vtable->vtable [imt_builder_entry->vtable_slot];
1142 /* Collision, build the thunk */
1143 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1146 result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
1147 for (i = 0; i < imt_ir->len; ++i)
1148 g_free (g_ptr_array_index (imt_ir, i));
1149 g_ptr_array_free (imt_ir, TRUE);
1159 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1162 guint32 imt_collisions_bitmap = 0;
1163 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1164 int method_count = 0;
1165 gboolean record_method_count_for_max_collisions = FALSE;
1168 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1170 for (i = 0; i < klass->interface_offsets_count; ++i) {
1171 MonoClass *iface = klass->interfaces_packed [i];
1172 int interface_offset = klass->interface_offsets_packed [i];
1173 int method_slot_in_interface;
1174 mono_class_setup_methods (iface);
1175 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1176 MonoMethod *method = iface->methods [method_slot_in_interface];
1177 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1180 if (extra_interfaces) {
1181 int interface_offset = klass->vtable_size;
1183 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1184 MonoClass* iface = list_item->data;
1185 int method_slot_in_interface;
1186 mono_class_setup_methods (iface);
1187 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1188 MonoMethod *method = iface->methods [method_slot_in_interface];
1189 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1191 interface_offset += iface->method.count;
1194 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1195 /* overwrite the imt slot only if we're building all the entries or if
1196 * we're uilding this specific one
1198 if (slot_num < 0 || i == slot_num)
1199 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1201 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1203 if (imt_builder [i] != NULL) {
1204 int methods_in_slot = imt_builder [i]->children + 1;
1205 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1206 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1207 record_method_count_for_max_collisions = TRUE;
1209 method_count += methods_in_slot;
1213 mono_stats.imt_number_of_methods += method_count;
1214 if (record_method_count_for_max_collisions) {
1215 mono_stats.imt_method_count_when_max_collisions = method_count;
1218 for (i = 0; i < MONO_IMT_SIZE; i++) {
1219 MonoImtBuilderEntry* entry = imt_builder [i];
1220 while (entry != NULL) {
1221 MonoImtBuilderEntry* next = entry->next;
1227 /* we OR the bitmap since we may build just a single imt slot at a time */
1228 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1232 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1233 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1236 static gpointer imt_trampoline = NULL;
1239 mono_install_imt_trampoline (gpointer tramp_code)
1241 imt_trampoline = tramp_code;
1244 static gpointer vtable_trampoline = NULL;
1247 mono_install_vtable_trampoline (gpointer tramp_code)
1249 vtable_trampoline = tramp_code;
1253 * mono_vtable_build_imt_slot:
1254 * @vtable: virtual object table struct
1255 * @imt_slot: slot in the IMT table
1257 * Fill the given @imt_slot in the IMT table of @vtable with
1258 * a trampoline or a thunk for the case of collisions.
1259 * This is part of the internal mono API.
1262 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1264 gpointer *imt = (gpointer*)vtable;
1265 imt -= MONO_IMT_SIZE;
1266 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1268 /* no support for extra interfaces: the proxy objects will need
1269 * to build the complete IMT
1270 * Update and heck needs to ahppen inside the proper domain lock, as all
1271 * the changes made to a MonoVTable.
1273 mono_domain_lock (vtable->domain);
1274 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1275 if (imt [imt_slot] == imt_trampoline)
1276 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1277 mono_domain_unlock (vtable->domain);
1280 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1283 * mono_class_vtable:
1284 * @domain: the application domain
1285 * @class: the class to initialize
1287 * VTables are domain specific because we create domain specific code, and
1288 * they contain the domain specific static class data.
1289 * On failure, NULL is returned, and class->exception_type is set.
1292 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1294 MonoClassRuntimeInfo *runtime_info;
1298 /* this check can be inlined in jitted code, too */
1299 runtime_info = class->runtime_info;
1300 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1301 return runtime_info->domain_vtables [domain->domain_id];
1302 return mono_class_create_runtime_vtable (domain, class);
1306 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1309 MonoClassRuntimeInfo *runtime_info, *old_info;
1310 MonoClassField *field;
1313 int imt_table_bytes = 0;
1314 guint32 vtable_size, class_size;
1316 guint32 constant_cols [MONO_CONSTANT_SIZE];
1318 gpointer *interface_offsets;
1320 mono_domain_lock (domain);
1321 runtime_info = class->runtime_info;
1322 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1323 mono_domain_unlock (domain);
1324 return runtime_info->domain_vtables [domain->domain_id];
1326 if (!class->inited || class->exception_type) {
1327 if (!mono_class_init (class) || class->exception_type){
1329 mono_domain_unlock (domain);
1330 exc = mono_class_get_exception_for_failure (class);
1332 mono_raise_exception (exc);
1336 mono_class_init (class);
1339 * For some classes, mono_class_init () already computed class->vtable_size, and
1340 * that is all that is needed because of the vtable trampolines.
1342 if (!class->vtable_size)
1343 mono_class_setup_vtable (class);
1345 if (class->exception_type) {
1346 mono_domain_unlock (domain);
1351 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1352 if (class->interface_offsets_count) {
1353 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1354 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1355 mono_stats.imt_number_of_tables++;
1356 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1359 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1360 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1363 mono_stats.used_class_count++;
1364 mono_stats.class_vtable_size += vtable_size;
1365 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1368 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1370 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1372 vt->rank = class->rank;
1373 vt->domain = domain;
1375 mono_class_compute_gc_descriptor (class);
1377 * We can't use typed allocation in the non-root domains, since the
1378 * collector needs the GC descriptor stored in the vtable even after
1379 * the mempool containing the vtable is destroyed when the domain is
1380 * unloaded. An alternative might be to allocate vtables in the GC
1381 * heap, but this does not seem to work (it leads to crashes inside
1382 * libgc). If that approach is tried, two gc descriptors need to be
1383 * allocated for each class: one for the root domain, and one for all
1384 * other domains. The second descriptor should contain a bit for the
1385 * vtable field in MonoObject, since we can no longer assume the
1386 * vtable is reachable by other roots after the appdomain is unloaded.
1388 #ifdef HAVE_BOEHM_GC
1389 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1390 vt->gc_descr = GC_NO_DESCRIPTOR;
1393 vt->gc_descr = class->gc_descr;
1395 if ((class_size = mono_class_data_size (class))) {
1396 if (class->has_static_refs) {
1397 gpointer statics_gc_descr;
1399 gsize default_bitmap [4] = {0};
1402 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1403 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1404 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1405 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1406 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1407 if (bitmap != default_bitmap)
1410 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1412 mono_stats.class_static_data_size += class_size;
1417 while ((field = mono_class_get_fields (class, &iter))) {
1418 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1420 if (mono_field_is_deleted (field))
1422 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1423 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1424 if (special_static != SPECIAL_STATIC_NONE) {
1425 guint32 size, offset;
1427 size = mono_type_size (field->type, &align);
1428 offset = mono_alloc_special_static_data (special_static, size, align);
1429 if (!domain->special_static_fields)
1430 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1431 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1435 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1436 MonoClass *fklass = mono_class_from_mono_type (field->type);
1437 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1438 t = (char*)vt->data + field->offset;
1439 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1442 if (fklass->valuetype) {
1443 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1445 /* it's a pointer type: add check */
1446 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1447 *t = *(char *)field->data;
1451 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1454 /* later do this only on demand if needed */
1456 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1458 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1460 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1461 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1462 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1467 vt->max_interface_id = class->max_interface_id;
1468 vt->interface_bitmap = class->interface_bitmap;
1470 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1471 // class->name, class->interface_offsets_count);
1473 if (! ARCH_USE_IMT) {
1474 /* initialize interface offsets */
1475 for (i = 0; i < class->interface_offsets_count; ++i) {
1476 int interface_id = class->interfaces_packed [i]->interface_id;
1477 int slot = class->interface_offsets_packed [i];
1478 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1482 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1483 * as we change the code in appdomain.c to invalidate vtables by
1484 * looking at the possible MonoClasses created for the domain.
1486 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1487 /* class->runtime_info is protected by the loader lock, both when
1488 * it it enlarged and when it is stored info.
1490 mono_loader_lock ();
1491 old_info = class->runtime_info;
1492 if (old_info && old_info->max_domain >= domain->domain_id) {
1493 /* someone already created a large enough runtime info */
1494 mono_memory_barrier ();
1495 old_info->domain_vtables [domain->domain_id] = vt;
1497 int new_size = domain->domain_id;
1499 new_size = MAX (new_size, old_info->max_domain);
1501 /* make the new size a power of two */
1503 while (new_size > i)
1506 /* this is a bounded memory retention issue: may want to
1507 * handle it differently when we'll have a rcu-like system.
1509 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1510 runtime_info->max_domain = new_size - 1;
1511 /* copy the stuff from the older info */
1513 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1515 runtime_info->domain_vtables [domain->domain_id] = vt;
1517 mono_memory_barrier ();
1518 class->runtime_info = runtime_info;
1520 mono_loader_unlock ();
1522 /* Initialize vtable */
1523 if (vtable_trampoline) {
1524 // This also covers the AOT case
1525 for (i = 0; i < class->vtable_size; ++i) {
1526 vt->vtable [i] = vtable_trampoline;
1529 mono_class_setup_vtable (class);
1531 for (i = 0; i < class->vtable_size; ++i) {
1534 if ((cm = class->vtable [i])) {
1535 if (mono_method_signature (cm)->generic_param_count)
1536 /* FIXME: Why is this needed ? */
1537 vt->vtable [i] = cm;
1539 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1544 if (ARCH_USE_IMT && imt_table_bytes) {
1545 /* Now that the vtable is full, we can actually fill up the IMT */
1546 if (imt_trampoline) {
1547 /* lazy construction of the IMT entries enabled */
1548 for (i = 0; i < MONO_IMT_SIZE; ++i)
1549 interface_offsets [i] = imt_trampoline;
1551 build_imt (class, vt, domain, interface_offsets, NULL);
1555 mono_domain_unlock (domain);
1557 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1558 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1559 MonoException *exc = mono_class_get_exception_for_failure (class);
1561 mono_raise_exception (exc);
1564 /* make sure the parent is initialized */
1566 mono_class_vtable (domain, class->parent);
1568 vt->type = mono_type_get_object (domain, &class->byval_arg);
1569 if (class->contextbound)
1578 * mono_class_proxy_vtable:
1579 * @domain: the application domain
1580 * @remove_class: the remote class
1582 * Creates a vtable for transparent proxies. It is basically
1583 * a copy of the real vtable of the class wrapped in @remote_class,
1584 * but all function pointers invoke the remoting functions, and
1585 * vtable->klass points to the transparent proxy class, and not to @class.
1588 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1590 MonoVTable *vt, *pvt;
1591 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1593 GSList *extra_interfaces = NULL;
1594 MonoClass *class = remote_class->proxy_class;
1595 gpointer *interface_offsets;
1597 vt = mono_class_vtable (domain, class);
1598 max_interface_id = vt->max_interface_id;
1600 /* Calculate vtable space for extra interfaces */
1601 for (j = 0; j < remote_class->interface_count; j++) {
1602 MonoClass* iclass = remote_class->interfaces[j];
1606 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1607 continue; /* interface implemented by the class */
1608 if (g_slist_find (extra_interfaces, iclass))
1611 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1613 method_count = mono_class_num_methods (iclass);
1615 ifaces = mono_class_get_implemented_interfaces (iclass);
1617 for (i = 0; i < ifaces->len; ++i) {
1618 MonoClass *ic = g_ptr_array_index (ifaces, i);
1619 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1620 continue; /* interface implemented by the class */
1621 if (g_slist_find (extra_interfaces, ic))
1623 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1624 method_count += mono_class_num_methods (ic);
1626 g_ptr_array_free (ifaces, TRUE);
1629 extra_interface_vtsize += method_count * sizeof (gpointer);
1630 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1634 mono_stats.imt_number_of_tables++;
1635 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1636 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1637 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1639 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1640 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1643 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1645 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1647 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1649 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1650 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1652 pvt->klass = mono_defaults.transparent_proxy_class;
1653 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1654 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1656 /* initialize vtable */
1657 mono_class_setup_vtable (class);
1658 for (i = 0; i < class->vtable_size; ++i) {
1661 if ((cm = class->vtable [i]))
1662 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1663 ? cm : arch_create_remoting_trampoline (cm, target_type);
1665 pvt->vtable [i] = NULL;
1668 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1669 /* create trampolines for abstract methods */
1670 for (k = class; k; k = k->parent) {
1672 gpointer iter = NULL;
1673 while ((m = mono_class_get_methods (k, &iter)))
1674 if (!pvt->vtable [m->slot])
1675 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1679 pvt->max_interface_id = max_interface_id;
1680 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1682 if (! ARCH_USE_IMT) {
1683 /* initialize interface offsets */
1684 for (i = 0; i < class->interface_offsets_count; ++i) {
1685 int interface_id = class->interfaces_packed [i]->interface_id;
1686 int slot = class->interface_offsets_packed [i];
1687 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1690 for (i = 0; i < class->interface_offsets_count; ++i) {
1691 int interface_id = class->interfaces_packed [i]->interface_id;
1692 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1695 if (extra_interfaces) {
1696 int slot = class->vtable_size;
1702 /* Create trampolines for the methods of the interfaces */
1703 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1704 interf = list_item->data;
1706 if (! ARCH_USE_IMT) {
1707 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1709 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1713 while ((cm = mono_class_get_methods (interf, &iter)))
1714 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1716 slot += mono_class_num_methods (interf);
1718 if (! ARCH_USE_IMT) {
1719 g_slist_free (extra_interfaces);
1724 /* Now that the vtable is full, we can actually fill up the IMT */
1725 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1726 if (extra_interfaces) {
1727 g_slist_free (extra_interfaces);
1735 * mono_class_field_is_special_static:
1737 * Returns whether @field is a thread/context static field.
1740 mono_class_field_is_special_static (MonoClassField *field)
1742 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1744 if (mono_field_is_deleted (field))
1746 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1747 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
1754 * mono_class_has_special_static_fields:
1756 * Returns whenever @klass has any thread/context static fields.
1759 mono_class_has_special_static_fields (MonoClass *klass)
1761 MonoClassField *field;
1765 while ((field = mono_class_get_fields (klass, &iter))) {
1766 g_assert (field->parent == klass);
1767 if (mono_class_field_is_special_static (field))
1775 * create_remote_class_key:
1776 * Creates an array of pointers that can be used as a hash key for a remote class.
1777 * The first element of the array is the number of pointers.
1780 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1785 if (remote_class == NULL) {
1786 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1787 key = g_malloc (sizeof(gpointer) * 3);
1788 key [0] = GINT_TO_POINTER (2);
1789 key [1] = mono_defaults.marshalbyrefobject_class;
1790 key [2] = extra_class;
1792 key = g_malloc (sizeof(gpointer) * 2);
1793 key [0] = GINT_TO_POINTER (1);
1794 key [1] = extra_class;
1797 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1798 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1799 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1800 key [1] = remote_class->proxy_class;
1802 // Keep the list of interfaces sorted
1803 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1804 if (extra_class && remote_class->interfaces [i] > extra_class) {
1805 key [j++] = extra_class;
1808 key [j] = remote_class->interfaces [i];
1811 key [j] = extra_class;
1813 // Replace the old class. The interface list is the same
1814 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1815 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1816 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1817 for (i = 0; i < remote_class->interface_count; i++)
1818 key [2 + i] = remote_class->interfaces [i];
1826 * copy_remote_class_key:
1828 * Make a copy of KEY in the mempool MP and return the copy.
1831 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1833 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1834 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1836 memcpy (mp_key, key, key_size);
1842 * mono_remote_class:
1843 * @domain: the application domain
1844 * @class_name: name of the remote class
1846 * Creates and initializes a MonoRemoteClass object for a remote type.
1850 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1852 MonoRemoteClass *rc;
1853 gpointer* key, *mp_key;
1855 key = create_remote_class_key (NULL, proxy_class);
1857 mono_domain_lock (domain);
1858 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1862 mono_domain_unlock (domain);
1866 mp_key = copy_remote_class_key (domain->mp, key);
1870 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1871 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1872 rc->interface_count = 1;
1873 rc->interfaces [0] = proxy_class;
1874 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1876 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1877 rc->interface_count = 0;
1878 rc->proxy_class = proxy_class;
1881 rc->default_vtable = NULL;
1882 rc->xdomain_vtable = NULL;
1883 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1885 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1887 mono_domain_unlock (domain);
1892 * clone_remote_class:
1893 * Creates a copy of the remote_class, adding the provided class or interface
1895 static MonoRemoteClass*
1896 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1898 MonoRemoteClass *rc;
1899 gpointer* key, *mp_key;
1901 key = create_remote_class_key (remote_class, extra_class);
1902 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1908 mp_key = copy_remote_class_key (domain->mp, key);
1912 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1914 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1915 rc->proxy_class = remote_class->proxy_class;
1916 rc->interface_count = remote_class->interface_count + 1;
1918 // Keep the list of interfaces sorted, since the hash key of
1919 // the remote class depends on this
1920 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1921 if (remote_class->interfaces [i] > extra_class && i == j)
1922 rc->interfaces [j++] = extra_class;
1923 rc->interfaces [j] = remote_class->interfaces [i];
1926 rc->interfaces [j] = extra_class;
1928 // Replace the old class. The interface array is the same
1929 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1930 rc->proxy_class = extra_class;
1931 rc->interface_count = remote_class->interface_count;
1932 if (rc->interface_count > 0)
1933 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1936 rc->default_vtable = NULL;
1937 rc->xdomain_vtable = NULL;
1938 rc->proxy_class_name = remote_class->proxy_class_name;
1940 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1946 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1948 mono_domain_lock (domain);
1949 if (rp->target_domain_id != -1) {
1950 if (remote_class->xdomain_vtable == NULL)
1951 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1952 mono_domain_unlock (domain);
1953 return remote_class->xdomain_vtable;
1955 if (remote_class->default_vtable == NULL) {
1958 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1959 klass = mono_class_from_mono_type (type);
1960 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1961 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1963 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1966 mono_domain_unlock (domain);
1967 return remote_class->default_vtable;
1971 * mono_upgrade_remote_class:
1972 * @domain: the application domain
1973 * @tproxy: the proxy whose remote class has to be upgraded.
1974 * @klass: class to which the remote class can be casted.
1976 * Updates the vtable of the remote class by adding the necessary method slots
1977 * and interface offsets so it can be safely casted to klass. klass can be a
1978 * class or an interface.
1981 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1983 MonoTransparentProxy *tproxy;
1984 MonoRemoteClass *remote_class;
1985 gboolean redo_vtable;
1987 mono_domain_lock (domain);
1989 tproxy = (MonoTransparentProxy*) proxy_object;
1990 remote_class = tproxy->remote_class;
1992 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1995 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1996 if (remote_class->interfaces [i] == klass)
1997 redo_vtable = FALSE;
2000 redo_vtable = (remote_class->proxy_class != klass);
2004 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2005 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2008 mono_domain_unlock (domain);
2013 * mono_object_get_virtual_method:
2014 * @obj: object to operate on.
2017 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2018 * the instance of a callvirt of method.
2021 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2024 MonoMethod **vtable;
2026 MonoMethod *res = NULL;
2028 klass = mono_object_class (obj);
2029 if (klass == mono_defaults.transparent_proxy_class) {
2030 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2036 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2039 mono_class_setup_vtable (klass);
2040 vtable = klass->vtable;
2042 /* check method->slot is a valid index: perform isinstance? */
2043 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2045 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2047 if (method->slot != -1) {
2048 res = vtable [method->slot];
2050 /* method->slot might not be set for instances of generic methods in the AOT case */
2051 if (method->is_inflated) {
2052 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2053 res = vtable [((MonoMethodInflated*)method)->declaring->slot];
2059 /* It may be an interface, abstract class method or generic method */
2060 if (!res || mono_method_signature (res)->generic_param_count)
2063 /* generic methods demand invoke_with_check */
2064 if (mono_method_signature (res)->generic_param_count)
2065 res = mono_marshal_get_remoting_invoke_with_check (res);
2067 res = mono_marshal_get_remoting_invoke (res);
2069 if (method->is_inflated && !res->is_inflated) {
2070 /* Have to inflate the result */
2071 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2081 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2083 g_error ("runtime invoke called on uninitialized runtime");
2087 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2090 * mono_runtime_invoke:
2091 * @method: method to invoke
2092 * @obJ: object instance
2093 * @params: arguments to the method
2094 * @exc: exception information.
2096 * Invokes the method represented by @method on the object @obj.
2098 * obj is the 'this' pointer, it should be NULL for static
2099 * methods, a MonoObject* for object instances and a pointer to
2100 * the value type for value types.
2102 * The params array contains the arguments to the method with the
2103 * same convention: MonoObject* pointers for object instances and
2104 * pointers to the value type otherwise.
2106 * From unmanaged code you'll usually use the
2107 * mono_runtime_invoke() variant.
2109 * Note that this function doesn't handle virtual methods for
2110 * you, it will exec the exact method you pass: we still need to
2111 * expose a function to lookup the derived class implementation
2112 * of a virtual method (there are examples of this in the code,
2115 * You can pass NULL as the exc argument if you don't want to
2116 * catch exceptions, otherwise, *exc will be set to the exception
2117 * thrown, if any. if an exception is thrown, you can't use the
2118 * MonoObject* result from the function.
2120 * If the method returns a value type, it is boxed in an object
2124 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2126 return default_mono_runtime_invoke (method, obj, params, exc);
2130 * mono_method_get_unmanaged_thunk:
2131 * @method: method to generate a thunk for.
2133 * Returns an unmanaged->managed thunk that can be used to call
2134 * a managed method directly from C.
2136 * The thunk's C signature closely matches the managed signature:
2138 * C#: public bool Equals (object obj);
2139 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2140 * MonoObject*, MonoException**);
2142 * The 1st ("this") parameter must not be used with static methods:
2144 * C#: public static bool ReferenceEquals (object a, object b);
2145 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2148 * The last argument must be a non-null pointer of a MonoException* pointer.
2149 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2150 * exception has been thrown in managed code. Otherwise it will point
2151 * to the MonoException* caught by the thunk. In this case, the result of
2152 * the thunk is undefined:
2154 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2155 * MonoException *ex = NULL;
2156 * Equals func = mono_method_get_unmanaged_thunk (method);
2157 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2159 * // handle exception
2162 * The calling convention of the thunk matches the platform's default
2163 * convention. This means that under Windows, C declarations must
2164 * contain the __stdcall attribute:
2166 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2167 * MonoObject*, MonoException**);
2171 * Value type arguments and return values are treated as they were objects:
2173 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2174 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2176 * Arguments must be properly boxed upon trunk's invocation, while return
2177 * values must be unboxed.
2180 mono_method_get_unmanaged_thunk (MonoMethod *method)
2182 method = mono_marshal_get_thunk_invoke_wrapper (method);
2183 return mono_compile_method (method);
2187 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2191 gpointer *p = (gpointer*)dest;
2198 case MONO_TYPE_BOOLEAN:
2200 case MONO_TYPE_U1: {
2201 guint8 *p = (guint8*)dest;
2202 *p = value ? *(guint8*)value : 0;
2207 case MONO_TYPE_CHAR: {
2208 guint16 *p = (guint16*)dest;
2209 *p = value ? *(guint16*)value : 0;
2212 #if SIZEOF_VOID_P == 4
2217 case MONO_TYPE_U4: {
2218 gint32 *p = (gint32*)dest;
2219 *p = value ? *(gint32*)value : 0;
2222 #if SIZEOF_VOID_P == 8
2227 case MONO_TYPE_U8: {
2228 gint64 *p = (gint64*)dest;
2229 *p = value ? *(gint64*)value : 0;
2232 case MONO_TYPE_R4: {
2233 float *p = (float*)dest;
2234 *p = value ? *(float*)value : 0;
2237 case MONO_TYPE_R8: {
2238 double *p = (double*)dest;
2239 *p = value ? *(double*)value : 0;
2242 case MONO_TYPE_STRING:
2243 case MONO_TYPE_SZARRAY:
2244 case MONO_TYPE_CLASS:
2245 case MONO_TYPE_OBJECT:
2246 case MONO_TYPE_ARRAY:
2247 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2249 case MONO_TYPE_FNPTR:
2250 case MONO_TYPE_PTR: {
2251 gpointer *p = (gpointer*)dest;
2252 *p = deref_pointer? *(gpointer*)value: value;
2255 case MONO_TYPE_VALUETYPE:
2256 /* note that 't' and 'type->type' can be different */
2257 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2258 t = type->data.klass->enum_basetype->type;
2262 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2264 memset (dest, 0, size);
2266 memcpy (dest, value, size);
2269 case MONO_TYPE_GENERICINST:
2270 t = type->data.generic_class->container_class->byval_arg.type;
2273 g_warning ("got type %x", type->type);
2274 g_assert_not_reached ();
2279 * mono_field_set_value:
2280 * @obj: Instance object
2281 * @field: MonoClassField describing the field to set
2282 * @value: The value to be set
2284 * Sets the value of the field described by @field in the object instance @obj
2285 * to the value passed in @value. This method should only be used for instance
2286 * fields. For static fields, use mono_field_static_set_value.
2288 * The value must be on the native format of the field type.
2291 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2295 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2297 dest = (char*)obj + field->offset;
2298 set_value (field->type, dest, value, FALSE);
2302 * mono_field_static_set_value:
2303 * @field: MonoClassField describing the field to set
2304 * @value: The value to be set
2306 * Sets the value of the static field described by @field
2307 * to the value passed in @value.
2309 * The value must be on the native format of the field type.
2312 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2316 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2317 /* you cant set a constant! */
2318 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2320 dest = (char*)vt->data + field->offset;
2321 set_value (field->type, dest, value, FALSE);
2324 /* Used by the debugger */
2326 mono_vtable_get_static_field_data (MonoVTable *vt)
2332 * mono_field_get_value:
2333 * @obj: Object instance
2334 * @field: MonoClassField describing the field to fetch information from
2335 * @value: pointer to the location where the value will be stored
2337 * Use this routine to get the value of the field @field in the object
2340 * The pointer provided by value must be of the field type, for reference
2341 * types this is a MonoObject*, for value types its the actual pointer to
2346 * mono_field_get_value (obj, int_field, &i);
2349 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2353 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2355 src = (char*)obj + field->offset;
2356 set_value (field->type, value, src, TRUE);
2360 * mono_field_get_value_object:
2361 * @domain: domain where the object will be created (if boxing)
2362 * @field: MonoClassField describing the field to fetch information from
2363 * @obj: The object instance for the field.
2365 * Returns: a new MonoObject with the value from the given field. If the
2366 * field represents a value type, the value is boxed.
2370 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2374 MonoVTable *vtable = NULL;
2376 gboolean is_static = FALSE;
2377 gboolean is_ref = FALSE;
2379 switch (field->type->type) {
2380 case MONO_TYPE_STRING:
2381 case MONO_TYPE_OBJECT:
2382 case MONO_TYPE_CLASS:
2383 case MONO_TYPE_ARRAY:
2384 case MONO_TYPE_SZARRAY:
2389 case MONO_TYPE_BOOLEAN:
2392 case MONO_TYPE_CHAR:
2401 case MONO_TYPE_VALUETYPE:
2402 is_ref = field->type->byref;
2404 case MONO_TYPE_GENERICINST:
2405 is_ref = !field->type->data.generic_class->container_class->valuetype;
2408 g_error ("type 0x%x not handled in "
2409 "mono_field_get_value_object", field->type->type);
2413 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2415 vtable = mono_class_vtable (domain, field->parent);
2416 if (!vtable->initialized)
2417 mono_runtime_class_init (vtable);
2422 mono_field_static_get_value (vtable, field, &o);
2424 mono_field_get_value (obj, field, &o);
2429 /* boxed value type */
2430 klass = mono_class_from_mono_type (field->type);
2431 o = mono_object_new (domain, klass);
2432 v = ((gchar *) o) + sizeof (MonoObject);
2434 mono_field_static_get_value (vtable, field, v);
2436 mono_field_get_value (obj, field, v);
2443 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2446 const char *p = blob;
2447 mono_metadata_decode_blob_size (p, &p);
2450 case MONO_TYPE_BOOLEAN:
2453 *(guint8 *) value = *p;
2455 case MONO_TYPE_CHAR:
2458 *(guint16*) value = read16 (p);
2462 *(guint32*) value = read32 (p);
2466 *(guint64*) value = read64 (p);
2469 readr4 (p, (float*) value);
2472 readr8 (p, (double*) value);
2474 case MONO_TYPE_STRING:
2475 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2477 case MONO_TYPE_CLASS:
2478 *(gpointer*) value = NULL;
2482 g_warning ("type 0x%02x should not be in constant table", type);
2488 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2490 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2491 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2495 * mono_field_static_get_value:
2496 * @vt: vtable to the object
2497 * @field: MonoClassField describing the field to fetch information from
2498 * @value: where the value is returned
2500 * Use this routine to get the value of the static field @field value.
2502 * The pointer provided by value must be of the field type, for reference
2503 * types this is a MonoObject*, for value types its the actual pointer to
2508 * mono_field_static_get_value (vt, int_field, &i);
2511 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2515 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2517 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2518 get_default_field_value (vt->domain, field, value);
2522 src = (char*)vt->data + field->offset;
2523 set_value (field->type, value, src, TRUE);
2527 * mono_property_set_value:
2528 * @prop: MonoProperty to set
2529 * @obj: instance object on which to act
2530 * @params: parameters to pass to the propery
2531 * @exc: optional exception
2533 * Invokes the property's set method with the given arguments on the
2534 * object instance obj (or NULL for static properties).
2536 * You can pass NULL as the exc argument if you don't want to
2537 * catch exceptions, otherwise, *exc will be set to the exception
2538 * thrown, if any. if an exception is thrown, you can't use the
2539 * MonoObject* result from the function.
2542 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2544 default_mono_runtime_invoke (prop->set, obj, params, exc);
2548 * mono_property_get_value:
2549 * @prop: MonoProperty to fetch
2550 * @obj: instance object on which to act
2551 * @params: parameters to pass to the propery
2552 * @exc: optional exception
2554 * Invokes the property's get method with the given arguments on the
2555 * object instance obj (or NULL for static properties).
2557 * You can pass NULL as the exc argument if you don't want to
2558 * catch exceptions, otherwise, *exc will be set to the exception
2559 * thrown, if any. if an exception is thrown, you can't use the
2560 * MonoObject* result from the function.
2562 * Returns: the value from invoking the get method on the property.
2565 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2567 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2571 * mono_nullable_init:
2572 * @buf: The nullable structure to initialize.
2573 * @value: the value to initialize from
2574 * @klass: the type for the object
2576 * Initialize the nullable structure pointed to by @buf from @value which
2577 * should be a boxed value type. The size of @buf should be able to hold
2578 * as much data as the @klass->instance_size (which is the number of bytes
2579 * that will be copies).
2581 * Since Nullables have variable structure, we can not define a C
2582 * structure for them.
2585 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2587 MonoClass *param_class = klass->cast_class;
2589 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2590 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2592 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2594 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2596 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2600 * mono_nullable_box:
2601 * @buf: The buffer representing the data to be boxed
2602 * @klass: the type to box it as.
2604 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2608 mono_nullable_box (guint8 *buf, MonoClass *klass)
2610 MonoClass *param_class = klass->cast_class;
2612 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2613 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2615 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2616 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2617 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2625 * mono_get_delegate_invoke:
2626 * @klass: The delegate class
2628 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2631 mono_get_delegate_invoke (MonoClass *klass)
2635 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2642 * mono_runtime_delegate_invoke:
2643 * @delegate: pointer to a delegate object.
2644 * @params: parameters for the delegate.
2645 * @exc: Pointer to the exception result.
2647 * Invokes the delegate method @delegate with the parameters provided.
2649 * You can pass NULL as the exc argument if you don't want to
2650 * catch exceptions, otherwise, *exc will be set to the exception
2651 * thrown, if any. if an exception is thrown, you can't use the
2652 * MonoObject* result from the function.
2655 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2659 im = mono_get_delegate_invoke (delegate->vtable->klass);
2662 return mono_runtime_invoke (im, delegate, params, exc);
2665 static char **main_args = NULL;
2666 static int num_main_args;
2669 * mono_runtime_get_main_args:
2671 * Returns: a MonoArray with the arguments passed to the main program
2674 mono_runtime_get_main_args (void)
2678 MonoDomain *domain = mono_domain_get ();
2683 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2685 for (i = 0; i < num_main_args; ++i)
2686 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2692 fire_process_exit_event (void)
2694 MonoClassField *field;
2695 MonoDomain *domain = mono_domain_get ();
2697 MonoObject *delegate, *exc;
2699 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2702 if (domain != mono_get_root_domain ())
2705 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2706 if (delegate == NULL)
2711 mono_runtime_delegate_invoke (delegate, pa, &exc);
2715 * mono_runtime_run_main:
2716 * @method: the method to start the application with (usually Main)
2717 * @argc: number of arguments from the command line
2718 * @argv: array of strings from the command line
2719 * @exc: excetption results
2721 * Execute a standard Main() method (argc/argv contains the
2722 * executable name). This method also sets the command line argument value
2723 * needed by System.Environment.
2728 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2732 MonoArray *args = NULL;
2733 MonoDomain *domain = mono_domain_get ();
2734 gchar *utf8_fullpath;
2737 g_assert (method != NULL);
2739 mono_thread_set_main (mono_thread_current ());
2741 main_args = g_new0 (char*, argc);
2742 num_main_args = argc;
2744 if (!g_path_is_absolute (argv [0])) {
2745 gchar *basename = g_path_get_basename (argv [0]);
2746 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2750 utf8_fullpath = mono_utf8_from_external (fullpath);
2751 if(utf8_fullpath == NULL) {
2752 /* Printing the arg text will cause glib to
2753 * whinge about "Invalid UTF-8", but at least
2754 * its relevant, and shows the problem text
2757 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2758 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2765 utf8_fullpath = mono_utf8_from_external (argv[0]);
2766 if(utf8_fullpath == NULL) {
2767 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2768 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2773 main_args [0] = utf8_fullpath;
2775 for (i = 1; i < argc; ++i) {
2778 utf8_arg=mono_utf8_from_external (argv[i]);
2779 if(utf8_arg==NULL) {
2780 /* Ditto the comment about Invalid UTF-8 here */
2781 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2782 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2786 main_args [i] = utf8_arg;
2790 if (mono_method_signature (method)->param_count) {
2791 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2792 for (i = 0; i < argc; ++i) {
2793 /* The encodings should all work, given that
2794 * we've checked all these args for the
2797 gchar *str = mono_utf8_from_external (argv [i]);
2798 MonoString *arg = mono_string_new (domain, str);
2799 mono_array_setref (args, i, arg);
2803 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2806 mono_assembly_set_main (method->klass->image->assembly);
2808 result = mono_runtime_exec_main (method, args, exc);
2809 fire_process_exit_event ();
2813 /* Used in call_unhandled_exception_delegate */
2815 create_unhandled_exception_eventargs (MonoObject *exc)
2819 MonoMethod *method = NULL;
2820 MonoBoolean is_terminating = TRUE;
2823 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2826 mono_class_init (klass);
2828 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2829 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2833 args [1] = &is_terminating;
2835 obj = mono_object_new (mono_domain_get (), klass);
2836 mono_runtime_invoke (method, obj, args, NULL);
2841 /* Used in mono_unhandled_exception */
2843 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2844 MonoObject *e = NULL;
2847 pa [0] = domain->domain;
2848 pa [1] = create_unhandled_exception_eventargs (exc);
2849 mono_runtime_delegate_invoke (delegate, pa, &e);
2852 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2853 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2858 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2861 * mono_runtime_unhandled_exception_policy_set:
2862 * @policy: the new policy
2864 * This is a VM internal routine.
2866 * Sets the runtime policy for handling unhandled exceptions.
2869 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2870 runtime_unhandled_exception_policy = policy;
2874 * mono_runtime_unhandled_exception_policy_get:
2876 * This is a VM internal routine.
2878 * Gets the runtime policy for handling unhandled exceptions.
2880 MonoRuntimeUnhandledExceptionPolicy
2881 mono_runtime_unhandled_exception_policy_get (void) {
2882 return runtime_unhandled_exception_policy;
2886 * mono_unhandled_exception:
2887 * @exc: exception thrown
2889 * This is a VM internal routine.
2891 * We call this function when we detect an unhandled exception
2892 * in the default domain.
2894 * It invokes the * UnhandledException event in AppDomain or prints
2895 * a warning to the console
2898 mono_unhandled_exception (MonoObject *exc)
2900 MonoDomain *current_domain = mono_domain_get ();
2901 MonoDomain *root_domain = mono_get_root_domain ();
2902 MonoClassField *field;
2903 MonoObject *current_appdomain_delegate;
2904 MonoObject *root_appdomain_delegate;
2906 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2907 "UnhandledException");
2910 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2911 gboolean abort_process = (mono_thread_current () == main_thread) ||
2912 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2913 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2914 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2915 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2917 current_appdomain_delegate = NULL;
2920 /* set exitcode only if we will abort the process */
2922 mono_environment_exitcode_set (1);
2923 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2924 mono_print_unhandled_exception (exc);
2926 if (root_appdomain_delegate) {
2927 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2929 if (current_appdomain_delegate) {
2930 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2937 * Launch a new thread to execute a function
2939 * main_func is called back from the thread with main_args as the
2940 * parameter. The callback function is expected to start Main()
2941 * eventually. This function then waits for all managed threads to
2943 * It is not necesseray anymore to execute managed code in a subthread,
2944 * so this function should not be used anymore by default: just
2945 * execute the code and then call mono_thread_manage ().
2948 mono_runtime_exec_managed_code (MonoDomain *domain,
2949 MonoMainThreadFunc main_func,
2952 mono_thread_create (domain, main_func, main_args);
2954 mono_thread_manage ();
2958 * Execute a standard Main() method (args doesn't contain the
2962 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2967 MonoCustomAttrInfo* cinfo;
2968 gboolean has_stathread_attribute;
2969 MonoThread* thread = mono_thread_current ();
2975 domain = mono_object_domain (args);
2976 if (!domain->entry_assembly) {
2978 MonoAssembly *assembly;
2980 assembly = method->klass->image->assembly;
2981 domain->entry_assembly = assembly;
2982 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2984 str = g_strconcat (assembly->image->name, ".config", NULL);
2985 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2989 cinfo = mono_custom_attrs_from_method (method);
2991 static MonoClass *stathread_attribute = NULL;
2992 if (!stathread_attribute)
2993 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
2994 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
2996 mono_custom_attrs_free (cinfo);
2998 has_stathread_attribute = FALSE;
3000 if (has_stathread_attribute) {
3001 thread->apartment_state = ThreadApartmentState_STA;
3002 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
3003 thread->apartment_state = ThreadApartmentState_Unknown;
3005 thread->apartment_state = ThreadApartmentState_MTA;
3007 mono_thread_init_apartment_state ();
3009 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3011 /* FIXME: check signature of method */
3012 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3014 res = mono_runtime_invoke (method, NULL, pa, exc);
3016 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3020 mono_environment_exitcode_set (rval);
3022 mono_runtime_invoke (method, NULL, pa, exc);
3026 /* If the return type of Main is void, only
3027 * set the exitcode if an exception was thrown
3028 * (we don't want to blow away an
3029 * explicitly-set exit code)
3032 mono_environment_exitcode_set (rval);
3036 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3042 * mono_install_runtime_invoke:
3043 * @func: Function to install
3045 * This is a VM internal routine
3048 mono_install_runtime_invoke (MonoInvokeFunc func)
3050 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3055 * mono_runtime_invoke_array:
3056 * @method: method to invoke
3057 * @obJ: object instance
3058 * @params: arguments to the method
3059 * @exc: exception information.
3061 * Invokes the method represented by @method on the object @obj.
3063 * obj is the 'this' pointer, it should be NULL for static
3064 * methods, a MonoObject* for object instances and a pointer to
3065 * the value type for value types.
3067 * The params array contains the arguments to the method with the
3068 * same convention: MonoObject* pointers for object instances and
3069 * pointers to the value type otherwise. The _invoke_array
3070 * variant takes a C# object[] as the params argument (MonoArray
3071 * *params): in this case the value types are boxed inside the
3072 * respective reference representation.
3074 * From unmanaged code you'll usually use the
3075 * mono_runtime_invoke() variant.
3077 * Note that this function doesn't handle virtual methods for
3078 * you, it will exec the exact method you pass: we still need to
3079 * expose a function to lookup the derived class implementation
3080 * of a virtual method (there are examples of this in the code,
3083 * You can pass NULL as the exc argument if you don't want to
3084 * catch exceptions, otherwise, *exc will be set to the exception
3085 * thrown, if any. if an exception is thrown, you can't use the
3086 * MonoObject* result from the function.
3088 * If the method returns a value type, it is boxed in an object
3092 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3095 MonoMethodSignature *sig = mono_method_signature (method);
3096 gpointer *pa = NULL;
3099 if (NULL != params) {
3100 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3101 for (i = 0; i < mono_array_length (params); i++) {
3102 MonoType *t = sig->params [i];
3108 case MONO_TYPE_BOOLEAN:
3111 case MONO_TYPE_CHAR:
3120 case MONO_TYPE_VALUETYPE:
3121 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3124 g_assert_not_reached ();
3125 /* The runtime invoke wrapper needs the original boxed vtype */
3126 pa [i] = mono_array_get (params, MonoObject*, i);
3128 /* MS seems to create the objects if a null is passed in */
3129 if (!mono_array_get (params, MonoObject*, i))
3130 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3134 * We can't pass the unboxed vtype byref to the callee, since
3135 * that would mean the callee would be able to modify boxed
3136 * primitive types. So we (and MS) make a copy of the boxed
3137 * object, pass that to the callee, and replace the original
3138 * boxed object in the arg array with the copy.
3140 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3141 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3142 mono_array_setref (params, i, copy);
3145 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3148 case MONO_TYPE_STRING:
3149 case MONO_TYPE_OBJECT:
3150 case MONO_TYPE_CLASS:
3151 case MONO_TYPE_ARRAY:
3152 case MONO_TYPE_SZARRAY:
3154 pa [i] = mono_array_addr (params, MonoObject*, i);
3155 // FIXME: I need to check this code path
3157 pa [i] = mono_array_get (params, MonoObject*, i);
3159 case MONO_TYPE_GENERICINST:
3161 t = &t->data.generic_class->container_class->this_arg;
3163 t = &t->data.generic_class->container_class->byval_arg;
3166 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3171 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3174 if (mono_class_is_nullable (method->klass)) {
3175 /* Need to create a boxed vtype instead */
3181 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3185 obj = mono_object_new (mono_domain_get (), method->klass);
3186 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3187 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3189 if (method->klass->valuetype)
3190 o = mono_object_unbox (obj);
3193 } else if (method->klass->valuetype) {
3194 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3197 mono_runtime_invoke (method, o, pa, exc);
3200 if (mono_class_is_nullable (method->klass)) {
3201 MonoObject *nullable;
3203 /* Convert the unboxed vtype into a Nullable structure */
3204 nullable = mono_object_new (mono_domain_get (), method->klass);
3206 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3207 obj = mono_object_unbox (nullable);
3210 /* obj must be already unboxed if needed */
3211 return mono_runtime_invoke (method, obj, pa, exc);
3216 arith_overflow (void)
3218 mono_raise_exception (mono_get_exception_overflow ());
3222 * mono_object_allocate:
3223 * @size: number of bytes to allocate
3225 * This is a very simplistic routine until we have our GC-aware
3228 * Returns: an allocated object of size @size, or NULL on failure.
3230 static inline void *
3231 mono_object_allocate (size_t size, MonoVTable *vtable)
3234 mono_stats.new_object_count++;
3235 ALLOC_OBJECT (o, vtable, size);
3241 * mono_object_allocate_ptrfree:
3242 * @size: number of bytes to allocate
3244 * Note that the memory allocated is not zeroed.
3245 * Returns: an allocated object of size @size, or NULL on failure.
3247 static inline void *
3248 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3251 mono_stats.new_object_count++;
3252 ALLOC_PTRFREE (o, vtable, size);
3256 static inline void *
3257 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3260 ALLOC_TYPED (o, size, vtable);
3261 mono_stats.new_object_count++;
3268 * @klass: the class of the object that we want to create
3270 * Returns: a newly created object whose definition is
3271 * looked up using @klass. This will not invoke any constructors,
3272 * so the consumer of this routine has to invoke any constructors on
3273 * its own to initialize the object.
3276 mono_object_new (MonoDomain *domain, MonoClass *klass)
3278 MONO_ARCH_SAVE_REGS;
3279 return mono_object_new_specific (mono_class_vtable (domain, klass));
3283 * mono_object_new_specific:
3284 * @vtable: the vtable of the object that we want to create
3286 * Returns: A newly created object with class and domain specified
3290 mono_object_new_specific (MonoVTable *vtable)
3294 MONO_ARCH_SAVE_REGS;
3296 /* check for is_com_object for COM Interop */
3297 if (vtable->remote || vtable->klass->is_com_object)
3300 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3303 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3306 mono_class_init (klass);
3308 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3310 vtable->domain->create_proxy_for_type_method = im;
3313 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3315 o = mono_runtime_invoke (im, NULL, pa, NULL);
3316 if (o != NULL) return o;
3319 return mono_object_new_alloc_specific (vtable);
3323 mono_object_new_alloc_specific (MonoVTable *vtable)
3327 if (!vtable->klass->has_references) {
3328 o = mono_object_new_ptrfree (vtable);
3329 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3330 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3332 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3333 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3335 if (G_UNLIKELY (vtable->klass->has_finalize))
3336 mono_object_register_finalizer (o);
3338 if (G_UNLIKELY (profile_allocs))
3339 mono_profiler_allocation (o, vtable->klass);
3344 mono_object_new_fast (MonoVTable *vtable)
3347 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3352 mono_object_new_ptrfree (MonoVTable *vtable)
3355 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3356 #if NEED_TO_ZERO_PTRFREE
3357 /* an inline memset is much faster for the common vcase of small objects
3358 * note we assume the allocated size is a multiple of sizeof (void*).
3360 if (vtable->klass->instance_size < 128) {
3362 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3363 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3369 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3376 mono_object_new_ptrfree_box (MonoVTable *vtable)
3379 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3380 /* the object will be boxed right away, no need to memzero it */
3385 * mono_class_get_allocation_ftn:
3387 * @for_box: the object will be used for boxing
3388 * @pass_size_in_words:
3390 * Return the allocation function appropriate for the given class.
3394 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3396 *pass_size_in_words = FALSE;
3398 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3399 profile_allocs = FALSE;
3401 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3402 return mono_object_new_specific;
3404 if (!vtable->klass->has_references) {
3405 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3407 return mono_object_new_ptrfree_box;
3408 return mono_object_new_ptrfree;
3411 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3413 return mono_object_new_fast;
3416 * FIXME: This is actually slower than mono_object_new_fast, because
3417 * of the overhead of parameter passing.
3420 *pass_size_in_words = TRUE;
3421 #ifdef GC_REDIRECT_TO_LOCAL
3422 return GC_local_gcj_fast_malloc;
3424 return GC_gcj_fast_malloc;
3429 return mono_object_new_specific;
3433 * mono_object_new_from_token:
3434 * @image: Context where the type_token is hosted
3435 * @token: a token of the type that we want to create
3437 * Returns: A newly created object whose definition is
3438 * looked up using @token in the @image image
3441 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3445 class = mono_class_get (image, token);
3447 return mono_object_new (domain, class);
3452 * mono_object_clone:
3453 * @obj: the object to clone
3455 * Returns: A newly created object who is a shallow copy of @obj
3458 mono_object_clone (MonoObject *obj)
3463 size = obj->vtable->klass->instance_size;
3464 o = mono_object_allocate (size, obj->vtable);
3465 /* do not copy the sync state */
3466 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3469 if (obj->vtable->klass->has_references)
3470 mono_gc_wbarrier_object (o);
3472 if (G_UNLIKELY (profile_allocs))
3473 mono_profiler_allocation (o, obj->vtable->klass);
3475 if (obj->vtable->klass->has_finalize)
3476 mono_object_register_finalizer (o);
3481 * mono_array_full_copy:
3482 * @src: source array to copy
3483 * @dest: destination array
3485 * Copies the content of one array to another with exactly the same type and size.
3488 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3490 mono_array_size_t size;
3491 MonoClass *klass = src->obj.vtable->klass;
3493 MONO_ARCH_SAVE_REGS;
3495 g_assert (klass == dest->obj.vtable->klass);
3497 size = mono_array_length (src);
3498 g_assert (size == mono_array_length (dest));
3499 size *= mono_array_element_size (klass);
3501 if (klass->element_class->valuetype) {
3502 if (klass->element_class->has_references)
3503 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3505 memcpy (&dest->vector, &src->vector, size);
3507 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3510 memcpy (&dest->vector, &src->vector, size);
3515 * mono_array_clone_in_domain:
3516 * @domain: the domain in which the array will be cloned into
3517 * @array: the array to clone
3519 * This routine returns a copy of the array that is hosted on the
3520 * specified MonoDomain.
3523 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3526 mono_array_size_t size, i;
3527 mono_array_size_t *sizes;
3528 MonoClass *klass = array->obj.vtable->klass;
3530 MONO_ARCH_SAVE_REGS;
3532 if (array->bounds == NULL) {
3533 size = mono_array_length (array);
3534 o = mono_array_new_full (domain, klass, &size, NULL);
3536 size *= mono_array_element_size (klass);
3538 if (klass->element_class->valuetype) {
3539 if (klass->element_class->has_references)
3540 mono_value_copy_array (o, 0, array, mono_array_length (array));
3542 memcpy (&o->vector, &array->vector, size);
3544 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3547 memcpy (&o->vector, &array->vector, size);
3552 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3553 size = mono_array_element_size (klass);
3554 for (i = 0; i < klass->rank; ++i) {
3555 sizes [i] = array->bounds [i].length;
3556 size *= array->bounds [i].length;
3557 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3559 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3561 if (klass->element_class->valuetype) {
3562 if (klass->element_class->has_references)
3563 mono_value_copy_array (o, 0, array, mono_array_length (array));
3565 memcpy (&o->vector, &array->vector, size);
3567 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3570 memcpy (&o->vector, &array->vector, size);
3578 * @array: the array to clone
3580 * Returns: A newly created array who is a shallow copy of @array
3583 mono_array_clone (MonoArray *array)
3585 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3588 /* helper macros to check for overflow when calculating the size of arrays */
3589 #ifdef MONO_BIG_ARRAYS
3590 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3591 #define MYGUINT_MAX MYGUINT64_MAX
3592 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3593 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a))
3594 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3595 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
3596 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3598 #define MYGUINT32_MAX 4294967295U
3599 #define MYGUINT_MAX MYGUINT32_MAX
3600 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3601 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3602 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3603 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
3604 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3608 * mono_array_new_full:
3609 * @domain: domain where the object is created
3610 * @array_class: array class
3611 * @lengths: lengths for each dimension in the array
3612 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3614 * This routine creates a new array objects with the given dimensions,
3615 * lower bounds and type.
3618 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3620 mono_array_size_t byte_len, len, bounds_size;
3626 if (!array_class->inited)
3627 mono_class_init (array_class);
3629 byte_len = mono_array_element_size (array_class);
3632 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3633 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3635 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3639 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3641 for (i = 0; i < array_class->rank; ++i) {
3642 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3644 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3645 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3650 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3651 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3653 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3654 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3655 byte_len += sizeof (MonoArray);
3658 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3659 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3660 byte_len = (byte_len + 3) & ~3;
3661 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3662 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3663 byte_len += bounds_size;
3666 * Following three lines almost taken from mono_object_new ():
3667 * they need to be kept in sync.
3669 vtable = mono_class_vtable (domain, array_class);
3670 if (!array_class->has_references) {
3671 o = mono_object_allocate_ptrfree (byte_len, vtable);
3672 #if NEED_TO_ZERO_PTRFREE
3673 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3675 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3676 o = mono_object_allocate_spec (byte_len, vtable);
3678 o = mono_object_allocate (byte_len, vtable);
3681 array = (MonoArray*)o;
3682 array->max_length = len;
3685 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3686 array->bounds = bounds;
3687 for (i = 0; i < array_class->rank; ++i) {
3688 bounds [i].length = lengths [i];
3690 bounds [i].lower_bound = lower_bounds [i];
3694 if (G_UNLIKELY (profile_allocs))
3695 mono_profiler_allocation (o, array_class);
3702 * @domain: domain where the object is created
3703 * @eclass: element class
3704 * @n: number of array elements
3706 * This routine creates a new szarray with @n elements of type @eclass.
3709 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3713 MONO_ARCH_SAVE_REGS;
3715 ac = mono_array_class_get (eclass, 1);
3718 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3722 * mono_array_new_specific:
3723 * @vtable: a vtable in the appropriate domain for an initialized class
3724 * @n: number of array elements
3726 * This routine is a fast alternative to mono_array_new() for code which
3727 * can be sure about the domain it operates in.
3730 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
3734 guint32 byte_len, elem_size;
3736 MONO_ARCH_SAVE_REGS;
3738 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
3743 elem_size = mono_array_element_size (vtable->klass);
3744 if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
3745 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3748 byte_len = n * elem_size;
3749 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
3750 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3753 byte_len += sizeof (MonoArray);
3754 if (!vtable->klass->has_references) {
3755 o = mono_object_allocate_ptrfree (byte_len, vtable);
3756 #if NEED_TO_ZERO_PTRFREE
3757 ((MonoArray*)o)->bounds = NULL;
3758 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3760 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3761 o = mono_object_allocate_spec (byte_len, vtable);
3763 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3764 o = mono_object_allocate (byte_len, vtable);
3767 ao = (MonoArray *)o;
3769 if (G_UNLIKELY (profile_allocs))
3770 mono_profiler_allocation (o, vtable->klass);
3776 * mono_string_new_utf16:
3777 * @text: a pointer to an utf16 string
3778 * @len: the length of the string
3780 * Returns: A newly created string object which contains @text.
3783 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3787 s = mono_string_new_size (domain, len);
3788 g_assert (s != NULL);
3790 memcpy (mono_string_chars (s), text, len * 2);
3796 * mono_string_new_size:
3797 * @text: a pointer to an utf16 string
3798 * @len: the length of the string
3800 * Returns: A newly created string object of @len
3803 mono_string_new_size (MonoDomain *domain, gint32 len)
3807 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3809 /* overflow ? can't fit it, can't allocate it! */
3811 mono_gc_out_of_memory (-1);
3813 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3815 s = mono_object_allocate_ptrfree (size, vtable);
3818 #if NEED_TO_ZERO_PTRFREE
3821 if (G_UNLIKELY (profile_allocs))
3822 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3828 * mono_string_new_len:
3829 * @text: a pointer to an utf8 string
3830 * @length: number of bytes in @text to consider
3832 * Returns: A newly created string object which contains @text.
3835 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3837 GError *error = NULL;
3838 MonoString *o = NULL;
3840 glong items_written;
3842 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3845 o = mono_string_new_utf16 (domain, ut, items_written);
3847 g_error_free (error);
3856 * @text: a pointer to an utf8 string
3858 * Returns: A newly created string object which contains @text.
3861 mono_string_new (MonoDomain *domain, const char *text)
3863 GError *error = NULL;
3864 MonoString *o = NULL;
3866 glong items_written;
3871 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3874 o = mono_string_new_utf16 (domain, ut, items_written);
3876 g_error_free (error);
3884 * mono_string_new_wrapper:
3885 * @text: pointer to utf8 characters.
3887 * Helper function to create a string object from @text in the current domain.
3890 mono_string_new_wrapper (const char *text)
3892 MonoDomain *domain = mono_domain_get ();
3894 MONO_ARCH_SAVE_REGS;
3897 return mono_string_new (domain, text);
3904 * @class: the class of the value
3905 * @value: a pointer to the unboxed data
3907 * Returns: A newly created object which contains @value.
3910 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3916 g_assert (class->valuetype);
3917 if (mono_class_is_nullable (class))
3918 return mono_nullable_box (value, class);
3920 vtable = mono_class_vtable (domain, class);
3921 size = mono_class_instance_size (class);
3922 res = mono_object_new_alloc_specific (vtable);
3923 if (G_UNLIKELY (profile_allocs))
3924 mono_profiler_allocation (res, class);
3926 size = size - sizeof (MonoObject);
3929 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3932 #if NO_UNALIGNED_ACCESS
3933 memcpy ((char *)res + sizeof (MonoObject), value, size);
3937 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3940 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3943 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3946 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3949 memcpy ((char *)res + sizeof (MonoObject), value, size);
3952 if (class->has_finalize)
3953 mono_object_register_finalizer (res);
3959 * @dest: destination pointer
3960 * @src: source pointer
3961 * @klass: a valuetype class
3963 * Copy a valuetype from @src to @dest. This function must be used
3964 * when @klass contains references fields.
3967 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3969 int size = mono_class_value_size (klass, NULL);
3970 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3971 memcpy (dest, src, size);
3975 * mono_value_copy_array:
3976 * @dest: destination array
3977 * @dest_idx: index in the @dest array
3978 * @src: source pointer
3979 * @count: number of items
3981 * Copy @count valuetype items from @src to @dest. This function must be used
3982 * when @klass contains references fields.
3983 * Overlap is handled.
3986 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3988 int size = mono_array_element_size (dest->obj.vtable->klass);
3989 char *d = mono_array_addr_with_size (dest, size, dest_idx);
3990 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3991 memmove (d, src, size * count);
3995 * mono_object_get_domain:
3996 * @obj: object to query
3998 * Returns: the MonoDomain where the object is hosted
4001 mono_object_get_domain (MonoObject *obj)
4003 return mono_object_domain (obj);
4007 * mono_object_get_class:
4008 * @obj: object to query
4010 * Returns: the MonOClass of the object.
4013 mono_object_get_class (MonoObject *obj)
4015 return mono_object_class (obj);
4018 * mono_object_get_size:
4019 * @o: object to query
4021 * Returns: the size, in bytes, of @o
4024 mono_object_get_size (MonoObject* o)
4026 MonoClass* klass = mono_object_class (o);
4027 if (klass == mono_defaults.string_class) {
4028 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4029 } else if (o->vtable->rank) {
4030 MonoArray *array = (MonoArray*)o;
4031 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4032 if (array->bounds) {
4035 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4039 return mono_class_instance_size (klass);
4044 * mono_object_unbox:
4045 * @obj: object to unbox
4047 * Returns: a pointer to the start of the valuetype boxed in this
4050 * This method will assert if the object passed is not a valuetype.
4053 mono_object_unbox (MonoObject *obj)
4055 /* add assert for valuetypes? */
4056 g_assert (obj->vtable->klass->valuetype);
4057 return ((char*)obj) + sizeof (MonoObject);
4061 * mono_object_isinst:
4063 * @klass: a pointer to a class
4065 * Returns: @obj if @obj is derived from @klass
4068 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4071 mono_class_init (klass);
4073 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4074 return mono_object_isinst_mbyref (obj, klass);
4079 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4083 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4092 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4093 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4097 MonoClass *oklass = vt->klass;
4098 if ((oklass == mono_defaults.transparent_proxy_class))
4099 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4101 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4105 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4107 MonoDomain *domain = mono_domain_get ();
4109 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4110 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4111 MonoMethod *im = NULL;
4114 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4115 im = mono_object_get_virtual_method (rp, im);
4118 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4121 res = mono_runtime_invoke (im, rp, pa, NULL);
4123 if (*(MonoBoolean *) mono_object_unbox(res)) {
4124 /* Update the vtable of the remote type, so it can safely cast to this new type */
4125 mono_upgrade_remote_class (domain, obj, klass);
4134 * mono_object_castclass_mbyref:
4136 * @klass: a pointer to a class
4138 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4141 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4143 if (!obj) return NULL;
4144 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4146 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4148 "InvalidCastException"));
4153 MonoDomain *orig_domain;
4159 str_lookup (MonoDomain *domain, gpointer user_data)
4161 LDStrInfo *info = user_data;
4162 if (info->res || domain == info->orig_domain)
4164 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4170 mono_string_get_pinned (MonoString *str)
4174 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4175 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4176 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4177 news->length = mono_string_length (str);
4182 #define mono_string_get_pinned(str) (str)
4186 mono_string_is_interned_lookup (MonoString *str, int insert)
4188 MonoGHashTable *ldstr_table;
4192 domain = ((MonoObject *)str)->vtable->domain;
4193 ldstr_table = domain->ldstr_table;
4195 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4200 str = mono_string_get_pinned (str);
4201 mono_g_hash_table_insert (ldstr_table, str, str);
4205 LDStrInfo ldstr_info;
4206 ldstr_info.orig_domain = domain;
4207 ldstr_info.ins = str;
4208 ldstr_info.res = NULL;
4210 mono_domain_foreach (str_lookup, &ldstr_info);
4211 if (ldstr_info.res) {
4213 * the string was already interned in some other domain:
4214 * intern it in the current one as well.
4216 mono_g_hash_table_insert (ldstr_table, str, str);
4226 * mono_string_is_interned:
4227 * @o: String to probe
4229 * Returns whether the string has been interned.
4232 mono_string_is_interned (MonoString *o)
4234 return mono_string_is_interned_lookup (o, FALSE);
4238 * mono_string_intern:
4239 * @o: String to intern
4241 * Interns the string passed.
4242 * Returns: The interned string.
4245 mono_string_intern (MonoString *str)
4247 return mono_string_is_interned_lookup (str, TRUE);
4252 * @domain: the domain where the string will be used.
4253 * @image: a metadata context
4254 * @idx: index into the user string table.
4256 * Implementation for the ldstr opcode.
4257 * Returns: a loaded string from the @image/@idx combination.
4260 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4262 MONO_ARCH_SAVE_REGS;
4265 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4267 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4271 * mono_ldstr_metdata_sig
4272 * @domain: the domain for the string
4273 * @sig: the signature of a metadata string
4275 * Returns: a MonoString for a string stored in the metadata
4278 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4280 const char *str = sig;
4281 MonoString *o, *interned;
4284 len2 = mono_metadata_decode_blob_size (str, &str);
4287 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4288 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4291 guint16 *p2 = (guint16*)mono_string_chars (o);
4292 for (i = 0; i < len2; ++i) {
4293 *p2 = GUINT16_FROM_LE (*p2);
4299 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4301 /* o will get garbage collected */
4305 o = mono_string_get_pinned (o);
4306 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4313 * mono_string_to_utf8:
4314 * @s: a System.String
4316 * Return the UTF8 representation for @s.
4317 * the resulting buffer nedds to be freed with g_free().
4320 mono_string_to_utf8 (MonoString *s)
4324 GError *error = NULL;
4330 return g_strdup ("");
4332 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4334 MonoException *exc = mono_get_exception_argument ("string", error->message);
4335 g_error_free (error);
4336 mono_raise_exception(exc);
4338 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4339 if (s->length > written) {
4340 /* allocate the total length and copy the part of the string that has been converted */
4341 char *as2 = g_malloc0 (s->length);
4342 memcpy (as2, as, written);
4351 * mono_string_to_utf16:
4354 * Return an null-terminated array of the utf-16 chars
4355 * contained in @s. The result must be freed with g_free().
4356 * This is a temporary helper until our string implementation
4357 * is reworked to always include the null terminating char.
4360 mono_string_to_utf16 (MonoString *s)
4367 as = g_malloc ((s->length * 2) + 2);
4368 as [(s->length * 2)] = '\0';
4369 as [(s->length * 2) + 1] = '\0';
4372 return (gunichar2 *)(as);
4375 memcpy (as, mono_string_chars(s), s->length * 2);
4376 return (gunichar2 *)(as);
4380 * mono_string_from_utf16:
4381 * @data: the UTF16 string (LPWSTR) to convert
4383 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4385 * Returns: a MonoString.
4388 mono_string_from_utf16 (gunichar2 *data)
4390 MonoDomain *domain = mono_domain_get ();
4396 while (data [len]) len++;
4398 return mono_string_new_utf16 (domain, data, len);
4402 * mono_string_to_utf8_mp:
4403 * @s: a System.String
4405 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4408 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4410 char *r = mono_string_to_utf8 (s);
4417 len = strlen (r) + 1;
4418 mp_s = mono_mempool_alloc (mp, len);
4419 memcpy (mp_s, r, len);
4427 default_ex_handler (MonoException *ex)
4429 MonoObject *o = (MonoObject*)ex;
4430 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4434 static MonoExceptionFunc ex_handler = default_ex_handler;
4437 * mono_install_handler:
4438 * @func: exception handler
4440 * This is an internal JIT routine used to install the handler for exceptions
4444 mono_install_handler (MonoExceptionFunc func)
4446 ex_handler = func? func: default_ex_handler;
4450 * mono_raise_exception:
4451 * @ex: exception object
4453 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4456 mono_raise_exception (MonoException *ex)
4459 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4460 * that will cause gcc to omit the function epilog, causing problems when
4461 * the JIT tries to walk the stack, since the return address on the stack
4462 * will point into the next function in the executable, not this one.
4465 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4466 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4472 * mono_wait_handle_new:
4473 * @domain: Domain where the object will be created
4474 * @handle: Handle for the wait handle
4476 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4479 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4481 MonoWaitHandle *res;
4482 gpointer params [1];
4483 static MonoMethod *handle_set;
4485 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4487 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4489 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4491 params [0] = &handle;
4492 mono_runtime_invoke (handle_set, res, params, NULL);
4498 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4500 static MonoClassField *f_os_handle;
4501 static MonoClassField *f_safe_handle;
4503 if (!f_os_handle && !f_safe_handle) {
4504 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4505 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4510 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4514 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4520 * mono_async_result_new:
4521 * @domain:domain where the object will be created.
4522 * @handle: wait handle.
4523 * @state: state to pass to AsyncResult
4524 * @data: C closure data.
4526 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4527 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4531 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4533 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4534 MonoMethod *method = mono_get_context_capture_method ();
4536 /* we must capture the execution context from the original thread */
4538 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4539 /* note: result may be null if the flow is suppressed */
4543 MONO_OBJECT_SETREF (res, object_data, object_data);
4544 MONO_OBJECT_SETREF (res, async_state, state);
4546 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4548 res->sync_completed = FALSE;
4549 res->completed = FALSE;
4555 mono_message_init (MonoDomain *domain,
4556 MonoMethodMessage *this,
4557 MonoReflectionMethod *method,
4558 MonoArray *out_args)
4560 static MonoClass *object_array_klass;
4561 static MonoClass *byte_array_klass;
4562 static MonoClass *string_array_klass;
4563 MonoMethodSignature *sig = mono_method_signature (method->method);
4569 if (!object_array_klass) {
4572 klass = mono_array_class_get (mono_defaults.object_class, 1);
4575 mono_memory_barrier ();
4576 object_array_klass = klass;
4578 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4581 mono_memory_barrier ();
4582 byte_array_klass = klass;
4584 klass = mono_array_class_get (mono_defaults.string_class, 1);
4587 mono_memory_barrier ();
4588 string_array_klass = klass;
4591 MONO_OBJECT_SETREF (this, method, method);
4593 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4594 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4595 this->async_result = NULL;
4596 this->call_type = CallType_Sync;
4598 names = g_new (char *, sig->param_count);
4599 mono_method_get_param_names (method->method, (const char **) names);
4600 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4602 for (i = 0; i < sig->param_count; i++) {
4603 name = mono_string_new (domain, names [i]);
4604 mono_array_setref (this->names, i, name);
4608 for (i = 0, j = 0; i < sig->param_count; i++) {
4609 if (sig->params [i]->byref) {
4611 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4612 mono_array_setref (this->args, i, arg);
4616 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4620 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4623 mono_array_set (this->arg_types, guint8, i, arg_type);
4628 * mono_remoting_invoke:
4629 * @real_proxy: pointer to a RealProxy object
4630 * @msg: The MonoMethodMessage to execute
4631 * @exc: used to store exceptions
4632 * @out_args: used to store output arguments
4634 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4635 * IMessage interface and it is not trivial to extract results from there. So
4636 * we call an helper method PrivateInvoke instead of calling
4637 * RealProxy::Invoke() directly.
4639 * Returns: the result object.
4642 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4643 MonoObject **exc, MonoArray **out_args)
4645 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4648 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4651 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4653 real_proxy->vtable->domain->private_invoke_method = im;
4656 pa [0] = real_proxy;
4661 return mono_runtime_invoke (im, NULL, pa, exc);
4665 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4666 MonoObject **exc, MonoArray **out_args)
4668 static MonoClass *object_array_klass;
4671 MonoMethodSignature *sig;
4673 int i, j, outarg_count = 0;
4675 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4677 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4678 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4679 target = tp->rp->unwrapped_server;
4681 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4685 domain = mono_domain_get ();
4686 method = msg->method->method;
4687 sig = mono_method_signature (method);
4689 for (i = 0; i < sig->param_count; i++) {
4690 if (sig->params [i]->byref)
4694 if (!object_array_klass) {
4697 klass = mono_array_class_get (mono_defaults.object_class, 1);
4700 mono_memory_barrier ();
4701 object_array_klass = klass;
4704 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4705 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
4708 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4710 for (i = 0, j = 0; i < sig->param_count; i++) {
4711 if (sig->params [i]->byref) {
4713 arg = mono_array_get (msg->args, gpointer, i);
4714 mono_array_setref (*out_args, j, arg);
4723 * mono_print_unhandled_exception:
4724 * @exc: The exception
4726 * Prints the unhandled exception.
4729 mono_print_unhandled_exception (MonoObject *exc)
4731 char *message = (char *) "";
4735 gboolean free_message = FALSE;
4737 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4738 klass = exc->vtable->klass;
4740 while (klass && method == NULL) {
4741 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4743 klass = klass->parent;
4748 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4750 message = mono_string_to_utf8 (str);
4751 free_message = TRUE;
4756 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4757 * exc->vtable->klass->name, message);
4759 g_printerr ("\nUnhandled Exception: %s\n", message);
4766 * mono_delegate_ctor:
4767 * @this: pointer to an uninitialized delegate object
4768 * @target: target object
4769 * @addr: pointer to native code
4771 * This is used to initialize a delegate.
4774 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4776 MonoDomain *domain = mono_domain_get ();
4777 MonoDelegate *delegate = (MonoDelegate *)this;
4778 MonoMethod *method = NULL;
4785 class = this->vtable->klass;
4786 mono_stats.delegate_creations++;
4788 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4789 method = ji->method;
4790 delegate->method = method;
4793 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4795 method = mono_marshal_get_remoting_invoke (method);
4796 delegate->method_ptr = mono_compile_method (method);
4797 MONO_OBJECT_SETREF (delegate, target, target);
4798 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4799 method = mono_marshal_get_unbox_wrapper (method);
4800 delegate->method_ptr = mono_compile_method (method);
4801 MONO_OBJECT_SETREF (delegate, target, target);
4803 delegate->method_ptr = addr;
4804 MONO_OBJECT_SETREF (delegate, target, target);
4807 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4811 * mono_method_call_message_new:
4812 * @method: method to encapsulate
4813 * @params: parameters to the method
4814 * @invoke: optional, delegate invoke.
4815 * @cb: async callback delegate.
4816 * @state: state passed to the async callback.
4818 * Translates arguments pointers into a MonoMethodMessage.
4821 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4822 MonoDelegate **cb, MonoObject **state)
4824 MonoDomain *domain = mono_domain_get ();
4825 MonoMethodSignature *sig = mono_method_signature (method);
4826 MonoMethodMessage *msg;
4829 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4832 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4833 count = sig->param_count - 2;
4835 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4836 count = sig->param_count;
4839 for (i = 0; i < count; i++) {
4844 if (sig->params [i]->byref)
4845 vpos = *((gpointer *)params [i]);
4849 type = sig->params [i]->type;
4850 class = mono_class_from_mono_type (sig->params [i]);
4852 if (class->valuetype)
4853 arg = mono_value_box (domain, class, vpos);
4855 arg = *((MonoObject **)vpos);
4857 mono_array_setref (msg->args, i, arg);
4860 if (cb != NULL && state != NULL) {
4861 *cb = *((MonoDelegate **)params [i]);
4863 *state = *((MonoObject **)params [i]);
4870 * mono_method_return_message_restore:
4872 * Restore results from message based processing back to arguments pointers
4875 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4877 MonoMethodSignature *sig = mono_method_signature (method);
4878 int i, j, type, size, out_len;
4880 if (out_args == NULL)
4882 out_len = mono_array_length (out_args);
4886 for (i = 0, j = 0; i < sig->param_count; i++) {
4887 MonoType *pt = sig->params [i];
4892 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4894 arg = mono_array_get (out_args, gpointer, j);
4898 case MONO_TYPE_VOID:
4899 g_assert_not_reached ();
4903 case MONO_TYPE_BOOLEAN:
4906 case MONO_TYPE_CHAR:
4913 case MONO_TYPE_VALUETYPE: {
4915 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4916 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4919 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4920 memset (*((gpointer *)params [i]), 0, size);
4924 case MONO_TYPE_STRING:
4925 case MONO_TYPE_CLASS:
4926 case MONO_TYPE_ARRAY:
4927 case MONO_TYPE_SZARRAY:
4928 case MONO_TYPE_OBJECT:
4929 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4932 g_assert_not_reached ();
4941 * mono_load_remote_field:
4942 * @this: pointer to an object
4943 * @klass: klass of the object containing @field
4944 * @field: the field to load
4945 * @res: a storage to store the result
4947 * This method is called by the runtime on attempts to load fields of
4948 * transparent proxy objects. @this points to such TP, @klass is the class of
4949 * the object containing @field. @res is a storage location which can be
4950 * used to store the result.
4952 * Returns: an address pointing to the value of field.
4955 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4957 static MonoMethod *getter = NULL;
4958 MonoDomain *domain = mono_domain_get ();
4959 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4960 MonoClass *field_class;
4961 MonoMethodMessage *msg;
4962 MonoArray *out_args;
4966 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4967 g_assert (res != NULL);
4969 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4970 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4975 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4979 field_class = mono_class_from_mono_type (field->type);
4981 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4982 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4983 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4985 full_name = mono_type_get_full_name (klass);
4986 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4987 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4990 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4992 if (exc) mono_raise_exception ((MonoException *)exc);
4994 if (mono_array_length (out_args) == 0)
4997 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4999 if (field_class->valuetype) {
5000 return ((char *)*res) + sizeof (MonoObject);
5006 * mono_load_remote_field_new:
5011 * Missing documentation.
5014 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5016 static MonoMethod *getter = NULL;
5017 MonoDomain *domain = mono_domain_get ();
5018 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5019 MonoClass *field_class;
5020 MonoMethodMessage *msg;
5021 MonoArray *out_args;
5022 MonoObject *exc, *res;
5025 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5027 field_class = mono_class_from_mono_type (field->type);
5029 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5031 if (field_class->valuetype) {
5032 res = mono_object_new (domain, field_class);
5033 val = ((gchar *) res) + sizeof (MonoObject);
5037 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5042 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5046 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5047 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5049 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5051 full_name = mono_type_get_full_name (klass);
5052 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5053 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5056 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5058 if (exc) mono_raise_exception ((MonoException *)exc);
5060 if (mono_array_length (out_args) == 0)
5063 res = mono_array_get (out_args, MonoObject *, 0);
5069 * mono_store_remote_field:
5070 * @this: pointer to an object
5071 * @klass: klass of the object containing @field
5072 * @field: the field to load
5073 * @val: the value/object to store
5075 * This method is called by the runtime on attempts to store fields of
5076 * transparent proxy objects. @this points to such TP, @klass is the class of
5077 * the object containing @field. @val is the new value to store in @field.
5080 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5082 static MonoMethod *setter = NULL;
5083 MonoDomain *domain = mono_domain_get ();
5084 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5085 MonoClass *field_class;
5086 MonoMethodMessage *msg;
5087 MonoArray *out_args;
5092 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5094 field_class = mono_class_from_mono_type (field->type);
5096 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5097 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5098 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5103 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5107 if (field_class->valuetype)
5108 arg = mono_value_box (domain, field_class, val);
5110 arg = *((MonoObject **)val);
5113 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5114 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5116 full_name = mono_type_get_full_name (klass);
5117 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5118 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5119 mono_array_setref (msg->args, 2, arg);
5122 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5124 if (exc) mono_raise_exception ((MonoException *)exc);
5128 * mono_store_remote_field_new:
5134 * Missing documentation
5137 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5139 static MonoMethod *setter = NULL;
5140 MonoDomain *domain = mono_domain_get ();
5141 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5142 MonoClass *field_class;
5143 MonoMethodMessage *msg;
5144 MonoArray *out_args;
5148 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5150 field_class = mono_class_from_mono_type (field->type);
5152 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5153 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5154 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5159 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5163 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5164 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5166 full_name = mono_type_get_full_name (klass);
5167 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5168 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5169 mono_array_setref (msg->args, 2, arg);
5172 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5174 if (exc) mono_raise_exception ((MonoException *)exc);
5178 * mono_create_ftnptr:
5180 * Given a function address, create a function descriptor for it.
5181 * This is only needed on IA64 and PPC64.
5184 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5189 mono_domain_lock (domain);
5190 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5191 mono_domain_unlock (domain);
5197 #elif defined(__ppc64__) || defined(__powerpc64__)
5200 mono_domain_lock (domain);
5201 desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5202 mono_domain_unlock (domain);
5215 * mono_get_addr_from_ftnptr:
5217 * Given a pointer to a function descriptor, return the function address.
5218 * This is only needed on IA64 and PPC64.
5221 mono_get_addr_from_ftnptr (gpointer descr)
5223 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5224 return *(gpointer*)descr;
5232 * mono_string_chars:
5235 * Returns a pointer to the UCS16 characters stored in the MonoString
5238 mono_string_chars(MonoString *s)
5240 /* This method is here only for documentation extraction, this is a macro */
5244 * mono_string_length:
5247 * Returns the lenght in characters of the string
5250 mono_string_length (MonoString *s)
5252 /* This method is here only for documentation extraction, this is a macro */