2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * (C) 2001-2004 Ximian, Inc.
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include "mono/metadata/security-manager.h"
35 #include "mono/metadata/mono-debug-debugger.h"
36 #include <mono/metadata/gc-internal.h>
37 #include <mono/utils/strenc.h>
40 #define NEED_TO_ZERO_PTRFREE 1
41 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
42 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
43 #ifdef HAVE_GC_GCJ_MALLOC
44 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
45 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
47 #define GC_NO_DESCRIPTOR (NULL)
48 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
52 #define GC_NO_DESCRIPTOR (NULL)
53 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
54 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
57 #define NEED_TO_ZERO_PTRFREE 1
58 #define GC_NO_DESCRIPTOR (NULL)
59 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
60 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
61 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
65 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
66 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
69 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
72 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
74 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
75 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
76 static CRITICAL_SECTION ldstr_section;
79 mono_runtime_object_init (MonoObject *this)
81 MonoMethod *method = NULL;
82 MonoClass *klass = this->vtable->klass;
84 method = mono_class_get_method_from_name (klass, ".ctor", 0);
87 if (method->klass->valuetype)
88 this = mono_object_unbox (this);
89 mono_runtime_invoke (method, this, NULL, NULL);
92 /* The pseudo algorithm for type initialization from the spec
93 Note it doesn't say anything about domains - only threads.
95 2. If the type is initialized you are done.
96 2.1. If the type is not yet initialized, try to take an
98 2.2. If successful, record this thread as responsible for
99 initializing the type and proceed to step 2.3.
100 2.2.1. If not, see whether this thread or any thread
101 waiting for this thread to complete already holds the lock.
102 2.2.2. If so, return since blocking would create a deadlock. This thread
103 will now see an incompletely initialized state for the type,
104 but no deadlock will arise.
105 2.2.3 If not, block until the type is initialized then return.
106 2.3 Initialize the parent type and then all interfaces implemented
108 2.4 Execute the type initialization code for this type.
109 2.5 Mark the type as initialized, release the initialization lock,
110 awaken any threads waiting for this type to be initialized,
117 guint32 initializing_tid;
118 guint32 waiting_count;
120 CRITICAL_SECTION initialization_section;
121 } TypeInitializationLock;
123 /* for locking access to type_initialization_hash and blocked_thread_hash */
124 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
125 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
126 static CRITICAL_SECTION type_initialization_section;
128 /* from vtable to lock */
129 static GHashTable *type_initialization_hash;
131 /* from thread id to thread id being waited on */
132 static GHashTable *blocked_thread_hash;
135 static MonoThread *main_thread;
138 * mono_thread_set_main:
139 * @thread: thread to set as the main thread
141 * This function can be used to instruct the runtime to treat @thread
142 * as the main thread, ie, the thread that would normally execute the Main()
143 * method. This basically means that at the end of @thread, the runtime will
144 * wait for the existing foreground threads to quit and other such details.
147 mono_thread_set_main (MonoThread *thread)
149 main_thread = thread;
153 mono_thread_get_main (void)
159 mono_type_initialization_init (void)
161 InitializeCriticalSection (&type_initialization_section);
162 type_initialization_hash = g_hash_table_new (NULL, NULL);
163 blocked_thread_hash = g_hash_table_new (NULL, NULL);
164 InitializeCriticalSection (&ldstr_section);
168 mono_type_initialization_cleanup (void)
171 /* This is causing race conditions with
172 * mono_release_type_locks
174 DeleteCriticalSection (&type_initialization_section);
176 DeleteCriticalSection (&ldstr_section);
180 * get_type_init_exception_for_vtable:
182 * Return the stored type initialization exception for VTABLE.
184 static MonoException*
185 get_type_init_exception_for_vtable (MonoVTable *vtable)
187 MonoDomain *domain = vtable->domain;
188 MonoClass *klass = vtable->klass;
192 g_assert (vtable->init_failed);
195 * If the initializing thread was rudely aborted, the exception is not stored
199 mono_domain_lock (domain);
200 if (domain->type_init_exception_hash)
201 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
202 mono_domain_unlock (domain);
205 if (klass->name_space && *klass->name_space)
206 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
208 full_name = g_strdup (klass->name);
209 ex = mono_get_exception_type_initialization (full_name, NULL);
217 * mono_runtime_class_init:
218 * @vtable: vtable that needs to be initialized
220 * This routine calls the class constructor for @vtable.
223 mono_runtime_class_init (MonoVTable *vtable)
226 MonoException *exc_to_throw;
227 MonoMethod *method = NULL;
233 if (vtable->initialized)
237 klass = vtable->klass;
239 if (!klass->image->checked_module_cctor) {
240 mono_image_check_for_module_cctor (klass->image);
241 if (klass->image->has_module_cctor) {
242 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
243 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
246 method = mono_class_get_cctor (klass);
249 MonoDomain *domain = vtable->domain;
250 TypeInitializationLock *lock;
251 guint32 tid = GetCurrentThreadId();
252 int do_initialization = 0;
253 MonoDomain *last_domain = NULL;
255 mono_type_initialization_lock ();
256 /* double check... */
257 if (vtable->initialized) {
258 mono_type_initialization_unlock ();
261 if (vtable->init_failed) {
262 mono_type_initialization_unlock ();
264 /* The type initialization already failed once, rethrow the same exception */
265 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
268 lock = g_hash_table_lookup (type_initialization_hash, vtable);
270 /* This thread will get to do the initialization */
271 if (mono_domain_get () != domain) {
272 /* Transfer into the target domain */
273 last_domain = mono_domain_get ();
274 if (!mono_domain_set (domain, FALSE)) {
275 vtable->initialized = 1;
276 mono_type_initialization_unlock ();
277 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
280 lock = g_malloc (sizeof(TypeInitializationLock));
281 InitializeCriticalSection (&lock->initialization_section);
282 lock->initializing_tid = tid;
283 lock->waiting_count = 1;
285 /* grab the vtable lock while this thread still owns type_initialization_section */
286 EnterCriticalSection (&lock->initialization_section);
287 g_hash_table_insert (type_initialization_hash, vtable, lock);
288 do_initialization = 1;
291 TypeInitializationLock *pending_lock;
293 if (lock->initializing_tid == tid || lock->done) {
294 mono_type_initialization_unlock ();
297 /* see if the thread doing the initialization is already blocked on this thread */
298 blocked = GUINT_TO_POINTER (lock->initializing_tid);
299 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
300 if (pending_lock->initializing_tid == tid) {
301 if (!pending_lock->done) {
302 mono_type_initialization_unlock ();
305 /* the thread doing the initialization is blocked on this thread,
306 but on a lock that has already been freed. It just hasn't got
311 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
313 ++lock->waiting_count;
314 /* record the fact that we are waiting on the initializing thread */
315 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
317 mono_type_initialization_unlock ();
319 if (do_initialization) {
320 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
322 /* If the initialization failed, mark the class as unusable. */
323 /* Avoid infinite loops */
325 (klass->image == mono_defaults.corlib &&
326 !strcmp (klass->name_space, "System") &&
327 !strcmp (klass->name, "TypeInitializationException")))) {
328 vtable->init_failed = 1;
330 if (klass->name_space && *klass->name_space)
331 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
333 full_name = g_strdup (klass->name);
334 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
338 * Store the exception object so it could be thrown on subsequent
341 mono_domain_lock (domain);
342 if (!domain->type_init_exception_hash)
343 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
344 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
345 mono_domain_unlock (domain);
349 mono_domain_set (last_domain, TRUE);
351 LeaveCriticalSection (&lock->initialization_section);
353 /* this just blocks until the initializing thread is done */
354 EnterCriticalSection (&lock->initialization_section);
355 LeaveCriticalSection (&lock->initialization_section);
358 mono_type_initialization_lock ();
359 if (lock->initializing_tid != tid)
360 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
361 --lock->waiting_count;
362 if (lock->waiting_count == 0) {
363 DeleteCriticalSection (&lock->initialization_section);
364 g_hash_table_remove (type_initialization_hash, vtable);
367 if (!vtable->init_failed)
368 vtable->initialized = 1;
369 mono_type_initialization_unlock ();
371 if (vtable->init_failed) {
372 /* Either we were the initializing thread or we waited for the initialization */
373 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
376 vtable->initialized = 1;
382 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
384 MonoVTable *vtable = (MonoVTable*)key;
386 TypeInitializationLock *lock = (TypeInitializationLock*) value;
387 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
390 * Have to set this since it cannot be set by the normal code in
391 * mono_runtime_class_init (). In this case, the exception object is not stored,
392 * and get_type_init_exception_for_class () needs to be aware of this.
394 vtable->init_failed = 1;
395 LeaveCriticalSection (&lock->initialization_section);
396 --lock->waiting_count;
397 if (lock->waiting_count == 0) {
398 DeleteCriticalSection (&lock->initialization_section);
407 mono_release_type_locks (MonoThread *thread)
409 mono_type_initialization_lock ();
410 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
411 mono_type_initialization_unlock ();
415 default_trampoline (MonoMethod *method)
421 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
423 g_assert_not_reached ();
429 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
431 g_error ("remoting not installed");
436 default_delegate_trampoline (MonoClass *klass)
438 g_assert_not_reached ();
442 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
443 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
444 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
445 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
446 static MonoImtThunkBuilder imt_thunk_builder = NULL;
447 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
448 #if (MONO_IMT_SIZE > 32)
449 #error "MONO_IMT_SIZE cannot be larger than 32"
453 mono_install_trampoline (MonoTrampoline func)
455 arch_create_jit_trampoline = func? func: default_trampoline;
459 mono_install_jump_trampoline (MonoJumpTrampoline func)
461 arch_create_jump_trampoline = func? func: default_jump_trampoline;
465 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
467 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
471 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
473 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
477 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
478 imt_thunk_builder = func;
481 static MonoCompileFunc default_mono_compile_method = NULL;
484 * mono_install_compile_method:
485 * @func: function to install
487 * This is a VM internal routine
490 mono_install_compile_method (MonoCompileFunc func)
492 default_mono_compile_method = func;
496 * mono_compile_method:
497 * @method: The method to compile.
499 * This JIT-compiles the method, and returns the pointer to the native code
503 mono_compile_method (MonoMethod *method)
505 if (!default_mono_compile_method) {
506 g_error ("compile method called on uninitialized runtime");
509 return default_mono_compile_method (method);
513 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
515 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
519 mono_runtime_create_delegate_trampoline (MonoClass *klass)
521 return arch_create_delegate_trampoline (klass);
524 static MonoFreeMethodFunc default_mono_free_method = NULL;
527 * mono_install_free_method:
528 * @func: pointer to the MonoFreeMethodFunc used to release a method
530 * This is an internal VM routine, it is used for the engines to
531 * register a handler to release the resources associated with a method.
533 * Methods are freed when no more references to the delegate that holds
537 mono_install_free_method (MonoFreeMethodFunc func)
539 default_mono_free_method = func;
543 * mono_runtime_free_method:
544 * @domain; domain where the method is hosted
545 * @method: method to release
547 * This routine is invoked to free the resources associated with
548 * a method that has been JIT compiled. This is used to discard
549 * methods that were used only temporarily (for example, used in marshalling)
553 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
555 if (default_mono_free_method != NULL)
556 default_mono_free_method (domain, method);
558 mono_free_method (method);
561 static MonoInitVTableFunc init_vtable_func = NULL;
564 * mono_install_init_vtable:
565 * @func: pointer to the function to be installed
567 * Register a function which will be called by the runtime to initialize the
568 * method pointers inside a vtable. The JIT can use this function to load the
569 * vtable from the AOT file for example.
572 mono_install_init_vtable (MonoInitVTableFunc func)
574 init_vtable_func = func;
578 * The vtables in the root appdomain are assumed to be reachable by other
579 * roots, and we don't use typed allocation in the other domains.
582 /* The sync block is no longer a GC pointer */
583 #define GC_HEADER_BITMAP (0)
585 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
588 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
590 MonoClassField *field;
596 max_size = mono_class_data_size (class) / sizeof (gpointer);
598 max_size = class->instance_size / sizeof (gpointer);
599 if (max_size >= size) {
600 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
603 for (p = class; p != NULL; p = p->parent) {
604 gpointer iter = NULL;
605 while ((field = mono_class_get_fields (p, &iter))) {
609 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
612 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
615 /* FIXME: should not happen, flag as type load error */
616 if (field->type->byref)
619 pos = field->offset / sizeof (gpointer);
622 type = mono_type_get_underlying_type (field->type);
623 switch (type->type) {
626 case MONO_TYPE_FNPTR:
628 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
633 if (class->image != mono_defaults.corlib)
636 case MONO_TYPE_STRING:
637 case MONO_TYPE_SZARRAY:
638 case MONO_TYPE_CLASS:
639 case MONO_TYPE_OBJECT:
640 case MONO_TYPE_ARRAY:
641 g_assert ((field->offset % sizeof(gpointer)) == 0);
643 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
644 *max_set = MAX (*max_set, pos);
646 case MONO_TYPE_GENERICINST:
647 if (!mono_type_generic_inst_is_valuetype (type)) {
648 g_assert ((field->offset % sizeof(gpointer)) == 0);
650 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
651 *max_set = MAX (*max_set, pos);
656 case MONO_TYPE_VALUETYPE: {
657 MonoClass *fclass = mono_class_from_mono_type (field->type);
658 if (fclass->has_references) {
659 /* remove the object header */
660 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
674 case MONO_TYPE_BOOLEAN:
678 g_assert_not_reached ();
690 * similar to the above, but sets the bits in the bitmap for any non-ref field
691 * and ignores static fields
694 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
696 MonoClassField *field;
701 max_size = class->instance_size / sizeof (gpointer);
702 if (max_size >= size) {
703 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
706 for (p = class; p != NULL; p = p->parent) {
707 gpointer iter = NULL;
708 while ((field = mono_class_get_fields (p, &iter))) {
711 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
713 /* FIXME: should not happen, flag as type load error */
714 if (field->type->byref)
717 pos = field->offset / sizeof (gpointer);
720 type = mono_type_get_underlying_type (field->type);
721 switch (type->type) {
722 #if SIZEOF_VOID_P == 8
726 case MONO_TYPE_FNPTR:
731 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
732 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
733 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
736 #if SIZEOF_VOID_P == 4
740 case MONO_TYPE_FNPTR:
745 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
746 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
747 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
753 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
754 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
755 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
758 case MONO_TYPE_BOOLEAN:
761 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
763 case MONO_TYPE_STRING:
764 case MONO_TYPE_SZARRAY:
765 case MONO_TYPE_CLASS:
766 case MONO_TYPE_OBJECT:
767 case MONO_TYPE_ARRAY:
769 case MONO_TYPE_GENERICINST:
770 if (!mono_type_generic_inst_is_valuetype (type)) {
775 case MONO_TYPE_VALUETYPE: {
776 MonoClass *fclass = mono_class_from_mono_type (field->type);
777 /* remove the object header */
778 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
782 g_assert_not_reached ();
791 * mono_class_insecure_overlapping:
792 * check if a class with explicit layout has references and non-references
793 * fields overlapping.
795 * Returns: TRUE if it is insecure to load the type.
798 mono_class_insecure_overlapping (MonoClass *klass)
802 gsize default_bitmap [4] = {0};
804 gsize default_nrbitmap [4] = {0};
805 int i, insecure = FALSE;
808 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
809 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
811 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
812 int idx = i % (sizeof (bitmap [0]) * 8);
813 if (bitmap [idx] & nrbitmap [idx]) {
818 if (bitmap != default_bitmap)
820 if (nrbitmap != default_nrbitmap)
823 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
831 mono_string_alloc (int length)
833 return mono_string_new_size (mono_domain_get (), length);
837 mono_class_compute_gc_descriptor (MonoClass *class)
841 gsize default_bitmap [4] = {0};
842 static gboolean gcj_inited = FALSE;
847 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
848 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
849 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
850 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
852 #ifdef HAVE_GC_GCJ_MALLOC
854 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
858 #ifdef GC_REDIRECT_TO_LOCAL
859 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
860 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
862 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
863 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
868 mono_loader_unlock ();
872 mono_class_init (class);
874 if (class->gc_descr_inited)
877 class->gc_descr_inited = TRUE;
878 class->gc_descr = GC_NO_DESCRIPTOR;
880 bitmap = default_bitmap;
881 if (class == mono_defaults.string_class) {
882 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
883 } else if (class->rank) {
884 mono_class_compute_gc_descriptor (class->element_class);
885 if (!class->element_class->valuetype) {
887 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
888 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
889 class->name_space, class->name);*/
891 /* remove the object header */
892 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
893 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
894 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
895 class->name_space, class->name);*/
896 if (bitmap != default_bitmap)
900 /*static int count = 0;
903 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
904 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
906 if (class->gc_descr == GC_NO_DESCRIPTOR)
907 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
909 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
910 if (bitmap != default_bitmap)
916 * field_is_special_static:
917 * @fklass: The MonoClass to look up.
918 * @field: The MonoClassField describing the field.
920 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
921 * SPECIAL_STATIC_NONE otherwise.
924 field_is_special_static (MonoClass *fklass, MonoClassField *field)
926 MonoCustomAttrInfo *ainfo;
928 ainfo = mono_custom_attrs_from_field (fklass, field);
931 for (i = 0; i < ainfo->num_attrs; ++i) {
932 MonoClass *klass = ainfo->attrs [i].ctor->klass;
933 if (klass->image == mono_defaults.corlib) {
934 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
935 mono_custom_attrs_free (ainfo);
936 return SPECIAL_STATIC_THREAD;
938 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
939 mono_custom_attrs_free (ainfo);
940 return SPECIAL_STATIC_CONTEXT;
944 mono_custom_attrs_free (ainfo);
945 return SPECIAL_STATIC_NONE;
948 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
949 #define mix(a,b,c) { \
950 a -= c; a ^= rot(c, 4); c += b; \
951 b -= a; b ^= rot(a, 6); a += c; \
952 c -= b; c ^= rot(b, 8); b += a; \
953 a -= c; a ^= rot(c,16); c += b; \
954 b -= a; b ^= rot(a,19); a += c; \
955 c -= b; c ^= rot(b, 4); b += a; \
957 #define final(a,b,c) { \
958 c ^= b; c -= rot(b,14); \
959 a ^= c; a -= rot(c,11); \
960 b ^= a; b -= rot(a,25); \
961 c ^= b; c -= rot(b,16); \
962 a ^= c; a -= rot(c,4); \
963 b ^= a; b -= rot(a,14); \
964 c ^= b; c -= rot(b,24); \
968 mono_method_get_imt_slot (MonoMethod *method) {
969 MonoMethodSignature *sig = mono_method_signature (method);
970 int hashes_count = sig->param_count + 4;
971 guint32 *hashes_start = malloc (hashes_count * sizeof (guint32));
972 guint32 *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.
1291 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1293 MonoClassRuntimeInfo *runtime_info;
1297 /* this check can be inlined in jitted code, too */
1298 runtime_info = class->runtime_info;
1299 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1300 return runtime_info->domain_vtables [domain->domain_id];
1301 return mono_class_create_runtime_vtable (domain, class);
1305 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1308 MonoClassRuntimeInfo *runtime_info, *old_info;
1309 MonoClassField *field;
1312 int imt_table_bytes = 0;
1313 gboolean inited = FALSE;
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);
1338 /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
1339 if (class->image->dynamic)
1340 mono_class_setup_vtable (class);
1343 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1344 if (class->interface_offsets_count) {
1345 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1346 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1347 mono_stats.imt_number_of_tables++;
1348 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1351 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1352 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1355 mono_stats.used_class_count++;
1356 mono_stats.class_vtable_size += vtable_size;
1357 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1360 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1362 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1364 vt->rank = class->rank;
1365 vt->domain = domain;
1367 mono_class_compute_gc_descriptor (class);
1369 * We can't use typed allocation in the non-root domains, since the
1370 * collector needs the GC descriptor stored in the vtable even after
1371 * the mempool containing the vtable is destroyed when the domain is
1372 * unloaded. An alternative might be to allocate vtables in the GC
1373 * heap, but this does not seem to work (it leads to crashes inside
1374 * libgc). If that approach is tried, two gc descriptors need to be
1375 * allocated for each class: one for the root domain, and one for all
1376 * other domains. The second descriptor should contain a bit for the
1377 * vtable field in MonoObject, since we can no longer assume the
1378 * vtable is reachable by other roots after the appdomain is unloaded.
1380 #ifdef HAVE_BOEHM_GC
1381 if (domain != mono_get_root_domain ())
1382 vt->gc_descr = GC_NO_DESCRIPTOR;
1385 vt->gc_descr = class->gc_descr;
1387 if ((class_size = mono_class_data_size (class))) {
1388 if (class->has_static_refs) {
1389 gpointer statics_gc_descr;
1391 gsize default_bitmap [4] = {0};
1394 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1395 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1396 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1397 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1398 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1399 if (bitmap != default_bitmap)
1402 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1404 mono_stats.class_static_data_size += class_size;
1409 while ((field = mono_class_get_fields (class, &iter))) {
1410 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1412 if (mono_field_is_deleted (field))
1414 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1415 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1416 if (special_static != SPECIAL_STATIC_NONE) {
1417 guint32 size, offset;
1419 size = mono_type_size (field->type, &align);
1420 offset = mono_alloc_special_static_data (special_static, size, align);
1421 if (!domain->special_static_fields)
1422 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1423 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1427 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1428 MonoClass *fklass = mono_class_from_mono_type (field->type);
1429 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1430 t = (char*)vt->data + field->offset;
1431 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1434 if (fklass->valuetype) {
1435 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1437 /* it's a pointer type: add check */
1438 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1439 *t = *(char *)field->data;
1443 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1446 /* later do this only on demand if needed */
1448 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1450 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1452 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1453 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1454 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1459 vt->max_interface_id = class->max_interface_id;
1460 vt->interface_bitmap = class->interface_bitmap;
1462 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1463 // class->name, class->interface_offsets_count);
1465 if (! ARCH_USE_IMT) {
1466 /* initialize interface offsets */
1467 for (i = 0; i < class->interface_offsets_count; ++i) {
1468 int interface_id = class->interfaces_packed [i]->interface_id;
1469 int slot = class->interface_offsets_packed [i];
1470 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1475 * arch_create_jit_trampoline () can recursively call this function again
1476 * because it compiles icall methods right away.
1478 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1479 * as we change the code in appdomain.c to invalidate vtables by
1480 * looking at the possible MonoClasses created for the domain.
1482 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1483 /* class->runtime_info is protected by the loader lock, both when
1484 * it it enlarged and when it is stored info.
1486 mono_loader_lock ();
1487 old_info = class->runtime_info;
1488 if (old_info && old_info->max_domain >= domain->domain_id) {
1489 /* someone already created a large enough runtime info */
1490 old_info->domain_vtables [domain->domain_id] = vt;
1492 int new_size = domain->domain_id;
1494 new_size = MAX (new_size, old_info->max_domain);
1496 /* make the new size a power of two */
1498 while (new_size > i)
1501 /* this is a bounded memory retention issue: may want to
1502 * handle it differently when we'll have a rcu-like system.
1504 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1505 runtime_info->max_domain = new_size - 1;
1506 /* copy the stuff from the older info */
1508 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1510 runtime_info->domain_vtables [domain->domain_id] = vt;
1511 /* keep this last (add membarrier) */
1512 class->runtime_info = runtime_info;
1514 mono_loader_unlock ();
1516 /* initialize vtable */
1517 if (init_vtable_func)
1518 inited = init_vtable_func (vt);
1521 mono_class_setup_vtable (class);
1523 for (i = 0; i < class->vtable_size; ++i) {
1526 if ((cm = class->vtable [i])) {
1527 if (mono_method_signature (cm)->generic_param_count)
1528 vt->vtable [i] = cm;
1530 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1535 if (ARCH_USE_IMT && imt_table_bytes) {
1536 /* Now that the vtable is full, we can actually fill up the IMT */
1537 if (imt_trampoline) {
1538 /* lazy construction of the IMT entries enabled */
1539 for (i = 0; i < MONO_IMT_SIZE; ++i)
1540 interface_offsets [i] = imt_trampoline;
1542 build_imt (class, vt, domain, interface_offsets, NULL);
1546 mono_domain_unlock (domain);
1548 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1549 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1550 MonoException *exc = mono_class_get_exception_for_failure (class);
1552 mono_raise_exception (exc);
1555 /* make sure the the parent is initialized */
1557 mono_class_vtable (domain, class->parent);
1559 vt->type = mono_type_get_object (domain, &class->byval_arg);
1560 if (class->contextbound)
1569 * mono_class_proxy_vtable:
1570 * @domain: the application domain
1571 * @remove_class: the remote class
1573 * Creates a vtable for transparent proxies. It is basically
1574 * a copy of the real vtable of the class wrapped in @remote_class,
1575 * but all function pointers invoke the remoting functions, and
1576 * vtable->klass points to the transparent proxy class, and not to @class.
1579 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1581 MonoVTable *vt, *pvt;
1582 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1584 GSList *extra_interfaces = NULL;
1585 MonoClass *class = remote_class->proxy_class;
1586 gpointer *interface_offsets;
1588 vt = mono_class_vtable (domain, class);
1589 max_interface_id = vt->max_interface_id;
1591 /* Calculate vtable space for extra interfaces */
1592 for (j = 0; j < remote_class->interface_count; j++) {
1593 MonoClass* iclass = remote_class->interfaces[j];
1597 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1598 continue; /* interface implemented by the class */
1599 if (g_slist_find (extra_interfaces, iclass))
1602 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1604 method_count = mono_class_num_methods (iclass);
1606 ifaces = mono_class_get_implemented_interfaces (iclass);
1608 for (i = 0; i < ifaces->len; ++i) {
1609 MonoClass *ic = g_ptr_array_index (ifaces, i);
1610 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1611 continue; /* interface implemented by the class */
1612 if (g_slist_find (extra_interfaces, ic))
1614 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1615 method_count += mono_class_num_methods (ic);
1617 g_ptr_array_free (ifaces, TRUE);
1620 extra_interface_vtsize += method_count * sizeof (gpointer);
1621 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1625 mono_stats.imt_number_of_tables++;
1626 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1627 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1628 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1630 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1631 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1634 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1636 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1638 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1640 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1641 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1643 pvt->klass = mono_defaults.transparent_proxy_class;
1644 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1645 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1647 /* initialize vtable */
1648 mono_class_setup_vtable (class);
1649 for (i = 0; i < class->vtable_size; ++i) {
1652 if ((cm = class->vtable [i]))
1653 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1654 ? cm : arch_create_remoting_trampoline (cm, target_type);
1657 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1658 /* create trampolines for abstract methods */
1659 for (k = class; k; k = k->parent) {
1661 gpointer iter = NULL;
1662 while ((m = mono_class_get_methods (k, &iter)))
1663 if (!pvt->vtable [m->slot])
1664 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1668 pvt->max_interface_id = max_interface_id;
1669 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1671 if (! ARCH_USE_IMT) {
1672 /* initialize interface offsets */
1673 for (i = 0; i < class->interface_offsets_count; ++i) {
1674 int interface_id = class->interfaces_packed [i]->interface_id;
1675 int slot = class->interface_offsets_packed [i];
1676 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1679 for (i = 0; i < class->interface_offsets_count; ++i) {
1680 int interface_id = class->interfaces_packed [i]->interface_id;
1681 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1684 if (extra_interfaces) {
1685 int slot = class->vtable_size;
1691 /* Create trampolines for the methods of the interfaces */
1692 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1693 interf = list_item->data;
1695 if (! ARCH_USE_IMT) {
1696 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1698 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1702 while ((cm = mono_class_get_methods (interf, &iter)))
1703 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1705 slot += mono_class_num_methods (interf);
1707 if (! ARCH_USE_IMT) {
1708 g_slist_free (extra_interfaces);
1713 /* Now that the vtable is full, we can actually fill up the IMT */
1714 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1715 if (extra_interfaces) {
1716 g_slist_free (extra_interfaces);
1724 * mono_class_has_special_static_fields:
1726 * Returns whenever @klass has any thread/context static fields.
1729 mono_class_has_special_static_fields (MonoClass *klass)
1731 MonoClassField *field;
1735 while ((field = mono_class_get_fields (klass, &iter))) {
1736 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1738 if (mono_field_is_deleted (field))
1740 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1741 if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
1750 * create_remote_class_key:
1751 * Creates an array of pointers that can be used as a hash key for a remote class.
1752 * The first element of the array is the number of pointers.
1755 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1760 if (remote_class == NULL) {
1761 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1762 key = g_malloc (sizeof(gpointer) * 3);
1763 key [0] = GINT_TO_POINTER (2);
1764 key [1] = mono_defaults.marshalbyrefobject_class;
1765 key [2] = extra_class;
1767 key = g_malloc (sizeof(gpointer) * 2);
1768 key [0] = GINT_TO_POINTER (1);
1769 key [1] = extra_class;
1772 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1773 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1774 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1775 key [1] = remote_class->proxy_class;
1777 // Keep the list of interfaces sorted
1778 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1779 if (extra_class && remote_class->interfaces [i] > extra_class) {
1780 key [j++] = extra_class;
1783 key [j] = remote_class->interfaces [i];
1786 key [j] = extra_class;
1788 // Replace the old class. The interface list is the same
1789 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1790 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1791 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1792 for (i = 0; i < remote_class->interface_count; i++)
1793 key [2 + i] = remote_class->interfaces [i];
1801 * copy_remote_class_key:
1803 * Make a copy of KEY in the mempool MP and return the copy.
1806 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1808 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1809 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1811 memcpy (mp_key, key, key_size);
1817 * mono_remote_class:
1818 * @domain: the application domain
1819 * @class_name: name of the remote class
1821 * Creates and initializes a MonoRemoteClass object for a remote type.
1825 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1827 MonoRemoteClass *rc;
1828 gpointer* key, *mp_key;
1830 key = create_remote_class_key (NULL, proxy_class);
1832 mono_domain_lock (domain);
1833 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1837 mono_domain_unlock (domain);
1841 mp_key = copy_remote_class_key (domain->mp, key);
1845 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1846 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1847 rc->interface_count = 1;
1848 rc->interfaces [0] = proxy_class;
1849 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1851 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1852 rc->interface_count = 0;
1853 rc->proxy_class = proxy_class;
1856 rc->default_vtable = NULL;
1857 rc->xdomain_vtable = NULL;
1858 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1860 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1862 mono_domain_unlock (domain);
1867 * clone_remote_class:
1868 * Creates a copy of the remote_class, adding the provided class or interface
1870 static MonoRemoteClass*
1871 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1873 MonoRemoteClass *rc;
1874 gpointer* key, *mp_key;
1876 key = create_remote_class_key (remote_class, extra_class);
1877 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1883 mp_key = copy_remote_class_key (domain->mp, key);
1887 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1889 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1890 rc->proxy_class = remote_class->proxy_class;
1891 rc->interface_count = remote_class->interface_count + 1;
1893 // Keep the list of interfaces sorted, since the hash key of
1894 // the remote class depends on this
1895 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1896 if (remote_class->interfaces [i] > extra_class && i == j)
1897 rc->interfaces [j++] = extra_class;
1898 rc->interfaces [j] = remote_class->interfaces [i];
1901 rc->interfaces [j] = extra_class;
1903 // Replace the old class. The interface array is the same
1904 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1905 rc->proxy_class = extra_class;
1906 rc->interface_count = remote_class->interface_count;
1907 if (rc->interface_count > 0)
1908 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1911 rc->default_vtable = NULL;
1912 rc->xdomain_vtable = NULL;
1913 rc->proxy_class_name = remote_class->proxy_class_name;
1915 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1921 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1923 mono_domain_lock (domain);
1924 if (rp->target_domain_id != -1) {
1925 if (remote_class->xdomain_vtable == NULL)
1926 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1927 mono_domain_unlock (domain);
1928 return remote_class->xdomain_vtable;
1930 if (remote_class->default_vtable == NULL) {
1933 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1934 klass = mono_class_from_mono_type (type);
1935 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1936 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1938 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1941 mono_domain_unlock (domain);
1942 return remote_class->default_vtable;
1946 * mono_upgrade_remote_class:
1947 * @domain: the application domain
1948 * @tproxy: the proxy whose remote class has to be upgraded.
1949 * @klass: class to which the remote class can be casted.
1951 * Updates the vtable of the remote class by adding the necessary method slots
1952 * and interface offsets so it can be safely casted to klass. klass can be a
1953 * class or an interface.
1956 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1958 MonoTransparentProxy *tproxy;
1959 MonoRemoteClass *remote_class;
1960 gboolean redo_vtable;
1962 mono_domain_lock (domain);
1964 tproxy = (MonoTransparentProxy*) proxy_object;
1965 remote_class = tproxy->remote_class;
1967 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1970 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1971 if (remote_class->interfaces [i] == klass)
1972 redo_vtable = FALSE;
1975 redo_vtable = (remote_class->proxy_class != klass);
1979 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1980 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1983 mono_domain_unlock (domain);
1988 * mono_object_get_virtual_method:
1989 * @obj: object to operate on.
1992 * Retrieves the MonoMethod that would be called on obj if obj is passed as
1993 * the instance of a callvirt of method.
1996 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1999 MonoMethod **vtable;
2001 MonoMethod *res = NULL;
2003 klass = mono_object_class (obj);
2004 if (klass == mono_defaults.transparent_proxy_class) {
2005 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2011 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2014 mono_class_setup_vtable (klass);
2015 vtable = klass->vtable;
2017 /* check method->slot is a valid index: perform isinstance? */
2018 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2020 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2022 if (method->slot != -1)
2023 res = vtable [method->slot];
2027 /* It may be an interface, abstract class method or generic method */
2028 if (!res || mono_method_signature (res)->generic_param_count)
2031 /* generic methods demand invoke_with_check */
2032 if (mono_method_signature (res)->generic_param_count)
2033 res = mono_marshal_get_remoting_invoke_with_check (res);
2035 res = mono_marshal_get_remoting_invoke (res);
2044 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2046 g_error ("runtime invoke called on uninitialized runtime");
2050 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2053 * mono_runtime_invoke:
2054 * @method: method to invoke
2055 * @obJ: object instance
2056 * @params: arguments to the method
2057 * @exc: exception information.
2059 * Invokes the method represented by @method on the object @obj.
2061 * obj is the 'this' pointer, it should be NULL for static
2062 * methods, a MonoObject* for object instances and a pointer to
2063 * the value type for value types.
2065 * The params array contains the arguments to the method with the
2066 * same convention: MonoObject* pointers for object instances and
2067 * pointers to the value type otherwise.
2069 * From unmanaged code you'll usually use the
2070 * mono_runtime_invoke() variant.
2072 * Note that this function doesn't handle virtual methods for
2073 * you, it will exec the exact method you pass: we still need to
2074 * expose a function to lookup the derived class implementation
2075 * of a virtual method (there are examples of this in the code,
2078 * You can pass NULL as the exc argument if you don't want to
2079 * catch exceptions, otherwise, *exc will be set to the exception
2080 * thrown, if any. if an exception is thrown, you can't use the
2081 * MonoObject* result from the function.
2083 * If the method returns a value type, it is boxed in an object
2087 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2089 return default_mono_runtime_invoke (method, obj, params, exc);
2093 * mono_method_get_unmanaged_thunk:
2094 * @method: method to generate a thunk for.
2096 * Returns an unmanaged->managed thunk that can be used to call
2097 * a managed method directly from C.
2099 * The thunk's C signature closely matches the managed signature:
2101 * C#: public bool Equals (object obj);
2102 * C: typedef MonoBoolean (*Equals)(MonoObject *this,
2103 * MonoObject *obj, MonoException **ex);
2105 * The "this" parameter must not be used with static methods:
2107 * C#: public static bool ReferenceEquals (object a, object b);
2108 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject *a, MonoObject *b,
2109 * MonoException **ex);
2111 * The last argument must be a non-null pointer of a MonoException* pointer.
2112 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2113 * exception has been thrown in managed code. Otherwise, it will point
2114 * to the MonoException* caught by the thunk. In this case, the result of
2115 * the thunk is undefined:
2117 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2118 * MonoException *ex = NULL;
2119 * Equals func = mono_method_get_unmanaged_thunk (method);
2120 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2122 * // handle exception
2125 * The calling convention of the thunk matches the platform's default
2126 * convention. This means that under Windows, C declarations must
2127 * contain the __stdcall attribute:
2129 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject *this,
2130 * MonoObject *obj, MonoException **ex);
2133 mono_method_get_unmanaged_thunk (MonoMethod *method)
2135 method = mono_marshal_get_thunk_invoke_wrapper (method);
2136 return mono_compile_method (method);
2140 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2144 gpointer *p = (gpointer*)dest;
2151 case MONO_TYPE_BOOLEAN:
2153 case MONO_TYPE_U1: {
2154 guint8 *p = (guint8*)dest;
2155 *p = value ? *(guint8*)value : 0;
2160 case MONO_TYPE_CHAR: {
2161 guint16 *p = (guint16*)dest;
2162 *p = value ? *(guint16*)value : 0;
2165 #if SIZEOF_VOID_P == 4
2170 case MONO_TYPE_U4: {
2171 gint32 *p = (gint32*)dest;
2172 *p = value ? *(gint32*)value : 0;
2175 #if SIZEOF_VOID_P == 8
2180 case MONO_TYPE_U8: {
2181 gint64 *p = (gint64*)dest;
2182 *p = value ? *(gint64*)value : 0;
2185 case MONO_TYPE_R4: {
2186 float *p = (float*)dest;
2187 *p = value ? *(float*)value : 0;
2190 case MONO_TYPE_R8: {
2191 double *p = (double*)dest;
2192 *p = value ? *(double*)value : 0;
2195 case MONO_TYPE_STRING:
2196 case MONO_TYPE_SZARRAY:
2197 case MONO_TYPE_CLASS:
2198 case MONO_TYPE_OBJECT:
2199 case MONO_TYPE_ARRAY:
2200 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2202 case MONO_TYPE_FNPTR:
2203 case MONO_TYPE_PTR: {
2204 gpointer *p = (gpointer*)dest;
2205 *p = deref_pointer? *(gpointer*)value: value;
2208 case MONO_TYPE_VALUETYPE:
2209 /* note that 't' and 'type->type' can be different */
2210 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2211 t = type->data.klass->enum_basetype->type;
2215 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2217 memset (dest, 0, size);
2219 memcpy (dest, value, size);
2222 case MONO_TYPE_GENERICINST:
2223 t = type->data.generic_class->container_class->byval_arg.type;
2226 g_warning ("got type %x", type->type);
2227 g_assert_not_reached ();
2232 * mono_field_set_value:
2233 * @obj: Instance object
2234 * @field: MonoClassField describing the field to set
2235 * @value: The value to be set
2237 * Sets the value of the field described by @field in the object instance @obj
2238 * to the value passed in @value. This method should only be used for instance
2239 * fields. For static fields, use mono_field_static_set_value.
2241 * The value must be on the native format of the field type.
2244 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2248 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2250 dest = (char*)obj + field->offset;
2251 set_value (field->type, dest, value, FALSE);
2255 * mono_field_static_set_value:
2256 * @field: MonoClassField describing the field to set
2257 * @value: The value to be set
2259 * Sets the value of the static field described by @field
2260 * to the value passed in @value.
2262 * The value must be on the native format of the field type.
2265 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2269 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2270 /* you cant set a constant! */
2271 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2273 dest = (char*)vt->data + field->offset;
2274 set_value (field->type, dest, value, FALSE);
2277 /* Used by the debugger */
2279 mono_vtable_get_static_field_data (MonoVTable *vt)
2285 * mono_field_get_value:
2286 * @obj: Object instance
2287 * @field: MonoClassField describing the field to fetch information from
2288 * @value: pointer to the location where the value will be stored
2290 * Use this routine to get the value of the field @field in the object
2293 * The pointer provided by value must be of the field type, for reference
2294 * types this is a MonoObject*, for value types its the actual pointer to
2299 * mono_field_get_value (obj, int_field, &i);
2302 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2306 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2308 src = (char*)obj + field->offset;
2309 set_value (field->type, value, src, TRUE);
2313 * mono_field_get_value_object:
2314 * @domain: domain where the object will be created (if boxing)
2315 * @field: MonoClassField describing the field to fetch information from
2316 * @obj: The object instance for the field.
2318 * Returns: a new MonoObject with the value from the given field. If the
2319 * field represents a value type, the value is boxed.
2323 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2327 MonoVTable *vtable = NULL;
2329 gboolean is_static = FALSE;
2330 gboolean is_ref = FALSE;
2332 switch (field->type->type) {
2333 case MONO_TYPE_STRING:
2334 case MONO_TYPE_OBJECT:
2335 case MONO_TYPE_CLASS:
2336 case MONO_TYPE_ARRAY:
2337 case MONO_TYPE_SZARRAY:
2342 case MONO_TYPE_BOOLEAN:
2345 case MONO_TYPE_CHAR:
2354 case MONO_TYPE_VALUETYPE:
2355 is_ref = field->type->byref;
2357 case MONO_TYPE_GENERICINST:
2358 is_ref = !field->type->data.generic_class->container_class->valuetype;
2361 g_error ("type 0x%x not handled in "
2362 "mono_field_get_value_object", field->type->type);
2366 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2368 vtable = mono_class_vtable (domain, field->parent);
2369 if (!vtable->initialized)
2370 mono_runtime_class_init (vtable);
2375 mono_field_static_get_value (vtable, field, &o);
2377 mono_field_get_value (obj, field, &o);
2382 /* boxed value type */
2383 klass = mono_class_from_mono_type (field->type);
2384 o = mono_object_new (domain, klass);
2385 v = ((gchar *) o) + sizeof (MonoObject);
2387 mono_field_static_get_value (vtable, field, v);
2389 mono_field_get_value (obj, field, v);
2396 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2399 const char *p = blob;
2400 mono_metadata_decode_blob_size (p, &p);
2403 case MONO_TYPE_BOOLEAN:
2406 *(guint8 *) value = *p;
2408 case MONO_TYPE_CHAR:
2411 *(guint16*) value = read16 (p);
2415 *(guint32*) value = read32 (p);
2419 *(guint64*) value = read64 (p);
2422 readr4 (p, (float*) value);
2425 readr8 (p, (double*) value);
2427 case MONO_TYPE_STRING:
2428 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2430 case MONO_TYPE_CLASS:
2431 *(gpointer*) value = NULL;
2435 g_warning ("type 0x%02x should not be in constant table", type);
2441 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2443 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2444 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2448 * mono_field_static_get_value:
2449 * @vt: vtable to the object
2450 * @field: MonoClassField describing the field to fetch information from
2451 * @value: where the value is returned
2453 * Use this routine to get the value of the static field @field value.
2455 * The pointer provided by value must be of the field type, for reference
2456 * types this is a MonoObject*, for value types its the actual pointer to
2461 * mono_field_static_get_value (vt, int_field, &i);
2464 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2468 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2470 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2471 get_default_field_value (vt->domain, field, value);
2475 src = (char*)vt->data + field->offset;
2476 set_value (field->type, value, src, TRUE);
2480 * mono_property_set_value:
2481 * @prop: MonoProperty to set
2482 * @obj: instance object on which to act
2483 * @params: parameters to pass to the propery
2484 * @exc: optional exception
2486 * Invokes the property's set method with the given arguments on the
2487 * object instance obj (or NULL for static properties).
2489 * You can pass NULL as the exc argument if you don't want to
2490 * catch exceptions, otherwise, *exc will be set to the exception
2491 * thrown, if any. if an exception is thrown, you can't use the
2492 * MonoObject* result from the function.
2495 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2497 default_mono_runtime_invoke (prop->set, obj, params, exc);
2501 * mono_property_get_value:
2502 * @prop: MonoProperty to fetch
2503 * @obj: instance object on which to act
2504 * @params: parameters to pass to the propery
2505 * @exc: optional exception
2507 * Invokes the property's get method with the given arguments on the
2508 * object instance obj (or NULL for static properties).
2510 * You can pass NULL as the exc argument if you don't want to
2511 * catch exceptions, otherwise, *exc will be set to the exception
2512 * thrown, if any. if an exception is thrown, you can't use the
2513 * MonoObject* result from the function.
2515 * Returns: the value from invoking the get method on the property.
2518 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2520 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2524 * mono_nullable_init:
2525 * @buf: The nullable structure to initialize.
2526 * @value: the value to initialize from
2527 * @klass: the type for the object
2529 * Initialize the nullable structure pointed to by @buf from @value which
2530 * should be a boxed value type. The size of @buf should be able to hold
2531 * as much data as the @klass->instance_size (which is the number of bytes
2532 * that will be copies).
2534 * Since Nullables have variable structure, we can not define a C
2535 * structure for them.
2538 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2540 MonoClass *param_class = klass->cast_class;
2542 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2543 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2545 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2547 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2549 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2553 * mono_nullable_box:
2554 * @buf: The buffer representing the data to be boxed
2555 * @klass: the type to box it as.
2557 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2561 mono_nullable_box (guint8 *buf, MonoClass *klass)
2563 MonoClass *param_class = klass->cast_class;
2565 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2566 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2568 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2569 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2570 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2578 * mono_get_delegate_invoke:
2579 * @klass: The delegate class
2581 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2584 mono_get_delegate_invoke (MonoClass *klass)
2588 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2595 * mono_runtime_delegate_invoke:
2596 * @delegate: pointer to a delegate object.
2597 * @params: parameters for the delegate.
2598 * @exc: Pointer to the exception result.
2600 * Invokes the delegate method @delegate with the parameters provided.
2602 * You can pass NULL as the exc argument if you don't want to
2603 * catch exceptions, otherwise, *exc will be set to the exception
2604 * thrown, if any. if an exception is thrown, you can't use the
2605 * MonoObject* result from the function.
2608 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2612 im = mono_get_delegate_invoke (delegate->vtable->klass);
2615 return mono_runtime_invoke (im, delegate, params, exc);
2618 static char **main_args = NULL;
2619 static int num_main_args;
2622 * mono_runtime_get_main_args:
2624 * Returns: a MonoArray with the arguments passed to the main program
2627 mono_runtime_get_main_args (void)
2631 MonoDomain *domain = mono_domain_get ();
2636 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2638 for (i = 0; i < num_main_args; ++i)
2639 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2645 fire_process_exit_event (void)
2647 MonoClassField *field;
2648 MonoDomain *domain = mono_domain_get ();
2650 MonoObject *delegate, *exc;
2652 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2655 if (domain != mono_get_root_domain ())
2658 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2659 if (delegate == NULL)
2664 mono_runtime_delegate_invoke (delegate, pa, &exc);
2668 * mono_runtime_run_main:
2669 * @method: the method to start the application with (usually Main)
2670 * @argc: number of arguments from the command line
2671 * @argv: array of strings from the command line
2672 * @exc: excetption results
2674 * Execute a standard Main() method (argc/argv contains the
2675 * executable name). This method also sets the command line argument value
2676 * needed by System.Environment.
2681 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2685 MonoArray *args = NULL;
2686 MonoDomain *domain = mono_domain_get ();
2687 gchar *utf8_fullpath;
2690 g_assert (method != NULL);
2692 mono_thread_set_main (mono_thread_current ());
2694 main_args = g_new0 (char*, argc);
2695 num_main_args = argc;
2697 if (!g_path_is_absolute (argv [0])) {
2698 gchar *basename = g_path_get_basename (argv [0]);
2699 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2703 utf8_fullpath = mono_utf8_from_external (fullpath);
2704 if(utf8_fullpath == NULL) {
2705 /* Printing the arg text will cause glib to
2706 * whinge about "Invalid UTF-8", but at least
2707 * its relevant, and shows the problem text
2710 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2711 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2718 utf8_fullpath = mono_utf8_from_external (argv[0]);
2719 if(utf8_fullpath == NULL) {
2720 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2721 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2726 main_args [0] = utf8_fullpath;
2728 for (i = 1; i < argc; ++i) {
2731 utf8_arg=mono_utf8_from_external (argv[i]);
2732 if(utf8_arg==NULL) {
2733 /* Ditto the comment about Invalid UTF-8 here */
2734 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2735 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2739 main_args [i] = utf8_arg;
2743 if (mono_method_signature (method)->param_count) {
2744 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2745 for (i = 0; i < argc; ++i) {
2746 /* The encodings should all work, given that
2747 * we've checked all these args for the
2750 gchar *str = mono_utf8_from_external (argv [i]);
2751 MonoString *arg = mono_string_new (domain, str);
2752 mono_array_setref (args, i, arg);
2756 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2759 mono_assembly_set_main (method->klass->image->assembly);
2761 result = mono_runtime_exec_main (method, args, exc);
2762 fire_process_exit_event ();
2766 /* Used in call_unhandled_exception_delegate */
2768 create_unhandled_exception_eventargs (MonoObject *exc)
2772 MonoMethod *method = NULL;
2773 MonoBoolean is_terminating = TRUE;
2776 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2779 mono_class_init (klass);
2781 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2782 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2786 args [1] = &is_terminating;
2788 obj = mono_object_new (mono_domain_get (), klass);
2789 mono_runtime_invoke (method, obj, args, NULL);
2794 /* Used in mono_unhandled_exception */
2796 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2797 MonoObject *e = NULL;
2800 pa [0] = domain->domain;
2801 pa [1] = create_unhandled_exception_eventargs (exc);
2802 mono_runtime_delegate_invoke (delegate, pa, &e);
2805 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2806 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2811 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2814 * mono_runtime_unhandled_exception_policy_set:
2815 * @policy: the new policy
2817 * This is a VM internal routine.
2819 * Sets the runtime policy for handling unhandled exceptions.
2822 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2823 runtime_unhandled_exception_policy = policy;
2827 * mono_runtime_unhandled_exception_policy_get:
2829 * This is a VM internal routine.
2831 * Gets the runtime policy for handling unhandled exceptions.
2833 MonoRuntimeUnhandledExceptionPolicy
2834 mono_runtime_unhandled_exception_policy_get (void) {
2835 return runtime_unhandled_exception_policy;
2839 * mono_unhandled_exception:
2840 * @exc: exception thrown
2842 * This is a VM internal routine.
2844 * We call this function when we detect an unhandled exception
2845 * in the default domain.
2847 * It invokes the * UnhandledException event in AppDomain or prints
2848 * a warning to the console
2851 mono_unhandled_exception (MonoObject *exc)
2853 MonoDomain *current_domain = mono_domain_get ();
2854 MonoDomain *root_domain = mono_get_root_domain ();
2855 MonoClassField *field;
2856 MonoObject *current_appdomain_delegate;
2857 MonoObject *root_appdomain_delegate;
2859 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2860 "UnhandledException");
2863 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2864 gboolean abort_process = (mono_thread_current () == main_thread) ||
2865 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2866 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2867 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2868 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2870 current_appdomain_delegate = NULL;
2873 /* set exitcode only if we will abort the process */
2875 mono_environment_exitcode_set (1);
2876 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2877 mono_print_unhandled_exception (exc);
2879 if (root_appdomain_delegate) {
2880 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2882 if (current_appdomain_delegate) {
2883 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2890 * Launch a new thread to execute a function
2892 * main_func is called back from the thread with main_args as the
2893 * parameter. The callback function is expected to start Main()
2894 * eventually. This function then waits for all managed threads to
2896 * It is not necesseray anymore to execute managed code in a subthread,
2897 * so this function should not be used anymore by default: just
2898 * execute the code and then call mono_thread_manage ().
2901 mono_runtime_exec_managed_code (MonoDomain *domain,
2902 MonoMainThreadFunc main_func,
2905 mono_thread_create (domain, main_func, main_args);
2907 mono_thread_manage ();
2911 * Execute a standard Main() method (args doesn't contain the
2915 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2920 MonoCustomAttrInfo* cinfo;
2921 gboolean has_stathread_attribute;
2922 MonoThread* thread = mono_thread_current ();
2928 domain = mono_object_domain (args);
2929 if (!domain->entry_assembly) {
2931 MonoAssembly *assembly;
2933 assembly = method->klass->image->assembly;
2934 domain->entry_assembly = assembly;
2935 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2937 str = g_strconcat (assembly->image->name, ".config", NULL);
2938 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2942 cinfo = mono_custom_attrs_from_method (method);
2944 static MonoClass *stathread_attribute = NULL;
2945 if (!stathread_attribute)
2946 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
2947 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
2949 mono_custom_attrs_free (cinfo);
2951 has_stathread_attribute = FALSE;
2953 if (has_stathread_attribute) {
2954 thread->apartment_state = ThreadApartmentState_STA;
2955 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
2956 thread->apartment_state = ThreadApartmentState_Unknown;
2958 thread->apartment_state = ThreadApartmentState_MTA;
2960 mono_thread_init_apartment_state ();
2962 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
2964 /* FIXME: check signature of method */
2965 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
2967 res = mono_runtime_invoke (method, NULL, pa, exc);
2969 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
2973 mono_environment_exitcode_set (rval);
2975 mono_runtime_invoke (method, NULL, pa, exc);
2979 /* If the return type of Main is void, only
2980 * set the exitcode if an exception was thrown
2981 * (we don't want to blow away an
2982 * explicitly-set exit code)
2985 mono_environment_exitcode_set (rval);
2989 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
2995 * mono_install_runtime_invoke:
2996 * @func: Function to install
2998 * This is a VM internal routine
3001 mono_install_runtime_invoke (MonoInvokeFunc func)
3003 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3008 * mono_runtime_invoke_array:
3009 * @method: method to invoke
3010 * @obJ: object instance
3011 * @params: arguments to the method
3012 * @exc: exception information.
3014 * Invokes the method represented by @method on the object @obj.
3016 * obj is the 'this' pointer, it should be NULL for static
3017 * methods, a MonoObject* for object instances and a pointer to
3018 * the value type for value types.
3020 * The params array contains the arguments to the method with the
3021 * same convention: MonoObject* pointers for object instances and
3022 * pointers to the value type otherwise. The _invoke_array
3023 * variant takes a C# object[] as the params argument (MonoArray
3024 * *params): in this case the value types are boxed inside the
3025 * respective reference representation.
3027 * From unmanaged code you'll usually use the
3028 * mono_runtime_invoke() variant.
3030 * Note that this function doesn't handle virtual methods for
3031 * you, it will exec the exact method you pass: we still need to
3032 * expose a function to lookup the derived class implementation
3033 * of a virtual method (there are examples of this in the code,
3036 * You can pass NULL as the exc argument if you don't want to
3037 * catch exceptions, otherwise, *exc will be set to the exception
3038 * thrown, if any. if an exception is thrown, you can't use the
3039 * MonoObject* result from the function.
3041 * If the method returns a value type, it is boxed in an object
3045 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3048 MonoMethodSignature *sig = mono_method_signature (method);
3049 gpointer *pa = NULL;
3052 if (NULL != params) {
3053 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3054 for (i = 0; i < mono_array_length (params); i++) {
3055 MonoType *t = sig->params [i];
3061 case MONO_TYPE_BOOLEAN:
3064 case MONO_TYPE_CHAR:
3073 case MONO_TYPE_VALUETYPE:
3074 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3077 g_assert_not_reached ();
3078 /* The runtime invoke wrapper needs the original boxed vtype */
3079 pa [i] = mono_array_get (params, MonoObject*, i);
3081 /* MS seems to create the objects if a null is passed in */
3082 if (!mono_array_get (params, MonoObject*, i))
3083 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3087 * We can't pass the unboxed vtype byref to the callee, since
3088 * that would mean the callee would be able to modify boxed
3089 * primitive types. So we (and MS) make a copy of the boxed
3090 * object, pass that to the callee, and replace the original
3091 * boxed object in the arg array with the copy.
3093 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3094 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3095 mono_array_setref (params, i, copy);
3098 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3101 case MONO_TYPE_STRING:
3102 case MONO_TYPE_OBJECT:
3103 case MONO_TYPE_CLASS:
3104 case MONO_TYPE_ARRAY:
3105 case MONO_TYPE_SZARRAY:
3107 pa [i] = mono_array_addr (params, MonoObject*, i);
3108 // FIXME: I need to check this code path
3110 pa [i] = mono_array_get (params, MonoObject*, i);
3112 case MONO_TYPE_GENERICINST:
3114 t = &t->data.generic_class->container_class->this_arg;
3116 t = &t->data.generic_class->container_class->byval_arg;
3119 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3124 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3127 if (mono_class_is_nullable (method->klass)) {
3128 /* Need to create a boxed vtype instead */
3134 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3138 obj = mono_object_new (mono_domain_get (), method->klass);
3139 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3140 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3142 if (method->klass->valuetype)
3143 o = mono_object_unbox (obj);
3146 } else if (method->klass->valuetype) {
3147 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3150 mono_runtime_invoke (method, o, pa, exc);
3153 if (mono_class_is_nullable (method->klass)) {
3154 MonoObject *nullable;
3156 /* Convert the unboxed vtype into a Nullable structure */
3157 nullable = mono_object_new (mono_domain_get (), method->klass);
3159 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3160 obj = mono_object_unbox (nullable);
3163 /* obj must be already unboxed if needed */
3164 return mono_runtime_invoke (method, obj, pa, exc);
3169 arith_overflow (void)
3171 mono_raise_exception (mono_get_exception_overflow ());
3175 * mono_object_allocate:
3176 * @size: number of bytes to allocate
3178 * This is a very simplistic routine until we have our GC-aware
3181 * Returns: an allocated object of size @size, or NULL on failure.
3183 static inline void *
3184 mono_object_allocate (size_t size, MonoVTable *vtable)
3187 mono_stats.new_object_count++;
3188 ALLOC_OBJECT (o, vtable, size);
3194 * mono_object_allocate_ptrfree:
3195 * @size: number of bytes to allocate
3197 * Note that the memory allocated is not zeroed.
3198 * Returns: an allocated object of size @size, or NULL on failure.
3200 static inline void *
3201 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3204 mono_stats.new_object_count++;
3205 ALLOC_PTRFREE (o, vtable, size);
3209 static inline void *
3210 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3213 ALLOC_TYPED (o, size, vtable);
3214 mono_stats.new_object_count++;
3221 * @klass: the class of the object that we want to create
3223 * Returns: a newly created object whose definition is
3224 * looked up using @klass. This will not invoke any constructors,
3225 * so the consumer of this routine has to invoke any constructors on
3226 * its own to initialize the object.
3229 mono_object_new (MonoDomain *domain, MonoClass *klass)
3231 MONO_ARCH_SAVE_REGS;
3232 return mono_object_new_specific (mono_class_vtable (domain, klass));
3236 * mono_object_new_specific:
3237 * @vtable: the vtable of the object that we want to create
3239 * Returns: A newly created object with class and domain specified
3243 mono_object_new_specific (MonoVTable *vtable)
3247 MONO_ARCH_SAVE_REGS;
3249 /* check for is_com_object for COM Interop */
3250 if (vtable->remote || vtable->klass->is_com_object)
3253 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3256 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3259 mono_class_init (klass);
3261 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3263 vtable->domain->create_proxy_for_type_method = im;
3266 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3268 o = mono_runtime_invoke (im, NULL, pa, NULL);
3269 if (o != NULL) return o;
3272 return mono_object_new_alloc_specific (vtable);
3276 mono_object_new_alloc_specific (MonoVTable *vtable)
3280 if (!vtable->klass->has_references) {
3281 o = mono_object_new_ptrfree (vtable);
3282 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3283 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3285 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3286 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3288 if (vtable->klass->has_finalize)
3289 mono_object_register_finalizer (o);
3291 mono_profiler_allocation (o, vtable->klass);
3296 mono_object_new_fast (MonoVTable *vtable)
3299 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3304 mono_object_new_ptrfree (MonoVTable *vtable)
3307 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3308 #if NEED_TO_ZERO_PTRFREE
3309 /* an inline memset is much faster for the common vcase of small objects
3310 * note we assume the allocated size is a multiple of sizeof (void*).
3312 if (vtable->klass->instance_size < 128) {
3314 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3315 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3321 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3328 mono_object_new_ptrfree_box (MonoVTable *vtable)
3331 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3332 /* the object will be boxed right away, no need to memzero it */
3337 * mono_class_get_allocation_ftn:
3339 * @for_box: the object will be used for boxing
3340 * @pass_size_in_words:
3342 * Return the allocation function appropriate for the given class.
3346 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3348 *pass_size_in_words = FALSE;
3350 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3351 return mono_object_new_specific;
3353 if (!vtable->klass->has_references) {
3354 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3356 return mono_object_new_ptrfree_box;
3357 return mono_object_new_ptrfree;
3360 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3362 return mono_object_new_fast;
3365 * FIXME: This is actually slower than mono_object_new_fast, because
3366 * of the overhead of parameter passing.
3369 *pass_size_in_words = TRUE;
3370 #ifdef GC_REDIRECT_TO_LOCAL
3371 return GC_local_gcj_fast_malloc;
3373 return GC_gcj_fast_malloc;
3378 return mono_object_new_specific;
3382 * mono_object_new_from_token:
3383 * @image: Context where the type_token is hosted
3384 * @token: a token of the type that we want to create
3386 * Returns: A newly created object whose definition is
3387 * looked up using @token in the @image image
3390 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3394 class = mono_class_get (image, token);
3396 return mono_object_new (domain, class);
3401 * mono_object_clone:
3402 * @obj: the object to clone
3404 * Returns: A newly created object who is a shallow copy of @obj
3407 mono_object_clone (MonoObject *obj)
3412 size = obj->vtable->klass->instance_size;
3413 o = mono_object_allocate (size, obj->vtable);
3414 /* do not copy the sync state */
3415 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3418 if (obj->vtable->klass->has_references)
3419 mono_gc_wbarrier_object (o);
3421 mono_profiler_allocation (o, obj->vtable->klass);
3423 if (obj->vtable->klass->has_finalize)
3424 mono_object_register_finalizer (o);
3429 * mono_array_full_copy:
3430 * @src: source array to copy
3431 * @dest: destination array
3433 * Copies the content of one array to another with exactly the same type and size.
3436 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3439 MonoClass *klass = src->obj.vtable->klass;
3441 MONO_ARCH_SAVE_REGS;
3443 g_assert (klass == dest->obj.vtable->klass);
3445 size = mono_array_length (src);
3446 g_assert (size == mono_array_length (dest));
3447 size *= mono_array_element_size (klass);
3449 if (klass->element_class->valuetype) {
3450 if (klass->element_class->has_references)
3451 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3453 memcpy (&dest->vector, &src->vector, size);
3455 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3458 memcpy (&dest->vector, &src->vector, size);
3463 * mono_array_clone_in_domain:
3464 * @domain: the domain in which the array will be cloned into
3465 * @array: the array to clone
3467 * This routine returns a copy of the array that is hosted on the
3468 * specified MonoDomain.
3471 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3476 MonoClass *klass = array->obj.vtable->klass;
3478 MONO_ARCH_SAVE_REGS;
3480 if (array->bounds == NULL) {
3481 size = mono_array_length (array);
3482 o = mono_array_new_full (domain, klass, &size, NULL);
3484 size *= mono_array_element_size (klass);
3486 if (klass->element_class->valuetype) {
3487 if (klass->element_class->has_references)
3488 mono_value_copy_array (o, 0, array, mono_array_length (array));
3490 memcpy (&o->vector, &array->vector, size);
3492 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3495 memcpy (&o->vector, &array->vector, size);
3500 sizes = alloca (klass->rank * sizeof(guint32) * 2);
3501 size = mono_array_element_size (klass);
3502 for (i = 0; i < klass->rank; ++i) {
3503 sizes [i] = array->bounds [i].length;
3504 size *= array->bounds [i].length;
3505 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3507 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3509 if (klass->element_class->valuetype) {
3510 if (klass->element_class->has_references)
3511 mono_value_copy_array (o, 0, array, mono_array_length (array));
3513 memcpy (&o->vector, &array->vector, size);
3515 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3518 memcpy (&o->vector, &array->vector, size);
3526 * @array: the array to clone
3528 * Returns: A newly created array who is a shallow copy of @array
3531 mono_array_clone (MonoArray *array)
3533 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3536 /* helper macros to check for overflow when calculating the size of arrays */
3537 #define MYGUINT32_MAX 4294967295U
3538 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3539 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
3540 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3541 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
3542 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
3545 * mono_array_new_full:
3546 * @domain: domain where the object is created
3547 * @array_class: array class
3548 * @lengths: lengths for each dimension in the array
3549 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3551 * This routine creates a new array objects with the given dimensions,
3552 * lower bounds and type.
3555 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
3557 guint32 byte_len, len, bounds_size;
3563 if (!array_class->inited)
3564 mono_class_init (array_class);
3566 byte_len = mono_array_element_size (array_class);
3569 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3570 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3576 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3578 for (i = 0; i < array_class->rank; ++i) {
3579 if ((int) lengths [i] < 0)
3581 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3582 mono_gc_out_of_memory (MYGUINT32_MAX);
3587 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3588 mono_gc_out_of_memory (MYGUINT32_MAX);
3590 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3591 mono_gc_out_of_memory (MYGUINT32_MAX);
3592 byte_len += sizeof (MonoArray);
3595 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3596 mono_gc_out_of_memory (MYGUINT32_MAX);
3597 byte_len = (byte_len + 3) & ~3;
3598 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3599 mono_gc_out_of_memory (MYGUINT32_MAX);
3600 byte_len += bounds_size;
3603 * Following three lines almost taken from mono_object_new ():
3604 * they need to be kept in sync.
3606 vtable = mono_class_vtable (domain, array_class);
3607 if (!array_class->has_references) {
3608 o = mono_object_allocate_ptrfree (byte_len, vtable);
3609 #if NEED_TO_ZERO_PTRFREE
3610 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3612 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3613 o = mono_object_allocate_spec (byte_len, vtable);
3615 o = mono_object_allocate (byte_len, vtable);
3618 array = (MonoArray*)o;
3619 array->max_length = len;
3622 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3623 array->bounds = bounds;
3624 for (i = 0; i < array_class->rank; ++i) {
3625 bounds [i].length = lengths [i];
3627 bounds [i].lower_bound = lower_bounds [i];
3631 mono_profiler_allocation (o, array_class);
3638 * @domain: domain where the object is created
3639 * @eclass: element class
3640 * @n: number of array elements
3642 * This routine creates a new szarray with @n elements of type @eclass.
3645 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
3649 MONO_ARCH_SAVE_REGS;
3651 ac = mono_array_class_get (eclass, 1);
3652 g_assert (ac != NULL);
3654 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3658 * mono_array_new_specific:
3659 * @vtable: a vtable in the appropriate domain for an initialized class
3660 * @n: number of array elements
3662 * This routine is a fast alternative to mono_array_new() for code which
3663 * can be sure about the domain it operates in.
3666 mono_array_new_specific (MonoVTable *vtable, guint32 n)
3670 guint32 byte_len, elem_size;
3672 MONO_ARCH_SAVE_REGS;
3677 elem_size = mono_array_element_size (vtable->klass);
3678 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
3679 mono_gc_out_of_memory (MYGUINT32_MAX);
3680 byte_len = n * elem_size;
3681 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3682 mono_gc_out_of_memory (MYGUINT32_MAX);
3683 byte_len += sizeof (MonoArray);
3684 if (!vtable->klass->has_references) {
3685 o = mono_object_allocate_ptrfree (byte_len, vtable);
3686 #if NEED_TO_ZERO_PTRFREE
3687 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3689 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3690 o = mono_object_allocate_spec (byte_len, vtable);
3692 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3693 o = mono_object_allocate (byte_len, vtable);
3696 ao = (MonoArray *)o;
3699 mono_profiler_allocation (o, vtable->klass);
3705 * mono_string_new_utf16:
3706 * @text: a pointer to an utf16 string
3707 * @len: the length of the string
3709 * Returns: A newly created string object which contains @text.
3712 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3716 s = mono_string_new_size (domain, len);
3717 g_assert (s != NULL);
3719 memcpy (mono_string_chars (s), text, len * 2);
3725 * mono_string_new_size:
3726 * @text: a pointer to an utf16 string
3727 * @len: the length of the string
3729 * Returns: A newly created string object of @len
3732 mono_string_new_size (MonoDomain *domain, gint32 len)
3736 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3738 /* overflow ? can't fit it, can't allocate it! */
3740 mono_gc_out_of_memory (-1);
3742 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3744 s = mono_object_allocate_ptrfree (size, vtable);
3747 #if NEED_TO_ZERO_PTRFREE
3750 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3756 * mono_string_new_len:
3757 * @text: a pointer to an utf8 string
3758 * @length: number of bytes in @text to consider
3760 * Returns: A newly created string object which contains @text.
3763 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3765 GError *error = NULL;
3766 MonoString *o = NULL;
3768 glong items_written;
3770 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3773 o = mono_string_new_utf16 (domain, ut, items_written);
3775 g_error_free (error);
3784 * @text: a pointer to an utf8 string
3786 * Returns: A newly created string object which contains @text.
3789 mono_string_new (MonoDomain *domain, const char *text)
3791 GError *error = NULL;
3792 MonoString *o = NULL;
3794 glong items_written;
3799 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3802 o = mono_string_new_utf16 (domain, ut, items_written);
3804 g_error_free (error);
3812 * mono_string_new_wrapper:
3813 * @text: pointer to utf8 characters.
3815 * Helper function to create a string object from @text in the current domain.
3818 mono_string_new_wrapper (const char *text)
3820 MonoDomain *domain = mono_domain_get ();
3822 MONO_ARCH_SAVE_REGS;
3825 return mono_string_new (domain, text);
3832 * @class: the class of the value
3833 * @value: a pointer to the unboxed data
3835 * Returns: A newly created object which contains @value.
3838 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3844 g_assert (class->valuetype);
3846 vtable = mono_class_vtable (domain, class);
3847 size = mono_class_instance_size (class);
3848 res = mono_object_new_alloc_specific (vtable);
3849 mono_profiler_allocation (res, class);
3851 size = size - sizeof (MonoObject);
3854 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3857 #if NO_UNALIGNED_ACCESS
3858 memcpy ((char *)res + sizeof (MonoObject), value, size);
3862 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3865 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3868 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3871 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3874 memcpy ((char *)res + sizeof (MonoObject), value, size);
3877 if (class->has_finalize)
3878 mono_object_register_finalizer (res);
3884 * @dest: destination pointer
3885 * @src: source pointer
3886 * @klass: a valuetype class
3888 * Copy a valuetype from @src to @dest. This function must be used
3889 * when @klass contains references fields.
3892 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3894 int size = mono_class_value_size (klass, NULL);
3895 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3896 memcpy (dest, src, size);
3900 * mono_value_copy_array:
3901 * @dest: destination array
3902 * @dest_idx: index in the @dest array
3903 * @src: source pointer
3904 * @count: number of items
3906 * Copy @count valuetype items from @src to @dest. This function must be used
3907 * when @klass contains references fields.
3908 * Overlap is handled.
3911 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3913 int size = mono_array_element_size (dest->obj.vtable->klass);
3914 char *d = mono_array_addr_with_size (dest, size, dest_idx);
3915 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3916 memmove (d, src, size * count);
3920 * mono_object_get_domain:
3921 * @obj: object to query
3923 * Returns: the MonoDomain where the object is hosted
3926 mono_object_get_domain (MonoObject *obj)
3928 return mono_object_domain (obj);
3932 * mono_object_get_class:
3933 * @obj: object to query
3935 * Returns: the MonOClass of the object.
3938 mono_object_get_class (MonoObject *obj)
3940 return mono_object_class (obj);
3943 * mono_object_get_size:
3944 * @o: object to query
3946 * Returns: the size, in bytes, of @o
3949 mono_object_get_size (MonoObject* o)
3951 MonoClass* klass = mono_object_class (o);
3952 if (klass == mono_defaults.string_class) {
3953 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
3954 } else if (o->vtable->rank) {
3955 MonoArray *array = (MonoArray*)o;
3956 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
3957 if (array->bounds) {
3960 size += sizeof (MonoArrayBounds) * o->vtable->rank;
3964 return mono_class_instance_size (klass);
3969 * mono_object_unbox:
3970 * @obj: object to unbox
3972 * Returns: a pointer to the start of the valuetype boxed in this
3975 * This method will assert if the object passed is not a valuetype.
3978 mono_object_unbox (MonoObject *obj)
3980 /* add assert for valuetypes? */
3981 g_assert (obj->vtable->klass->valuetype);
3982 return ((char*)obj) + sizeof (MonoObject);
3986 * mono_object_isinst:
3988 * @klass: a pointer to a class
3990 * Returns: @obj if @obj is derived from @klass
3993 mono_object_isinst (MonoObject *obj, MonoClass *klass)
3996 mono_class_init (klass);
3998 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3999 return mono_object_isinst_mbyref (obj, klass);
4004 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4008 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4017 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4018 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4022 MonoClass *oklass = vt->klass;
4023 if ((oklass == mono_defaults.transparent_proxy_class))
4024 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4026 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4030 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4032 MonoDomain *domain = mono_domain_get ();
4034 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4035 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4036 MonoMethod *im = NULL;
4039 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4040 im = mono_object_get_virtual_method (rp, im);
4043 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4046 res = mono_runtime_invoke (im, rp, pa, NULL);
4048 if (*(MonoBoolean *) mono_object_unbox(res)) {
4049 /* Update the vtable of the remote type, so it can safely cast to this new type */
4050 mono_upgrade_remote_class (domain, obj, klass);
4059 * mono_object_castclass_mbyref:
4061 * @klass: a pointer to a class
4063 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4066 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4068 if (!obj) return NULL;
4069 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4071 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4073 "InvalidCastException"));
4078 MonoDomain *orig_domain;
4084 str_lookup (MonoDomain *domain, gpointer user_data)
4086 LDStrInfo *info = user_data;
4087 if (info->res || domain == info->orig_domain)
4089 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4095 mono_string_get_pinned (MonoString *str)
4099 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4100 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4101 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4102 news->length = mono_string_length (str);
4107 #define mono_string_get_pinned(str) (str)
4111 mono_string_is_interned_lookup (MonoString *str, int insert)
4113 MonoGHashTable *ldstr_table;
4117 domain = ((MonoObject *)str)->vtable->domain;
4118 ldstr_table = domain->ldstr_table;
4120 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4125 str = mono_string_get_pinned (str);
4126 mono_g_hash_table_insert (ldstr_table, str, str);
4130 LDStrInfo ldstr_info;
4131 ldstr_info.orig_domain = domain;
4132 ldstr_info.ins = str;
4133 ldstr_info.res = NULL;
4135 mono_domain_foreach (str_lookup, &ldstr_info);
4136 if (ldstr_info.res) {
4138 * the string was already interned in some other domain:
4139 * intern it in the current one as well.
4141 mono_g_hash_table_insert (ldstr_table, str, str);
4151 * mono_string_is_interned:
4152 * @o: String to probe
4154 * Returns whether the string has been interned.
4157 mono_string_is_interned (MonoString *o)
4159 return mono_string_is_interned_lookup (o, FALSE);
4163 * mono_string_intern:
4164 * @o: String to intern
4166 * Interns the string passed.
4167 * Returns: The interned string.
4170 mono_string_intern (MonoString *str)
4172 return mono_string_is_interned_lookup (str, TRUE);
4177 * @domain: the domain where the string will be used.
4178 * @image: a metadata context
4179 * @idx: index into the user string table.
4181 * Implementation for the ldstr opcode.
4182 * Returns: a loaded string from the @image/@idx combination.
4185 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4187 MONO_ARCH_SAVE_REGS;
4190 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4192 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4196 * mono_ldstr_metdata_sig
4197 * @domain: the domain for the string
4198 * @sig: the signature of a metadata string
4200 * Returns: a MonoString for a string stored in the metadata
4203 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4205 const char *str = sig;
4206 MonoString *o, *interned;
4209 len2 = mono_metadata_decode_blob_size (str, &str);
4212 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4213 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4216 guint16 *p2 = (guint16*)mono_string_chars (o);
4217 for (i = 0; i < len2; ++i) {
4218 *p2 = GUINT16_FROM_LE (*p2);
4224 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4226 /* o will get garbage collected */
4230 o = mono_string_get_pinned (o);
4231 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4238 * mono_string_to_utf8:
4239 * @s: a System.String
4241 * Return the UTF8 representation for @s.
4242 * the resulting buffer nedds to be freed with g_free().
4245 mono_string_to_utf8 (MonoString *s)
4249 GError *error = NULL;
4255 return g_strdup ("");
4257 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4259 MonoException *exc = mono_get_exception_argument ("string", error->message);
4260 g_error_free (error);
4261 mono_raise_exception(exc);
4263 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4264 if (s->length > written) {
4265 /* allocate the total length and copy the part of the string that has been converted */
4266 char *as2 = g_malloc0 (s->length);
4267 memcpy (as2, as, written);
4276 * mono_string_to_utf16:
4279 * Return an null-terminated array of the utf-16 chars
4280 * contained in @s. The result must be freed with g_free().
4281 * This is a temporary helper until our string implementation
4282 * is reworked to always include the null terminating char.
4285 mono_string_to_utf16 (MonoString *s)
4292 as = g_malloc ((s->length * 2) + 2);
4293 as [(s->length * 2)] = '\0';
4294 as [(s->length * 2) + 1] = '\0';
4297 return (gunichar2 *)(as);
4300 memcpy (as, mono_string_chars(s), s->length * 2);
4301 return (gunichar2 *)(as);
4305 * mono_string_from_utf16:
4306 * @data: the UTF16 string (LPWSTR) to convert
4308 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4310 * Returns: a MonoString.
4313 mono_string_from_utf16 (gunichar2 *data)
4315 MonoDomain *domain = mono_domain_get ();
4321 while (data [len]) len++;
4323 return mono_string_new_utf16 (domain, data, len);
4327 * mono_string_to_utf8_mp:
4328 * @s: a System.String
4330 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4333 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4335 char *r = mono_string_to_utf8 (s);
4342 len = strlen (r) + 1;
4343 mp_s = mono_mempool_alloc (mp, len);
4344 memcpy (mp_s, r, len);
4352 default_ex_handler (MonoException *ex)
4354 MonoObject *o = (MonoObject*)ex;
4355 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4359 static MonoExceptionFunc ex_handler = default_ex_handler;
4362 * mono_install_handler:
4363 * @func: exception handler
4365 * This is an internal JIT routine used to install the handler for exceptions
4369 mono_install_handler (MonoExceptionFunc func)
4371 ex_handler = func? func: default_ex_handler;
4375 * mono_raise_exception:
4376 * @ex: exception object
4378 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4381 mono_raise_exception (MonoException *ex)
4384 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4385 * that will cause gcc to omit the function epilog, causing problems when
4386 * the JIT tries to walk the stack, since the return address on the stack
4387 * will point into the next function in the executable, not this one.
4390 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4391 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4397 * mono_wait_handle_new:
4398 * @domain: Domain where the object will be created
4399 * @handle: Handle for the wait handle
4401 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4404 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4406 MonoWaitHandle *res;
4407 gpointer params [1];
4408 static MonoMethod *handle_set;
4410 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4412 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4414 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4416 params [0] = &handle;
4417 mono_runtime_invoke (handle_set, res, params, NULL);
4423 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4425 static MonoClassField *f_os_handle;
4426 static MonoClassField *f_safe_handle;
4428 if (!f_os_handle && !f_safe_handle) {
4429 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4430 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4435 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4439 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4445 * mono_async_result_new:
4446 * @domain:domain where the object will be created.
4447 * @handle: wait handle.
4448 * @state: state to pass to AsyncResult
4449 * @data: C closure data.
4451 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4452 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4456 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4458 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4459 MonoMethod *method = mono_get_context_capture_method ();
4461 /* we must capture the execution context from the original thread */
4463 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4464 /* note: result may be null if the flow is suppressed */
4468 MONO_OBJECT_SETREF (res, object_data, object_data);
4469 MONO_OBJECT_SETREF (res, async_state, state);
4471 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4473 res->sync_completed = FALSE;
4474 res->completed = FALSE;
4480 mono_message_init (MonoDomain *domain,
4481 MonoMethodMessage *this,
4482 MonoReflectionMethod *method,
4483 MonoArray *out_args)
4485 MonoMethodSignature *sig = mono_method_signature (method->method);
4491 MONO_OBJECT_SETREF (this, method, method);
4493 MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
4494 MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
4495 this->async_result = NULL;
4496 this->call_type = CallType_Sync;
4498 names = g_new (char *, sig->param_count);
4499 mono_method_get_param_names (method->method, (const char **) names);
4500 MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
4502 for (i = 0; i < sig->param_count; i++) {
4503 name = mono_string_new (domain, names [i]);
4504 mono_array_setref (this->names, i, name);
4508 for (i = 0, j = 0; i < sig->param_count; i++) {
4510 if (sig->params [i]->byref) {
4512 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4513 mono_array_setref (this->args, i, arg);
4517 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4521 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4524 mono_array_set (this->arg_types, guint8, i, arg_type);
4529 * mono_remoting_invoke:
4530 * @real_proxy: pointer to a RealProxy object
4531 * @msg: The MonoMethodMessage to execute
4532 * @exc: used to store exceptions
4533 * @out_args: used to store output arguments
4535 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4536 * IMessage interface and it is not trivial to extract results from there. So
4537 * we call an helper method PrivateInvoke instead of calling
4538 * RealProxy::Invoke() directly.
4540 * Returns: the result object.
4543 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4544 MonoObject **exc, MonoArray **out_args)
4546 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4549 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4552 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4554 real_proxy->vtable->domain->private_invoke_method = im;
4557 pa [0] = real_proxy;
4562 return mono_runtime_invoke (im, NULL, pa, exc);
4566 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4567 MonoObject **exc, MonoArray **out_args)
4571 MonoMethodSignature *sig;
4573 int i, j, outarg_count = 0;
4575 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4577 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4578 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4579 target = tp->rp->unwrapped_server;
4581 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4585 domain = mono_domain_get ();
4586 method = msg->method->method;
4587 sig = mono_method_signature (method);
4589 for (i = 0; i < sig->param_count; i++) {
4590 if (sig->params [i]->byref)
4594 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4595 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
4598 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4600 for (i = 0, j = 0; i < sig->param_count; i++) {
4601 if (sig->params [i]->byref) {
4603 arg = mono_array_get (msg->args, gpointer, i);
4604 mono_array_setref (*out_args, j, arg);
4613 * mono_print_unhandled_exception:
4614 * @exc: The exception
4616 * Prints the unhandled exception.
4619 mono_print_unhandled_exception (MonoObject *exc)
4621 char *message = (char *) "";
4625 gboolean free_message = FALSE;
4627 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4628 klass = exc->vtable->klass;
4630 while (klass && method == NULL) {
4631 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4633 klass = klass->parent;
4638 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4640 message = mono_string_to_utf8 (str);
4641 free_message = TRUE;
4646 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4647 * exc->vtable->klass->name, message);
4649 g_printerr ("\nUnhandled Exception: %s\n", message);
4656 * mono_delegate_ctor:
4657 * @this: pointer to an uninitialized delegate object
4658 * @target: target object
4659 * @addr: pointer to native code
4661 * This is used to initialize a delegate.
4664 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4666 MonoDomain *domain = mono_domain_get ();
4667 MonoDelegate *delegate = (MonoDelegate *)this;
4668 MonoMethod *method = NULL;
4675 class = this->vtable->klass;
4676 mono_stats.delegate_creations++;
4678 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4679 method = ji->method;
4680 delegate->method = method;
4683 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4685 method = mono_marshal_get_remoting_invoke (method);
4686 delegate->method_ptr = mono_compile_method (method);
4687 MONO_OBJECT_SETREF (delegate, target, target);
4688 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4689 method = mono_marshal_get_unbox_wrapper (method);
4690 delegate->method_ptr = mono_compile_method (method);
4691 MONO_OBJECT_SETREF (delegate, target, target);
4693 delegate->method_ptr = addr;
4694 MONO_OBJECT_SETREF (delegate, target, target);
4697 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4701 * mono_method_call_message_new:
4702 * @method: method to encapsulate
4703 * @params: parameters to the method
4704 * @invoke: optional, delegate invoke.
4705 * @cb: async callback delegate.
4706 * @state: state passed to the async callback.
4708 * Translates arguments pointers into a MonoMethodMessage.
4711 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4712 MonoDelegate **cb, MonoObject **state)
4714 MonoDomain *domain = mono_domain_get ();
4715 MonoMethodSignature *sig = mono_method_signature (method);
4716 MonoMethodMessage *msg;
4719 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4722 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4723 count = sig->param_count - 2;
4725 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4726 count = sig->param_count;
4729 for (i = 0; i < count; i++) {
4734 if (sig->params [i]->byref)
4735 vpos = *((gpointer *)params [i]);
4739 type = sig->params [i]->type;
4740 class = mono_class_from_mono_type (sig->params [i]);
4742 if (class->valuetype)
4743 arg = mono_value_box (domain, class, vpos);
4745 arg = *((MonoObject **)vpos);
4747 mono_array_setref (msg->args, i, arg);
4750 if (cb != NULL && state != NULL) {
4751 *cb = *((MonoDelegate **)params [i]);
4753 *state = *((MonoObject **)params [i]);
4760 * mono_method_return_message_restore:
4762 * Restore results from message based processing back to arguments pointers
4765 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4767 MonoMethodSignature *sig = mono_method_signature (method);
4768 int i, j, type, size, out_len;
4770 if (out_args == NULL)
4772 out_len = mono_array_length (out_args);
4776 for (i = 0, j = 0; i < sig->param_count; i++) {
4777 MonoType *pt = sig->params [i];
4782 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4784 arg = mono_array_get (out_args, gpointer, j);
4788 case MONO_TYPE_VOID:
4789 g_assert_not_reached ();
4793 case MONO_TYPE_BOOLEAN:
4796 case MONO_TYPE_CHAR:
4803 case MONO_TYPE_VALUETYPE: {
4805 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4806 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4809 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4810 memset (*((gpointer *)params [i]), 0, size);
4814 case MONO_TYPE_STRING:
4815 case MONO_TYPE_CLASS:
4816 case MONO_TYPE_ARRAY:
4817 case MONO_TYPE_SZARRAY:
4818 case MONO_TYPE_OBJECT:
4819 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4822 g_assert_not_reached ();
4831 * mono_load_remote_field:
4832 * @this: pointer to an object
4833 * @klass: klass of the object containing @field
4834 * @field: the field to load
4835 * @res: a storage to store the result
4837 * This method is called by the runtime on attempts to load fields of
4838 * transparent proxy objects. @this points to such TP, @klass is the class of
4839 * the object containing @field. @res is a storage location which can be
4840 * used to store the result.
4842 * Returns: an address pointing to the value of field.
4845 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4847 static MonoMethod *getter = NULL;
4848 MonoDomain *domain = mono_domain_get ();
4849 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4850 MonoClass *field_class;
4851 MonoMethodMessage *msg;
4852 MonoArray *out_args;
4856 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4857 g_assert (res != NULL);
4859 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4860 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4865 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4869 field_class = mono_class_from_mono_type (field->type);
4871 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4872 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4873 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4875 full_name = mono_type_get_full_name (klass);
4876 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4877 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4880 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4882 if (exc) mono_raise_exception ((MonoException *)exc);
4884 if (mono_array_length (out_args) == 0)
4887 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4889 if (field_class->valuetype) {
4890 return ((char *)*res) + sizeof (MonoObject);
4896 * mono_load_remote_field_new:
4901 * Missing documentation.
4904 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
4906 static MonoMethod *getter = NULL;
4907 MonoDomain *domain = mono_domain_get ();
4908 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4909 MonoClass *field_class;
4910 MonoMethodMessage *msg;
4911 MonoArray *out_args;
4912 MonoObject *exc, *res;
4915 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4917 field_class = mono_class_from_mono_type (field->type);
4919 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4921 if (field_class->valuetype) {
4922 res = mono_object_new (domain, field_class);
4923 val = ((gchar *) res) + sizeof (MonoObject);
4927 mono_field_get_value (tp->rp->unwrapped_server, field, val);
4932 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4936 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4937 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4939 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4941 full_name = mono_type_get_full_name (klass);
4942 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4943 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4946 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4948 if (exc) mono_raise_exception ((MonoException *)exc);
4950 if (mono_array_length (out_args) == 0)
4953 res = mono_array_get (out_args, MonoObject *, 0);
4959 * mono_store_remote_field:
4960 * @this: pointer to an object
4961 * @klass: klass of the object containing @field
4962 * @field: the field to load
4963 * @val: the value/object to store
4965 * This method is called by the runtime on attempts to store fields of
4966 * transparent proxy objects. @this points to such TP, @klass is the class of
4967 * the object containing @field. @val is the new value to store in @field.
4970 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
4972 static MonoMethod *setter = NULL;
4973 MonoDomain *domain = mono_domain_get ();
4974 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4975 MonoClass *field_class;
4976 MonoMethodMessage *msg;
4977 MonoArray *out_args;
4982 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4984 field_class = mono_class_from_mono_type (field->type);
4986 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4987 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
4988 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
4993 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4997 if (field_class->valuetype)
4998 arg = mono_value_box (domain, field_class, val);
5000 arg = *((MonoObject **)val);
5003 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5004 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5006 full_name = mono_type_get_full_name (klass);
5007 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5008 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5009 mono_array_setref (msg->args, 2, arg);
5012 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5014 if (exc) mono_raise_exception ((MonoException *)exc);
5018 * mono_store_remote_field_new:
5024 * Missing documentation
5027 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5029 static MonoMethod *setter = NULL;
5030 MonoDomain *domain = mono_domain_get ();
5031 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5032 MonoClass *field_class;
5033 MonoMethodMessage *msg;
5034 MonoArray *out_args;
5038 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5040 field_class = mono_class_from_mono_type (field->type);
5042 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5043 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5044 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5049 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5053 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5054 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5056 full_name = mono_type_get_full_name (klass);
5057 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5058 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5059 mono_array_setref (msg->args, 2, arg);
5062 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5064 if (exc) mono_raise_exception ((MonoException *)exc);
5068 * mono_create_ftnptr:
5070 * Given a function address, create a function descriptor for it.
5071 * This is only needed on IA64.
5074 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5079 mono_domain_lock (domain);
5080 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5081 mono_domain_unlock (domain);
5093 * mono_get_addr_from_ftnptr:
5095 * Given a pointer to a function descriptor, return the function address.
5096 * This is only needed on IA64.
5099 mono_get_addr_from_ftnptr (gpointer descr)
5102 return *(gpointer*)descr;
5110 * mono_string_chars:
5113 * Returns a pointer to the UCS16 characters stored in the MonoString
5116 mono_string_chars(MonoString *s)
5118 /* This method is here only for documentation extraction, this is a macro */
5122 * mono_string_length:
5125 * Returns the lenght in characters of the string
5128 mono_string_length (MonoString *s)
5130 /* This method is here only for documentation extraction, this is a macro */