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 class_needs_rgctx (MonoClass *class)
1307 if (!mono_class_generic_sharing_enabled (class))
1311 if (class->generic_class)
1313 class = class->parent;
1320 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1323 MonoClassRuntimeInfo *runtime_info, *old_info;
1324 MonoClassField *field;
1327 int imt_table_bytes = 0;
1328 gboolean inited = FALSE;
1329 guint32 vtable_size, class_size;
1331 guint32 constant_cols [MONO_CONSTANT_SIZE];
1333 gpointer *interface_offsets;
1335 mono_domain_lock (domain);
1336 runtime_info = class->runtime_info;
1337 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1338 mono_domain_unlock (domain);
1339 return runtime_info->domain_vtables [domain->domain_id];
1341 if (!class->inited || class->exception_type) {
1342 if (!mono_class_init (class) || class->exception_type){
1344 mono_domain_unlock (domain);
1345 exc = mono_class_get_exception_for_failure (class);
1347 mono_raise_exception (exc);
1351 mono_class_init (class);
1353 /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
1354 if (class->image->dynamic)
1355 mono_class_setup_vtable (class);
1358 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1359 if (class->interface_offsets_count) {
1360 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1361 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1362 mono_stats.imt_number_of_tables++;
1363 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1366 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1367 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1370 mono_stats.used_class_count++;
1371 mono_stats.class_vtable_size += vtable_size;
1372 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1375 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1377 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1379 vt->rank = class->rank;
1380 vt->domain = domain;
1382 mono_class_compute_gc_descriptor (class);
1384 * We can't use typed allocation in the non-root domains, since the
1385 * collector needs the GC descriptor stored in the vtable even after
1386 * the mempool containing the vtable is destroyed when the domain is
1387 * unloaded. An alternative might be to allocate vtables in the GC
1388 * heap, but this does not seem to work (it leads to crashes inside
1389 * libgc). If that approach is tried, two gc descriptors need to be
1390 * allocated for each class: one for the root domain, and one for all
1391 * other domains. The second descriptor should contain a bit for the
1392 * vtable field in MonoObject, since we can no longer assume the
1393 * vtable is reachable by other roots after the appdomain is unloaded.
1395 #ifdef HAVE_BOEHM_GC
1396 if (domain != mono_get_root_domain ())
1397 vt->gc_descr = GC_NO_DESCRIPTOR;
1400 vt->gc_descr = class->gc_descr;
1402 if ((class_size = mono_class_data_size (class))) {
1403 if (class->has_static_refs) {
1404 gpointer statics_gc_descr;
1406 gsize default_bitmap [4] = {0};
1409 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1410 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1411 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1412 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1413 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1414 if (bitmap != default_bitmap)
1417 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1419 mono_stats.class_static_data_size += class_size;
1424 while ((field = mono_class_get_fields (class, &iter))) {
1425 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1427 if (mono_field_is_deleted (field))
1429 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1430 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1431 if (special_static != SPECIAL_STATIC_NONE) {
1432 guint32 size, offset;
1434 size = mono_type_size (field->type, &align);
1435 offset = mono_alloc_special_static_data (special_static, size, align);
1436 if (!domain->special_static_fields)
1437 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1438 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1442 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1443 MonoClass *fklass = mono_class_from_mono_type (field->type);
1444 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1445 t = (char*)vt->data + field->offset;
1446 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1449 if (fklass->valuetype) {
1450 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1452 /* it's a pointer type: add check */
1453 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1454 *t = *(char *)field->data;
1458 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1461 /* later do this only on demand if needed */
1463 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1465 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1467 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1468 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1469 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1474 vt->max_interface_id = class->max_interface_id;
1475 vt->interface_bitmap = class->interface_bitmap;
1477 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1478 // class->name, class->interface_offsets_count);
1480 if (! ARCH_USE_IMT) {
1481 /* initialize interface offsets */
1482 for (i = 0; i < class->interface_offsets_count; ++i) {
1483 int interface_id = class->interfaces_packed [i]->interface_id;
1484 int slot = class->interface_offsets_packed [i];
1485 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1490 * arch_create_jit_trampoline () can recursively call this function again
1491 * because it compiles icall methods right away.
1493 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1494 * as we change the code in appdomain.c to invalidate vtables by
1495 * looking at the possible MonoClasses created for the domain.
1497 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1498 /* class->runtime_info is protected by the loader lock, both when
1499 * it it enlarged and when it is stored info.
1501 mono_loader_lock ();
1502 old_info = class->runtime_info;
1503 if (old_info && old_info->max_domain >= domain->domain_id) {
1504 /* someone already created a large enough runtime info */
1505 old_info->domain_vtables [domain->domain_id] = vt;
1507 int new_size = domain->domain_id;
1509 new_size = MAX (new_size, old_info->max_domain);
1511 /* make the new size a power of two */
1513 while (new_size > i)
1516 /* this is a bounded memory retention issue: may want to
1517 * handle it differently when we'll have a rcu-like system.
1519 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1520 runtime_info->max_domain = new_size - 1;
1521 /* copy the stuff from the older info */
1523 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1525 runtime_info->domain_vtables [domain->domain_id] = vt;
1526 /* keep this last (add membarrier) */
1527 class->runtime_info = runtime_info;
1529 mono_loader_unlock ();
1531 /* initialize vtable */
1532 if (init_vtable_func)
1533 inited = init_vtable_func (vt);
1536 mono_class_setup_vtable (class);
1538 for (i = 0; i < class->vtable_size; ++i) {
1541 if ((cm = class->vtable [i])) {
1542 if (mono_method_signature (cm)->generic_param_count)
1543 vt->vtable [i] = cm;
1545 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1550 if (ARCH_USE_IMT && imt_table_bytes) {
1551 /* Now that the vtable is full, we can actually fill up the IMT */
1552 if (imt_trampoline) {
1553 /* lazy construction of the IMT entries enabled */
1554 for (i = 0; i < MONO_IMT_SIZE; ++i)
1555 interface_offsets [i] = imt_trampoline;
1557 build_imt (class, vt, domain, interface_offsets, NULL);
1561 if (class_needs_rgctx (class))
1562 mono_class_setup_runtime_generic_context (class, domain);
1564 mono_domain_unlock (domain);
1566 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1567 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1568 MonoException *exc = mono_class_get_exception_for_failure (class);
1570 mono_raise_exception (exc);
1573 /* make sure the the parent is initialized */
1575 mono_class_vtable (domain, class->parent);
1577 vt->type = mono_type_get_object (domain, &class->byval_arg);
1578 if (class->contextbound)
1587 * mono_class_proxy_vtable:
1588 * @domain: the application domain
1589 * @remove_class: the remote class
1591 * Creates a vtable for transparent proxies. It is basically
1592 * a copy of the real vtable of the class wrapped in @remote_class,
1593 * but all function pointers invoke the remoting functions, and
1594 * vtable->klass points to the transparent proxy class, and not to @class.
1597 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1599 MonoVTable *vt, *pvt;
1600 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1602 GSList *extra_interfaces = NULL;
1603 MonoClass *class = remote_class->proxy_class;
1604 gpointer *interface_offsets;
1606 vt = mono_class_vtable (domain, class);
1607 max_interface_id = vt->max_interface_id;
1609 /* Calculate vtable space for extra interfaces */
1610 for (j = 0; j < remote_class->interface_count; j++) {
1611 MonoClass* iclass = remote_class->interfaces[j];
1615 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1616 continue; /* interface implemented by the class */
1617 if (g_slist_find (extra_interfaces, iclass))
1620 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1622 method_count = mono_class_num_methods (iclass);
1624 ifaces = mono_class_get_implemented_interfaces (iclass);
1626 for (i = 0; i < ifaces->len; ++i) {
1627 MonoClass *ic = g_ptr_array_index (ifaces, i);
1628 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1629 continue; /* interface implemented by the class */
1630 if (g_slist_find (extra_interfaces, ic))
1632 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1633 method_count += mono_class_num_methods (ic);
1635 g_ptr_array_free (ifaces, TRUE);
1638 extra_interface_vtsize += method_count * sizeof (gpointer);
1639 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1643 mono_stats.imt_number_of_tables++;
1644 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1645 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1646 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1648 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1649 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1652 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1654 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1656 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1658 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1659 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1661 pvt->klass = mono_defaults.transparent_proxy_class;
1662 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1663 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1665 /* initialize vtable */
1666 mono_class_setup_vtable (class);
1667 for (i = 0; i < class->vtable_size; ++i) {
1670 if ((cm = class->vtable [i]))
1671 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1672 ? cm : arch_create_remoting_trampoline (cm, target_type);
1675 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1676 /* create trampolines for abstract methods */
1677 for (k = class; k; k = k->parent) {
1679 gpointer iter = NULL;
1680 while ((m = mono_class_get_methods (k, &iter)))
1681 if (!pvt->vtable [m->slot])
1682 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1686 pvt->max_interface_id = max_interface_id;
1687 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1689 if (! ARCH_USE_IMT) {
1690 /* initialize interface offsets */
1691 for (i = 0; i < class->interface_offsets_count; ++i) {
1692 int interface_id = class->interfaces_packed [i]->interface_id;
1693 int slot = class->interface_offsets_packed [i];
1694 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1697 for (i = 0; i < class->interface_offsets_count; ++i) {
1698 int interface_id = class->interfaces_packed [i]->interface_id;
1699 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1702 if (extra_interfaces) {
1703 int slot = class->vtable_size;
1709 /* Create trampolines for the methods of the interfaces */
1710 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1711 interf = list_item->data;
1713 if (! ARCH_USE_IMT) {
1714 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1716 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1720 while ((cm = mono_class_get_methods (interf, &iter)))
1721 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1723 slot += mono_class_num_methods (interf);
1725 if (! ARCH_USE_IMT) {
1726 g_slist_free (extra_interfaces);
1731 /* Now that the vtable is full, we can actually fill up the IMT */
1732 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1733 if (extra_interfaces) {
1734 g_slist_free (extra_interfaces);
1742 * mono_class_has_special_static_fields:
1744 * Returns whenever @klass has any thread/context static fields.
1747 mono_class_has_special_static_fields (MonoClass *klass)
1749 MonoClassField *field;
1753 while ((field = mono_class_get_fields (klass, &iter))) {
1754 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1756 if (mono_field_is_deleted (field))
1758 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1759 if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
1768 * create_remote_class_key:
1769 * Creates an array of pointers that can be used as a hash key for a remote class.
1770 * The first element of the array is the number of pointers.
1773 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1778 if (remote_class == NULL) {
1779 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1780 key = g_malloc (sizeof(gpointer) * 3);
1781 key [0] = GINT_TO_POINTER (2);
1782 key [1] = mono_defaults.marshalbyrefobject_class;
1783 key [2] = extra_class;
1785 key = g_malloc (sizeof(gpointer) * 2);
1786 key [0] = GINT_TO_POINTER (1);
1787 key [1] = extra_class;
1790 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1791 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1792 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1793 key [1] = remote_class->proxy_class;
1795 // Keep the list of interfaces sorted
1796 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1797 if (extra_class && remote_class->interfaces [i] > extra_class) {
1798 key [j++] = extra_class;
1801 key [j] = remote_class->interfaces [i];
1804 key [j] = extra_class;
1806 // Replace the old class. The interface list is the same
1807 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1808 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1809 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1810 for (i = 0; i < remote_class->interface_count; i++)
1811 key [2 + i] = remote_class->interfaces [i];
1819 * copy_remote_class_key:
1821 * Make a copy of KEY in the mempool MP and return the copy.
1824 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1826 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1827 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1829 memcpy (mp_key, key, key_size);
1835 * mono_remote_class:
1836 * @domain: the application domain
1837 * @class_name: name of the remote class
1839 * Creates and initializes a MonoRemoteClass object for a remote type.
1843 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1845 MonoRemoteClass *rc;
1846 gpointer* key, *mp_key;
1848 key = create_remote_class_key (NULL, proxy_class);
1850 mono_domain_lock (domain);
1851 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1855 mono_domain_unlock (domain);
1859 mp_key = copy_remote_class_key (domain->mp, key);
1863 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1864 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1865 rc->interface_count = 1;
1866 rc->interfaces [0] = proxy_class;
1867 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1869 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1870 rc->interface_count = 0;
1871 rc->proxy_class = proxy_class;
1874 rc->default_vtable = NULL;
1875 rc->xdomain_vtable = NULL;
1876 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1878 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1880 mono_domain_unlock (domain);
1885 * clone_remote_class:
1886 * Creates a copy of the remote_class, adding the provided class or interface
1888 static MonoRemoteClass*
1889 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1891 MonoRemoteClass *rc;
1892 gpointer* key, *mp_key;
1894 key = create_remote_class_key (remote_class, extra_class);
1895 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1901 mp_key = copy_remote_class_key (domain->mp, key);
1905 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1907 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1908 rc->proxy_class = remote_class->proxy_class;
1909 rc->interface_count = remote_class->interface_count + 1;
1911 // Keep the list of interfaces sorted, since the hash key of
1912 // the remote class depends on this
1913 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1914 if (remote_class->interfaces [i] > extra_class && i == j)
1915 rc->interfaces [j++] = extra_class;
1916 rc->interfaces [j] = remote_class->interfaces [i];
1919 rc->interfaces [j] = extra_class;
1921 // Replace the old class. The interface array is the same
1922 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1923 rc->proxy_class = extra_class;
1924 rc->interface_count = remote_class->interface_count;
1925 if (rc->interface_count > 0)
1926 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1929 rc->default_vtable = NULL;
1930 rc->xdomain_vtable = NULL;
1931 rc->proxy_class_name = remote_class->proxy_class_name;
1933 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1939 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1941 mono_domain_lock (domain);
1942 if (rp->target_domain_id != -1) {
1943 if (remote_class->xdomain_vtable == NULL)
1944 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1945 mono_domain_unlock (domain);
1946 return remote_class->xdomain_vtable;
1948 if (remote_class->default_vtable == NULL) {
1951 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1952 klass = mono_class_from_mono_type (type);
1953 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1954 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1956 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1959 mono_domain_unlock (domain);
1960 return remote_class->default_vtable;
1964 * mono_upgrade_remote_class:
1965 * @domain: the application domain
1966 * @tproxy: the proxy whose remote class has to be upgraded.
1967 * @klass: class to which the remote class can be casted.
1969 * Updates the vtable of the remote class by adding the necessary method slots
1970 * and interface offsets so it can be safely casted to klass. klass can be a
1971 * class or an interface.
1974 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1976 MonoTransparentProxy *tproxy;
1977 MonoRemoteClass *remote_class;
1978 gboolean redo_vtable;
1980 mono_domain_lock (domain);
1982 tproxy = (MonoTransparentProxy*) proxy_object;
1983 remote_class = tproxy->remote_class;
1985 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1988 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1989 if (remote_class->interfaces [i] == klass)
1990 redo_vtable = FALSE;
1993 redo_vtable = (remote_class->proxy_class != klass);
1997 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1998 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2001 mono_domain_unlock (domain);
2006 * mono_object_get_virtual_method:
2007 * @obj: object to operate on.
2010 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2011 * the instance of a callvirt of method.
2014 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2017 MonoMethod **vtable;
2019 MonoMethod *res = NULL;
2021 klass = mono_object_class (obj);
2022 if (klass == mono_defaults.transparent_proxy_class) {
2023 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2029 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2032 mono_class_setup_vtable (klass);
2033 vtable = klass->vtable;
2035 /* check method->slot is a valid index: perform isinstance? */
2036 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2038 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2040 if (method->slot != -1)
2041 res = vtable [method->slot];
2045 /* It may be an interface, abstract class method or generic method */
2046 if (!res || mono_method_signature (res)->generic_param_count)
2049 /* generic methods demand invoke_with_check */
2050 if (mono_method_signature (res)->generic_param_count)
2051 res = mono_marshal_get_remoting_invoke_with_check (res);
2053 res = mono_marshal_get_remoting_invoke (res);
2062 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2064 g_error ("runtime invoke called on uninitialized runtime");
2068 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2071 * mono_runtime_invoke:
2072 * @method: method to invoke
2073 * @obJ: object instance
2074 * @params: arguments to the method
2075 * @exc: exception information.
2077 * Invokes the method represented by @method on the object @obj.
2079 * obj is the 'this' pointer, it should be NULL for static
2080 * methods, a MonoObject* for object instances and a pointer to
2081 * the value type for value types.
2083 * The params array contains the arguments to the method with the
2084 * same convention: MonoObject* pointers for object instances and
2085 * pointers to the value type otherwise.
2087 * From unmanaged code you'll usually use the
2088 * mono_runtime_invoke() variant.
2090 * Note that this function doesn't handle virtual methods for
2091 * you, it will exec the exact method you pass: we still need to
2092 * expose a function to lookup the derived class implementation
2093 * of a virtual method (there are examples of this in the code,
2096 * You can pass NULL as the exc argument if you don't want to
2097 * catch exceptions, otherwise, *exc will be set to the exception
2098 * thrown, if any. if an exception is thrown, you can't use the
2099 * MonoObject* result from the function.
2101 * If the method returns a value type, it is boxed in an object
2105 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2107 return default_mono_runtime_invoke (method, obj, params, exc);
2111 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2115 gpointer *p = (gpointer*)dest;
2122 case MONO_TYPE_BOOLEAN:
2124 case MONO_TYPE_U1: {
2125 guint8 *p = (guint8*)dest;
2126 *p = value ? *(guint8*)value : 0;
2131 case MONO_TYPE_CHAR: {
2132 guint16 *p = (guint16*)dest;
2133 *p = value ? *(guint16*)value : 0;
2136 #if SIZEOF_VOID_P == 4
2141 case MONO_TYPE_U4: {
2142 gint32 *p = (gint32*)dest;
2143 *p = value ? *(gint32*)value : 0;
2146 #if SIZEOF_VOID_P == 8
2151 case MONO_TYPE_U8: {
2152 gint64 *p = (gint64*)dest;
2153 *p = value ? *(gint64*)value : 0;
2156 case MONO_TYPE_R4: {
2157 float *p = (float*)dest;
2158 *p = value ? *(float*)value : 0;
2161 case MONO_TYPE_R8: {
2162 double *p = (double*)dest;
2163 *p = value ? *(double*)value : 0;
2166 case MONO_TYPE_STRING:
2167 case MONO_TYPE_SZARRAY:
2168 case MONO_TYPE_CLASS:
2169 case MONO_TYPE_OBJECT:
2170 case MONO_TYPE_ARRAY:
2171 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2173 case MONO_TYPE_FNPTR:
2174 case MONO_TYPE_PTR: {
2175 gpointer *p = (gpointer*)dest;
2176 *p = deref_pointer? *(gpointer*)value: value;
2179 case MONO_TYPE_VALUETYPE:
2180 /* note that 't' and 'type->type' can be different */
2181 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2182 t = type->data.klass->enum_basetype->type;
2186 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2188 memset (dest, 0, size);
2190 memcpy (dest, value, size);
2193 case MONO_TYPE_GENERICINST:
2194 t = type->data.generic_class->container_class->byval_arg.type;
2197 g_warning ("got type %x", type->type);
2198 g_assert_not_reached ();
2203 * mono_field_set_value:
2204 * @obj: Instance object
2205 * @field: MonoClassField describing the field to set
2206 * @value: The value to be set
2208 * Sets the value of the field described by @field in the object instance @obj
2209 * to the value passed in @value. This method should only be used for instance
2210 * fields. For static fields, use mono_field_static_set_value.
2212 * The value must be on the native format of the field type.
2215 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2219 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2221 dest = (char*)obj + field->offset;
2222 set_value (field->type, dest, value, FALSE);
2226 * mono_field_static_set_value:
2227 * @field: MonoClassField describing the field to set
2228 * @value: The value to be set
2230 * Sets the value of the static field described by @field
2231 * to the value passed in @value.
2233 * The value must be on the native format of the field type.
2236 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2240 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2241 /* you cant set a constant! */
2242 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2244 dest = (char*)vt->data + field->offset;
2245 set_value (field->type, dest, value, FALSE);
2248 /* Used by the debugger */
2250 mono_vtable_get_static_field_data (MonoVTable *vt)
2256 * mono_field_get_value:
2257 * @obj: Object instance
2258 * @field: MonoClassField describing the field to fetch information from
2259 * @value: pointer to the location where the value will be stored
2261 * Use this routine to get the value of the field @field in the object
2264 * The pointer provided by value must be of the field type, for reference
2265 * types this is a MonoObject*, for value types its the actual pointer to
2270 * mono_field_get_value (obj, int_field, &i);
2273 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2277 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2279 src = (char*)obj + field->offset;
2280 set_value (field->type, value, src, TRUE);
2284 * mono_field_get_value_object:
2285 * @domain: domain where the object will be created (if boxing)
2286 * @field: MonoClassField describing the field to fetch information from
2287 * @obj: The object instance for the field.
2289 * Returns: a new MonoObject with the value from the given field. If the
2290 * field represents a value type, the value is boxed.
2294 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2298 MonoVTable *vtable = NULL;
2300 gboolean is_static = FALSE;
2301 gboolean is_ref = FALSE;
2303 switch (field->type->type) {
2304 case MONO_TYPE_STRING:
2305 case MONO_TYPE_OBJECT:
2306 case MONO_TYPE_CLASS:
2307 case MONO_TYPE_ARRAY:
2308 case MONO_TYPE_SZARRAY:
2313 case MONO_TYPE_BOOLEAN:
2316 case MONO_TYPE_CHAR:
2325 case MONO_TYPE_VALUETYPE:
2326 is_ref = field->type->byref;
2328 case MONO_TYPE_GENERICINST:
2329 is_ref = !field->type->data.generic_class->container_class->valuetype;
2332 g_error ("type 0x%x not handled in "
2333 "mono_field_get_value_object", field->type->type);
2337 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2339 vtable = mono_class_vtable (domain, field->parent);
2340 if (!vtable->initialized)
2341 mono_runtime_class_init (vtable);
2346 mono_field_static_get_value (vtable, field, &o);
2348 mono_field_get_value (obj, field, &o);
2353 /* boxed value type */
2354 klass = mono_class_from_mono_type (field->type);
2355 o = mono_object_new (domain, klass);
2356 v = ((gchar *) o) + sizeof (MonoObject);
2358 mono_field_static_get_value (vtable, field, v);
2360 mono_field_get_value (obj, field, v);
2367 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2370 const char *p = blob;
2371 mono_metadata_decode_blob_size (p, &p);
2374 case MONO_TYPE_BOOLEAN:
2377 *(guint8 *) value = *p;
2379 case MONO_TYPE_CHAR:
2382 *(guint16*) value = read16 (p);
2386 *(guint32*) value = read32 (p);
2390 *(guint64*) value = read64 (p);
2393 readr4 (p, (float*) value);
2396 readr8 (p, (double*) value);
2398 case MONO_TYPE_STRING:
2399 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2401 case MONO_TYPE_CLASS:
2402 *(gpointer*) value = NULL;
2406 g_warning ("type 0x%02x should not be in constant table", type);
2412 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2414 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2415 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2419 * mono_field_static_get_value:
2420 * @vt: vtable to the object
2421 * @field: MonoClassField describing the field to fetch information from
2422 * @value: where the value is returned
2424 * Use this routine to get the value of the static field @field value.
2426 * The pointer provided by value must be of the field type, for reference
2427 * types this is a MonoObject*, for value types its the actual pointer to
2432 * mono_field_static_get_value (vt, int_field, &i);
2435 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2439 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2441 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2442 get_default_field_value (vt->domain, field, value);
2446 src = (char*)vt->data + field->offset;
2447 set_value (field->type, value, src, TRUE);
2451 * mono_property_set_value:
2452 * @prop: MonoProperty to set
2453 * @obj: instance object on which to act
2454 * @params: parameters to pass to the propery
2455 * @exc: optional exception
2457 * Invokes the property's set method with the given arguments on the
2458 * object instance obj (or NULL for static properties).
2460 * You can pass NULL as the exc argument if you don't want to
2461 * catch exceptions, otherwise, *exc will be set to the exception
2462 * thrown, if any. if an exception is thrown, you can't use the
2463 * MonoObject* result from the function.
2466 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2468 default_mono_runtime_invoke (prop->set, obj, params, exc);
2472 * mono_property_get_value:
2473 * @prop: MonoProperty to fetch
2474 * @obj: instance object on which to act
2475 * @params: parameters to pass to the propery
2476 * @exc: optional exception
2478 * Invokes the property's get method with the given arguments on the
2479 * object instance obj (or NULL for static properties).
2481 * You can pass NULL as the exc argument if you don't want to
2482 * catch exceptions, otherwise, *exc will be set to the exception
2483 * thrown, if any. if an exception is thrown, you can't use the
2484 * MonoObject* result from the function.
2486 * Returns: the value from invoking the get method on the property.
2489 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2491 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2495 * mono_nullable_init:
2496 * @buf: The nullable structure to initialize.
2497 * @value: the value to initialize from
2498 * @klass: the type for the object
2500 * Initialize the nullable structure pointed to by @buf from @value which
2501 * should be a boxed value type. The size of @buf should be able to hold
2502 * as much data as the @klass->instance_size (which is the number of bytes
2503 * that will be copies).
2505 * Since Nullables have variable structure, we can not define a C
2506 * structure for them.
2509 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2511 MonoClass *param_class = klass->cast_class;
2513 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2514 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2516 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2518 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2520 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2524 * mono_nullable_box:
2525 * @buf: The buffer representing the data to be boxed
2526 * @klass: the type to box it as.
2528 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2532 mono_nullable_box (guint8 *buf, MonoClass *klass)
2534 MonoClass *param_class = klass->cast_class;
2536 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2537 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2539 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2540 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2541 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2549 * mono_get_delegate_invoke:
2550 * @klass: The delegate class
2552 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2555 mono_get_delegate_invoke (MonoClass *klass)
2559 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2566 * mono_runtime_delegate_invoke:
2567 * @delegate: pointer to a delegate object.
2568 * @params: parameters for the delegate.
2569 * @exc: Pointer to the exception result.
2571 * Invokes the delegate method @delegate with the parameters provided.
2573 * You can pass NULL as the exc argument if you don't want to
2574 * catch exceptions, otherwise, *exc will be set to the exception
2575 * thrown, if any. if an exception is thrown, you can't use the
2576 * MonoObject* result from the function.
2579 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2583 im = mono_get_delegate_invoke (delegate->vtable->klass);
2586 return mono_runtime_invoke (im, delegate, params, exc);
2589 static char **main_args = NULL;
2590 static int num_main_args;
2593 * mono_runtime_get_main_args:
2595 * Returns: a MonoArray with the arguments passed to the main program
2598 mono_runtime_get_main_args (void)
2602 MonoDomain *domain = mono_domain_get ();
2607 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2609 for (i = 0; i < num_main_args; ++i)
2610 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2616 fire_process_exit_event (void)
2618 MonoClassField *field;
2619 MonoDomain *domain = mono_domain_get ();
2621 MonoObject *delegate, *exc;
2623 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2626 if (domain != mono_get_root_domain ())
2629 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2630 if (delegate == NULL)
2635 mono_runtime_delegate_invoke (delegate, pa, &exc);
2639 * mono_runtime_run_main:
2640 * @method: the method to start the application with (usually Main)
2641 * @argc: number of arguments from the command line
2642 * @argv: array of strings from the command line
2643 * @exc: excetption results
2645 * Execute a standard Main() method (argc/argv contains the
2646 * executable name). This method also sets the command line argument value
2647 * needed by System.Environment.
2652 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2656 MonoArray *args = NULL;
2657 MonoDomain *domain = mono_domain_get ();
2658 gchar *utf8_fullpath;
2661 g_assert (method != NULL);
2663 mono_thread_set_main (mono_thread_current ());
2665 main_args = g_new0 (char*, argc);
2666 num_main_args = argc;
2668 if (!g_path_is_absolute (argv [0])) {
2669 gchar *basename = g_path_get_basename (argv [0]);
2670 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2674 utf8_fullpath = mono_utf8_from_external (fullpath);
2675 if(utf8_fullpath == NULL) {
2676 /* Printing the arg text will cause glib to
2677 * whinge about "Invalid UTF-8", but at least
2678 * its relevant, and shows the problem text
2681 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2682 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2689 utf8_fullpath = mono_utf8_from_external (argv[0]);
2690 if(utf8_fullpath == NULL) {
2691 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2692 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2697 main_args [0] = utf8_fullpath;
2699 for (i = 1; i < argc; ++i) {
2702 utf8_arg=mono_utf8_from_external (argv[i]);
2703 if(utf8_arg==NULL) {
2704 /* Ditto the comment about Invalid UTF-8 here */
2705 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2706 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2710 main_args [i] = utf8_arg;
2714 if (mono_method_signature (method)->param_count) {
2715 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2716 for (i = 0; i < argc; ++i) {
2717 /* The encodings should all work, given that
2718 * we've checked all these args for the
2721 gchar *str = mono_utf8_from_external (argv [i]);
2722 MonoString *arg = mono_string_new (domain, str);
2723 mono_array_setref (args, i, arg);
2727 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2730 mono_assembly_set_main (method->klass->image->assembly);
2732 result = mono_runtime_exec_main (method, args, exc);
2733 fire_process_exit_event ();
2737 /* Used in call_unhandled_exception_delegate */
2739 create_unhandled_exception_eventargs (MonoObject *exc)
2743 MonoMethod *method = NULL;
2744 MonoBoolean is_terminating = TRUE;
2747 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2750 mono_class_init (klass);
2752 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2753 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2757 args [1] = &is_terminating;
2759 obj = mono_object_new (mono_domain_get (), klass);
2760 mono_runtime_invoke (method, obj, args, NULL);
2765 /* Used in mono_unhandled_exception */
2767 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2768 MonoObject *e = NULL;
2771 pa [0] = domain->domain;
2772 pa [1] = create_unhandled_exception_eventargs (exc);
2773 mono_runtime_delegate_invoke (delegate, pa, &e);
2776 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2777 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2782 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2785 * mono_runtime_unhandled_exception_policy_set:
2786 * @policy: the new policy
2788 * This is a VM internal routine.
2790 * Sets the runtime policy for handling unhandled exceptions.
2793 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2794 runtime_unhandled_exception_policy = policy;
2798 * mono_runtime_unhandled_exception_policy_get:
2800 * This is a VM internal routine.
2802 * Gets the runtime policy for handling unhandled exceptions.
2804 MonoRuntimeUnhandledExceptionPolicy
2805 mono_runtime_unhandled_exception_policy_get (void) {
2806 return runtime_unhandled_exception_policy;
2810 * mono_unhandled_exception:
2811 * @exc: exception thrown
2813 * This is a VM internal routine.
2815 * We call this function when we detect an unhandled exception
2816 * in the default domain.
2818 * It invokes the * UnhandledException event in AppDomain or prints
2819 * a warning to the console
2822 mono_unhandled_exception (MonoObject *exc)
2824 MonoDomain *current_domain = mono_domain_get ();
2825 MonoDomain *root_domain = mono_get_root_domain ();
2826 MonoClassField *field;
2827 MonoObject *current_appdomain_delegate;
2828 MonoObject *root_appdomain_delegate;
2830 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2831 "UnhandledException");
2834 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2835 gboolean abort_process = (mono_thread_current () == main_thread) ||
2836 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2837 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2838 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2839 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2841 current_appdomain_delegate = NULL;
2844 /* set exitcode only if we will abort the process */
2846 mono_environment_exitcode_set (1);
2847 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2848 mono_print_unhandled_exception (exc);
2850 if (root_appdomain_delegate) {
2851 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2853 if (current_appdomain_delegate) {
2854 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2861 * Launch a new thread to execute a function
2863 * main_func is called back from the thread with main_args as the
2864 * parameter. The callback function is expected to start Main()
2865 * eventually. This function then waits for all managed threads to
2867 * It is not necesseray anymore to execute managed code in a subthread,
2868 * so this function should not be used anymore by default: just
2869 * execute the code and then call mono_thread_manage ().
2872 mono_runtime_exec_managed_code (MonoDomain *domain,
2873 MonoMainThreadFunc main_func,
2876 mono_thread_create (domain, main_func, main_args);
2878 mono_thread_manage ();
2882 * Execute a standard Main() method (args doesn't contain the
2886 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2891 MonoCustomAttrInfo* cinfo;
2892 gboolean has_stathread_attribute;
2893 MonoThread* thread = mono_thread_current ();
2899 domain = mono_object_domain (args);
2900 if (!domain->entry_assembly) {
2902 MonoAssembly *assembly;
2904 assembly = method->klass->image->assembly;
2905 domain->entry_assembly = assembly;
2906 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2908 str = g_strconcat (assembly->image->name, ".config", NULL);
2909 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2913 cinfo = mono_custom_attrs_from_method (method);
2915 static MonoClass *stathread_attribute = NULL;
2916 if (!stathread_attribute)
2917 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
2918 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
2920 mono_custom_attrs_free (cinfo);
2922 has_stathread_attribute = FALSE;
2924 if (has_stathread_attribute) {
2925 thread->apartment_state = ThreadApartmentState_STA;
2926 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
2927 thread->apartment_state = ThreadApartmentState_Unknown;
2929 thread->apartment_state = ThreadApartmentState_MTA;
2931 mono_thread_init_apartment_state ();
2933 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
2935 /* FIXME: check signature of method */
2936 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
2938 res = mono_runtime_invoke (method, NULL, pa, exc);
2940 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
2944 mono_environment_exitcode_set (rval);
2946 mono_runtime_invoke (method, NULL, pa, exc);
2950 /* If the return type of Main is void, only
2951 * set the exitcode if an exception was thrown
2952 * (we don't want to blow away an
2953 * explicitly-set exit code)
2956 mono_environment_exitcode_set (rval);
2960 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
2966 * mono_install_runtime_invoke:
2967 * @func: Function to install
2969 * This is a VM internal routine
2972 mono_install_runtime_invoke (MonoInvokeFunc func)
2974 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2979 * mono_runtime_invoke_array:
2980 * @method: method to invoke
2981 * @obJ: object instance
2982 * @params: arguments to the method
2983 * @exc: exception information.
2985 * Invokes the method represented by @method on the object @obj.
2987 * obj is the 'this' pointer, it should be NULL for static
2988 * methods, a MonoObject* for object instances and a pointer to
2989 * the value type for value types.
2991 * The params array contains the arguments to the method with the
2992 * same convention: MonoObject* pointers for object instances and
2993 * pointers to the value type otherwise. The _invoke_array
2994 * variant takes a C# object[] as the params argument (MonoArray
2995 * *params): in this case the value types are boxed inside the
2996 * respective reference representation.
2998 * From unmanaged code you'll usually use the
2999 * mono_runtime_invoke() variant.
3001 * Note that this function doesn't handle virtual methods for
3002 * you, it will exec the exact method you pass: we still need to
3003 * expose a function to lookup the derived class implementation
3004 * of a virtual method (there are examples of this in the code,
3007 * You can pass NULL as the exc argument if you don't want to
3008 * catch exceptions, otherwise, *exc will be set to the exception
3009 * thrown, if any. if an exception is thrown, you can't use the
3010 * MonoObject* result from the function.
3012 * If the method returns a value type, it is boxed in an object
3016 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3019 MonoMethodSignature *sig = mono_method_signature (method);
3020 gpointer *pa = NULL;
3023 if (NULL != params) {
3024 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3025 for (i = 0; i < mono_array_length (params); i++) {
3026 MonoType *t = sig->params [i];
3032 case MONO_TYPE_BOOLEAN:
3035 case MONO_TYPE_CHAR:
3044 case MONO_TYPE_VALUETYPE:
3045 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3048 g_assert_not_reached ();
3049 /* The runtime invoke wrapper needs the original boxed vtype */
3050 pa [i] = mono_array_get (params, MonoObject*, i);
3052 /* MS seems to create the objects if a null is passed in */
3053 if (!mono_array_get (params, MonoObject*, i))
3054 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3058 * We can't pass the unboxed vtype byref to the callee, since
3059 * that would mean the callee would be able to modify boxed
3060 * primitive types. So we (and MS) make a copy of the boxed
3061 * object, pass that to the callee, and replace the original
3062 * boxed object in the arg array with the copy.
3064 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3065 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3066 mono_array_setref (params, i, copy);
3069 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3072 case MONO_TYPE_STRING:
3073 case MONO_TYPE_OBJECT:
3074 case MONO_TYPE_CLASS:
3075 case MONO_TYPE_ARRAY:
3076 case MONO_TYPE_SZARRAY:
3078 pa [i] = mono_array_addr (params, MonoObject*, i);
3079 // FIXME: I need to check this code path
3081 pa [i] = mono_array_get (params, MonoObject*, i);
3083 case MONO_TYPE_GENERICINST:
3085 t = &t->data.generic_class->container_class->this_arg;
3087 t = &t->data.generic_class->container_class->byval_arg;
3090 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3095 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3098 if (mono_class_is_nullable (method->klass)) {
3099 /* Need to create a boxed vtype instead */
3105 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3109 obj = mono_object_new (mono_domain_get (), method->klass);
3110 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3111 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3113 if (method->klass->valuetype)
3114 o = mono_object_unbox (obj);
3117 } else if (method->klass->valuetype) {
3118 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3121 mono_runtime_invoke (method, o, pa, exc);
3124 if (mono_class_is_nullable (method->klass)) {
3125 MonoObject *nullable;
3127 /* Convert the unboxed vtype into a Nullable structure */
3128 nullable = mono_object_new (mono_domain_get (), method->klass);
3130 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3131 obj = mono_object_unbox (nullable);
3134 /* obj must be already unboxed if needed */
3135 return mono_runtime_invoke (method, obj, pa, exc);
3140 arith_overflow (void)
3142 mono_raise_exception (mono_get_exception_overflow ());
3146 * mono_object_allocate:
3147 * @size: number of bytes to allocate
3149 * This is a very simplistic routine until we have our GC-aware
3152 * Returns: an allocated object of size @size, or NULL on failure.
3154 static inline void *
3155 mono_object_allocate (size_t size, MonoVTable *vtable)
3158 mono_stats.new_object_count++;
3159 ALLOC_OBJECT (o, vtable, size);
3165 * mono_object_allocate_ptrfree:
3166 * @size: number of bytes to allocate
3168 * Note that the memory allocated is not zeroed.
3169 * Returns: an allocated object of size @size, or NULL on failure.
3171 static inline void *
3172 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3175 mono_stats.new_object_count++;
3176 ALLOC_PTRFREE (o, vtable, size);
3180 static inline void *
3181 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3184 ALLOC_TYPED (o, size, vtable);
3185 mono_stats.new_object_count++;
3192 * @klass: the class of the object that we want to create
3194 * Returns: a newly created object whose definition is
3195 * looked up using @klass. This will not invoke any constructors,
3196 * so the consumer of this routine has to invoke any constructors on
3197 * its own to initialize the object.
3200 mono_object_new (MonoDomain *domain, MonoClass *klass)
3202 MONO_ARCH_SAVE_REGS;
3203 return mono_object_new_specific (mono_class_vtable (domain, klass));
3207 * mono_object_new_specific:
3208 * @vtable: the vtable of the object that we want to create
3210 * Returns: A newly created object with class and domain specified
3214 mono_object_new_specific (MonoVTable *vtable)
3218 MONO_ARCH_SAVE_REGS;
3220 /* check for is_com_object for COM Interop */
3221 if (vtable->remote || vtable->klass->is_com_object)
3224 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3227 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3230 mono_class_init (klass);
3232 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3234 vtable->domain->create_proxy_for_type_method = im;
3237 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3239 o = mono_runtime_invoke (im, NULL, pa, NULL);
3240 if (o != NULL) return o;
3243 return mono_object_new_alloc_specific (vtable);
3247 mono_object_new_alloc_specific (MonoVTable *vtable)
3251 if (!vtable->klass->has_references) {
3252 o = mono_object_new_ptrfree (vtable);
3253 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3254 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3256 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3257 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3259 if (vtable->klass->has_finalize)
3260 mono_object_register_finalizer (o);
3262 mono_profiler_allocation (o, vtable->klass);
3267 mono_object_new_fast (MonoVTable *vtable)
3270 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3275 mono_object_new_ptrfree (MonoVTable *vtable)
3278 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3279 #if NEED_TO_ZERO_PTRFREE
3280 /* an inline memset is much faster for the common vcase of small objects
3281 * note we assume the allocated size is a multiple of sizeof (void*).
3283 if (vtable->klass->instance_size < 128) {
3285 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3286 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3292 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3299 mono_object_new_ptrfree_box (MonoVTable *vtable)
3302 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3303 /* the object will be boxed right away, no need to memzero it */
3308 * mono_class_get_allocation_ftn:
3310 * @for_box: the object will be used for boxing
3311 * @pass_size_in_words:
3313 * Return the allocation function appropriate for the given class.
3317 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3319 *pass_size_in_words = FALSE;
3321 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3322 return mono_object_new_specific;
3324 if (!vtable->klass->has_references) {
3325 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3327 return mono_object_new_ptrfree_box;
3328 return mono_object_new_ptrfree;
3331 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3333 return mono_object_new_fast;
3336 * FIXME: This is actually slower than mono_object_new_fast, because
3337 * of the overhead of parameter passing.
3340 *pass_size_in_words = TRUE;
3341 #ifdef GC_REDIRECT_TO_LOCAL
3342 return GC_local_gcj_fast_malloc;
3344 return GC_gcj_fast_malloc;
3349 return mono_object_new_specific;
3353 * mono_object_new_from_token:
3354 * @image: Context where the type_token is hosted
3355 * @token: a token of the type that we want to create
3357 * Returns: A newly created object whose definition is
3358 * looked up using @token in the @image image
3361 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3365 class = mono_class_get (image, token);
3367 return mono_object_new (domain, class);
3372 * mono_object_clone:
3373 * @obj: the object to clone
3375 * Returns: A newly created object who is a shallow copy of @obj
3378 mono_object_clone (MonoObject *obj)
3383 size = obj->vtable->klass->instance_size;
3384 o = mono_object_allocate (size, obj->vtable);
3385 /* do not copy the sync state */
3386 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3389 if (obj->vtable->klass->has_references)
3390 mono_gc_wbarrier_object (o);
3392 mono_profiler_allocation (o, obj->vtable->klass);
3394 if (obj->vtable->klass->has_finalize)
3395 mono_object_register_finalizer (o);
3400 * mono_array_full_copy:
3401 * @src: source array to copy
3402 * @dest: destination array
3404 * Copies the content of one array to another with exactly the same type and size.
3407 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3410 MonoClass *klass = src->obj.vtable->klass;
3412 MONO_ARCH_SAVE_REGS;
3414 g_assert (klass == dest->obj.vtable->klass);
3416 size = mono_array_length (src);
3417 g_assert (size == mono_array_length (dest));
3418 size *= mono_array_element_size (klass);
3420 if (klass->element_class->valuetype) {
3421 if (klass->element_class->has_references)
3422 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3424 memcpy (&dest->vector, &src->vector, size);
3426 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3429 memcpy (&dest->vector, &src->vector, size);
3434 * mono_array_clone_in_domain:
3435 * @domain: the domain in which the array will be cloned into
3436 * @array: the array to clone
3438 * This routine returns a copy of the array that is hosted on the
3439 * specified MonoDomain.
3442 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3447 MonoClass *klass = array->obj.vtable->klass;
3449 MONO_ARCH_SAVE_REGS;
3451 if (array->bounds == NULL) {
3452 size = mono_array_length (array);
3453 o = mono_array_new_full (domain, klass, &size, NULL);
3455 size *= mono_array_element_size (klass);
3457 if (klass->element_class->valuetype) {
3458 if (klass->element_class->has_references)
3459 mono_value_copy_array (o, 0, array, mono_array_length (array));
3461 memcpy (&o->vector, &array->vector, size);
3463 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3466 memcpy (&o->vector, &array->vector, size);
3471 sizes = alloca (klass->rank * sizeof(guint32) * 2);
3472 size = mono_array_element_size (klass);
3473 for (i = 0; i < klass->rank; ++i) {
3474 sizes [i] = array->bounds [i].length;
3475 size *= array->bounds [i].length;
3476 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3478 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3480 if (klass->element_class->valuetype) {
3481 if (klass->element_class->has_references)
3482 mono_value_copy_array (o, 0, array, mono_array_length (array));
3484 memcpy (&o->vector, &array->vector, size);
3486 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3489 memcpy (&o->vector, &array->vector, size);
3497 * @array: the array to clone
3499 * Returns: A newly created array who is a shallow copy of @array
3502 mono_array_clone (MonoArray *array)
3504 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3507 /* helper macros to check for overflow when calculating the size of arrays */
3508 #define MYGUINT32_MAX 4294967295U
3509 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3510 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
3511 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3512 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
3513 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
3516 * mono_array_new_full:
3517 * @domain: domain where the object is created
3518 * @array_class: array class
3519 * @lengths: lengths for each dimension in the array
3520 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3522 * This routine creates a new array objects with the given dimensions,
3523 * lower bounds and type.
3526 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
3528 guint32 byte_len, len, bounds_size;
3534 if (!array_class->inited)
3535 mono_class_init (array_class);
3537 byte_len = mono_array_element_size (array_class);
3540 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3541 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3547 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3549 for (i = 0; i < array_class->rank; ++i) {
3550 if ((int) lengths [i] < 0)
3552 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3553 mono_gc_out_of_memory (MYGUINT32_MAX);
3558 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3559 mono_gc_out_of_memory (MYGUINT32_MAX);
3561 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3562 mono_gc_out_of_memory (MYGUINT32_MAX);
3563 byte_len += sizeof (MonoArray);
3566 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3567 mono_gc_out_of_memory (MYGUINT32_MAX);
3568 byte_len = (byte_len + 3) & ~3;
3569 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3570 mono_gc_out_of_memory (MYGUINT32_MAX);
3571 byte_len += bounds_size;
3574 * Following three lines almost taken from mono_object_new ():
3575 * they need to be kept in sync.
3577 vtable = mono_class_vtable (domain, array_class);
3578 if (!array_class->has_references) {
3579 o = mono_object_allocate_ptrfree (byte_len, vtable);
3580 #if NEED_TO_ZERO_PTRFREE
3581 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3583 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3584 o = mono_object_allocate_spec (byte_len, vtable);
3586 o = mono_object_allocate (byte_len, vtable);
3589 array = (MonoArray*)o;
3590 array->max_length = len;
3593 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3594 array->bounds = bounds;
3595 for (i = 0; i < array_class->rank; ++i) {
3596 bounds [i].length = lengths [i];
3598 bounds [i].lower_bound = lower_bounds [i];
3602 mono_profiler_allocation (o, array_class);
3609 * @domain: domain where the object is created
3610 * @eclass: element class
3611 * @n: number of array elements
3613 * This routine creates a new szarray with @n elements of type @eclass.
3616 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
3620 MONO_ARCH_SAVE_REGS;
3622 ac = mono_array_class_get (eclass, 1);
3623 g_assert (ac != NULL);
3625 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3629 * mono_array_new_specific:
3630 * @vtable: a vtable in the appropriate domain for an initialized class
3631 * @n: number of array elements
3633 * This routine is a fast alternative to mono_array_new() for code which
3634 * can be sure about the domain it operates in.
3637 mono_array_new_specific (MonoVTable *vtable, guint32 n)
3641 guint32 byte_len, elem_size;
3643 MONO_ARCH_SAVE_REGS;
3648 elem_size = mono_array_element_size (vtable->klass);
3649 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
3650 mono_gc_out_of_memory (MYGUINT32_MAX);
3651 byte_len = n * elem_size;
3652 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3653 mono_gc_out_of_memory (MYGUINT32_MAX);
3654 byte_len += sizeof (MonoArray);
3655 if (!vtable->klass->has_references) {
3656 o = mono_object_allocate_ptrfree (byte_len, vtable);
3657 #if NEED_TO_ZERO_PTRFREE
3658 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3660 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3661 o = mono_object_allocate_spec (byte_len, vtable);
3663 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3664 o = mono_object_allocate (byte_len, vtable);
3667 ao = (MonoArray *)o;
3670 mono_profiler_allocation (o, vtable->klass);
3676 * mono_string_new_utf16:
3677 * @text: a pointer to an utf16 string
3678 * @len: the length of the string
3680 * Returns: A newly created string object which contains @text.
3683 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3687 s = mono_string_new_size (domain, len);
3688 g_assert (s != NULL);
3690 memcpy (mono_string_chars (s), text, len * 2);
3696 * mono_string_new_size:
3697 * @text: a pointer to an utf16 string
3698 * @len: the length of the string
3700 * Returns: A newly created string object of @len
3703 mono_string_new_size (MonoDomain *domain, gint32 len)
3707 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3709 /* overflow ? can't fit it, can't allocate it! */
3711 mono_gc_out_of_memory (-1);
3713 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3715 s = mono_object_allocate_ptrfree (size, vtable);
3718 #if NEED_TO_ZERO_PTRFREE
3721 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3727 * mono_string_new_len:
3728 * @text: a pointer to an utf8 string
3729 * @length: number of bytes in @text to consider
3731 * Returns: A newly created string object which contains @text.
3734 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3736 GError *error = NULL;
3737 MonoString *o = NULL;
3739 glong items_written;
3741 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3744 o = mono_string_new_utf16 (domain, ut, items_written);
3746 g_error_free (error);
3755 * @text: a pointer to an utf8 string
3757 * Returns: A newly created string object which contains @text.
3760 mono_string_new (MonoDomain *domain, const char *text)
3762 GError *error = NULL;
3763 MonoString *o = NULL;
3765 glong items_written;
3770 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3773 o = mono_string_new_utf16 (domain, ut, items_written);
3775 g_error_free (error);
3783 * mono_string_new_wrapper:
3784 * @text: pointer to utf8 characters.
3786 * Helper function to create a string object from @text in the current domain.
3789 mono_string_new_wrapper (const char *text)
3791 MonoDomain *domain = mono_domain_get ();
3793 MONO_ARCH_SAVE_REGS;
3796 return mono_string_new (domain, text);
3803 * @class: the class of the value
3804 * @value: a pointer to the unboxed data
3806 * Returns: A newly created object which contains @value.
3809 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3815 g_assert (class->valuetype);
3817 vtable = mono_class_vtable (domain, class);
3818 size = mono_class_instance_size (class);
3819 res = mono_object_new_alloc_specific (vtable);
3820 mono_profiler_allocation (res, class);
3822 size = size - sizeof (MonoObject);
3825 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3828 #if NO_UNALIGNED_ACCESS
3829 memcpy ((char *)res + sizeof (MonoObject), value, size);
3833 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3836 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3839 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3842 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3845 memcpy ((char *)res + sizeof (MonoObject), value, size);
3848 if (class->has_finalize)
3849 mono_object_register_finalizer (res);
3855 * @dest: destination pointer
3856 * @src: source pointer
3857 * @klass: a valuetype class
3859 * Copy a valuetype from @src to @dest. This function must be used
3860 * when @klass contains references fields.
3863 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3865 int size = mono_class_value_size (klass, NULL);
3866 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3867 memcpy (dest, src, size);
3871 * mono_value_copy_array:
3872 * @dest: destination array
3873 * @dest_idx: index in the @dest array
3874 * @src: source pointer
3875 * @count: number of items
3877 * Copy @count valuetype items from @src to @dest. This function must be used
3878 * when @klass contains references fields.
3879 * Overlap is handled.
3882 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3884 int size = mono_array_element_size (dest->obj.vtable->klass);
3885 char *d = mono_array_addr_with_size (dest, size, dest_idx);
3886 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3887 memmove (d, src, size * count);
3891 * mono_object_get_domain:
3892 * @obj: object to query
3894 * Returns: the MonoDomain where the object is hosted
3897 mono_object_get_domain (MonoObject *obj)
3899 return mono_object_domain (obj);
3903 * mono_object_get_class:
3904 * @obj: object to query
3906 * Returns: the MonOClass of the object.
3909 mono_object_get_class (MonoObject *obj)
3911 return mono_object_class (obj);
3914 * mono_object_get_size:
3915 * @o: object to query
3917 * Returns: the size, in bytes, of @o
3920 mono_object_get_size (MonoObject* o)
3922 MonoClass* klass = mono_object_class (o);
3923 if (klass == mono_defaults.string_class) {
3924 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
3925 } else if (o->vtable->rank) {
3926 MonoArray *array = (MonoArray*)o;
3927 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
3928 if (array->bounds) {
3931 size += sizeof (MonoArrayBounds) * o->vtable->rank;
3935 return mono_class_instance_size (klass);
3940 * mono_object_unbox:
3941 * @obj: object to unbox
3943 * Returns: a pointer to the start of the valuetype boxed in this
3946 * This method will assert if the object passed is not a valuetype.
3949 mono_object_unbox (MonoObject *obj)
3951 /* add assert for valuetypes? */
3952 g_assert (obj->vtable->klass->valuetype);
3953 return ((char*)obj) + sizeof (MonoObject);
3957 * mono_object_isinst:
3959 * @klass: a pointer to a class
3961 * Returns: @obj if @obj is derived from @klass
3964 mono_object_isinst (MonoObject *obj, MonoClass *klass)
3967 mono_class_init (klass);
3969 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3970 return mono_object_isinst_mbyref (obj, klass);
3975 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
3979 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
3988 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3989 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
3993 MonoClass *oklass = vt->klass;
3994 if ((oklass == mono_defaults.transparent_proxy_class))
3995 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
3997 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4001 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4003 MonoDomain *domain = mono_domain_get ();
4005 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4006 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4007 MonoMethod *im = NULL;
4010 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4011 im = mono_object_get_virtual_method (rp, im);
4014 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4017 res = mono_runtime_invoke (im, rp, pa, NULL);
4019 if (*(MonoBoolean *) mono_object_unbox(res)) {
4020 /* Update the vtable of the remote type, so it can safely cast to this new type */
4021 mono_upgrade_remote_class (domain, obj, klass);
4030 * mono_object_castclass_mbyref:
4032 * @klass: a pointer to a class
4034 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4037 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4039 if (!obj) return NULL;
4040 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4042 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4044 "InvalidCastException"));
4049 MonoDomain *orig_domain;
4055 str_lookup (MonoDomain *domain, gpointer user_data)
4057 LDStrInfo *info = user_data;
4058 if (info->res || domain == info->orig_domain)
4060 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4066 mono_string_get_pinned (MonoString *str)
4070 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4071 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4072 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4073 news->length = mono_string_length (str);
4078 #define mono_string_get_pinned(str) (str)
4082 mono_string_is_interned_lookup (MonoString *str, int insert)
4084 MonoGHashTable *ldstr_table;
4088 domain = ((MonoObject *)str)->vtable->domain;
4089 ldstr_table = domain->ldstr_table;
4091 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4096 str = mono_string_get_pinned (str);
4097 mono_g_hash_table_insert (ldstr_table, str, str);
4101 LDStrInfo ldstr_info;
4102 ldstr_info.orig_domain = domain;
4103 ldstr_info.ins = str;
4104 ldstr_info.res = NULL;
4106 mono_domain_foreach (str_lookup, &ldstr_info);
4107 if (ldstr_info.res) {
4109 * the string was already interned in some other domain:
4110 * intern it in the current one as well.
4112 mono_g_hash_table_insert (ldstr_table, str, str);
4122 * mono_string_is_interned:
4123 * @o: String to probe
4125 * Returns whether the string has been interned.
4128 mono_string_is_interned (MonoString *o)
4130 return mono_string_is_interned_lookup (o, FALSE);
4134 * mono_string_intern:
4135 * @o: String to intern
4137 * Interns the string passed.
4138 * Returns: The interned string.
4141 mono_string_intern (MonoString *str)
4143 return mono_string_is_interned_lookup (str, TRUE);
4148 * @domain: the domain where the string will be used.
4149 * @image: a metadata context
4150 * @idx: index into the user string table.
4152 * Implementation for the ldstr opcode.
4153 * Returns: a loaded string from the @image/@idx combination.
4156 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4158 MONO_ARCH_SAVE_REGS;
4161 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4163 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4167 * mono_ldstr_metdata_sig
4168 * @domain: the domain for the string
4169 * @sig: the signature of a metadata string
4171 * Returns: a MonoString for a string stored in the metadata
4174 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4176 const char *str = sig;
4177 MonoString *o, *interned;
4180 len2 = mono_metadata_decode_blob_size (str, &str);
4183 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4184 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4187 guint16 *p2 = (guint16*)mono_string_chars (o);
4188 for (i = 0; i < len2; ++i) {
4189 *p2 = GUINT16_FROM_LE (*p2);
4195 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4197 /* o will get garbage collected */
4201 o = mono_string_get_pinned (o);
4202 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4209 * mono_string_to_utf8:
4210 * @s: a System.String
4212 * Return the UTF8 representation for @s.
4213 * the resulting buffer nedds to be freed with g_free().
4216 mono_string_to_utf8 (MonoString *s)
4220 GError *error = NULL;
4226 return g_strdup ("");
4228 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4230 MonoException *exc = mono_get_exception_argument ("string", error->message);
4231 g_error_free (error);
4232 mono_raise_exception(exc);
4234 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4235 if (s->length > written) {
4236 /* allocate the total length and copy the part of the string that has been converted */
4237 char *as2 = g_malloc0 (s->length);
4238 memcpy (as2, as, written);
4247 * mono_string_to_utf16:
4250 * Return an null-terminated array of the utf-16 chars
4251 * contained in @s. The result must be freed with g_free().
4252 * This is a temporary helper until our string implementation
4253 * is reworked to always include the null terminating char.
4256 mono_string_to_utf16 (MonoString *s)
4263 as = g_malloc ((s->length * 2) + 2);
4264 as [(s->length * 2)] = '\0';
4265 as [(s->length * 2) + 1] = '\0';
4268 return (gunichar2 *)(as);
4271 memcpy (as, mono_string_chars(s), s->length * 2);
4272 return (gunichar2 *)(as);
4276 * mono_string_from_utf16:
4277 * @data: the UTF16 string (LPWSTR) to convert
4279 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4281 * Returns: a MonoString.
4284 mono_string_from_utf16 (gunichar2 *data)
4286 MonoDomain *domain = mono_domain_get ();
4292 while (data [len]) len++;
4294 return mono_string_new_utf16 (domain, data, len);
4298 * mono_string_to_utf8_mp:
4299 * @s: a System.String
4301 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4304 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4306 char *r = mono_string_to_utf8 (s);
4313 len = strlen (r) + 1;
4314 mp_s = mono_mempool_alloc (mp, len);
4315 memcpy (mp_s, r, len);
4323 default_ex_handler (MonoException *ex)
4325 MonoObject *o = (MonoObject*)ex;
4326 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4330 static MonoExceptionFunc ex_handler = default_ex_handler;
4333 * mono_install_handler:
4334 * @func: exception handler
4336 * This is an internal JIT routine used to install the handler for exceptions
4340 mono_install_handler (MonoExceptionFunc func)
4342 ex_handler = func? func: default_ex_handler;
4346 * mono_raise_exception:
4347 * @ex: exception object
4349 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4352 mono_raise_exception (MonoException *ex)
4355 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4356 * that will cause gcc to omit the function epilog, causing problems when
4357 * the JIT tries to walk the stack, since the return address on the stack
4358 * will point into the next function in the executable, not this one.
4361 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4362 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4368 * mono_wait_handle_new:
4369 * @domain: Domain where the object will be created
4370 * @handle: Handle for the wait handle
4372 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4375 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4377 MonoWaitHandle *res;
4378 gpointer params [1];
4379 static MonoMethod *handle_set;
4381 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4383 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4385 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4387 params [0] = &handle;
4388 mono_runtime_invoke (handle_set, res, params, NULL);
4394 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4396 static MonoClassField *f_os_handle;
4397 static MonoClassField *f_safe_handle;
4399 if (!f_os_handle && !f_safe_handle) {
4400 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4401 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4406 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4410 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4416 * mono_async_result_new:
4417 * @domain:domain where the object will be created.
4418 * @handle: wait handle.
4419 * @state: state to pass to AsyncResult
4420 * @data: C closure data.
4422 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4423 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4427 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4429 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4430 MonoMethod *method = mono_get_context_capture_method ();
4432 /* we must capture the execution context from the original thread */
4434 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4435 /* note: result may be null if the flow is suppressed */
4439 MONO_OBJECT_SETREF (res, object_data, object_data);
4440 MONO_OBJECT_SETREF (res, async_state, state);
4442 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4444 res->sync_completed = FALSE;
4445 res->completed = FALSE;
4451 mono_message_init (MonoDomain *domain,
4452 MonoMethodMessage *this,
4453 MonoReflectionMethod *method,
4454 MonoArray *out_args)
4456 MonoMethodSignature *sig = mono_method_signature (method->method);
4462 MONO_OBJECT_SETREF (this, method, method);
4464 MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
4465 MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
4466 this->async_result = NULL;
4467 this->call_type = CallType_Sync;
4469 names = g_new (char *, sig->param_count);
4470 mono_method_get_param_names (method->method, (const char **) names);
4471 MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
4473 for (i = 0; i < sig->param_count; i++) {
4474 name = mono_string_new (domain, names [i]);
4475 mono_array_setref (this->names, i, name);
4479 for (i = 0, j = 0; i < sig->param_count; i++) {
4481 if (sig->params [i]->byref) {
4483 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4484 mono_array_setref (this->args, i, arg);
4488 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4492 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4495 mono_array_set (this->arg_types, guint8, i, arg_type);
4500 * mono_remoting_invoke:
4501 * @real_proxy: pointer to a RealProxy object
4502 * @msg: The MonoMethodMessage to execute
4503 * @exc: used to store exceptions
4504 * @out_args: used to store output arguments
4506 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4507 * IMessage interface and it is not trivial to extract results from there. So
4508 * we call an helper method PrivateInvoke instead of calling
4509 * RealProxy::Invoke() directly.
4511 * Returns: the result object.
4514 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4515 MonoObject **exc, MonoArray **out_args)
4517 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4520 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4523 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4525 real_proxy->vtable->domain->private_invoke_method = im;
4528 pa [0] = real_proxy;
4533 return mono_runtime_invoke (im, NULL, pa, exc);
4537 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4538 MonoObject **exc, MonoArray **out_args)
4542 MonoMethodSignature *sig;
4544 int i, j, outarg_count = 0;
4546 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4548 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4549 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4550 target = tp->rp->unwrapped_server;
4552 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4556 domain = mono_domain_get ();
4557 method = msg->method->method;
4558 sig = mono_method_signature (method);
4560 for (i = 0; i < sig->param_count; i++) {
4561 if (sig->params [i]->byref)
4565 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4566 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
4569 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4571 for (i = 0, j = 0; i < sig->param_count; i++) {
4572 if (sig->params [i]->byref) {
4574 arg = mono_array_get (msg->args, gpointer, i);
4575 mono_array_setref (*out_args, j, arg);
4584 * mono_print_unhandled_exception:
4585 * @exc: The exception
4587 * Prints the unhandled exception.
4590 mono_print_unhandled_exception (MonoObject *exc)
4592 char *message = (char *) "";
4596 gboolean free_message = FALSE;
4598 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4599 klass = exc->vtable->klass;
4601 while (klass && method == NULL) {
4602 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4604 klass = klass->parent;
4609 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4611 message = mono_string_to_utf8 (str);
4612 free_message = TRUE;
4617 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4618 * exc->vtable->klass->name, message);
4620 g_printerr ("\nUnhandled Exception: %s\n", message);
4627 * mono_delegate_ctor:
4628 * @this: pointer to an uninitialized delegate object
4629 * @target: target object
4630 * @addr: pointer to native code
4632 * This is used to initialize a delegate.
4635 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4637 MonoDomain *domain = mono_domain_get ();
4638 MonoDelegate *delegate = (MonoDelegate *)this;
4639 MonoMethod *method = NULL;
4646 class = this->vtable->klass;
4647 mono_stats.delegate_creations++;
4649 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4650 method = ji->method;
4651 delegate->method = method;
4654 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4656 method = mono_marshal_get_remoting_invoke (method);
4657 delegate->method_ptr = mono_compile_method (method);
4658 MONO_OBJECT_SETREF (delegate, target, target);
4659 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4660 method = mono_marshal_get_unbox_wrapper (method);
4661 delegate->method_ptr = mono_compile_method (method);
4662 MONO_OBJECT_SETREF (delegate, target, target);
4664 delegate->method_ptr = addr;
4665 MONO_OBJECT_SETREF (delegate, target, target);
4668 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4672 * mono_method_call_message_new:
4673 * @method: method to encapsulate
4674 * @params: parameters to the method
4675 * @invoke: optional, delegate invoke.
4676 * @cb: async callback delegate.
4677 * @state: state passed to the async callback.
4679 * Translates arguments pointers into a MonoMethodMessage.
4682 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4683 MonoDelegate **cb, MonoObject **state)
4685 MonoDomain *domain = mono_domain_get ();
4686 MonoMethodSignature *sig = mono_method_signature (method);
4687 MonoMethodMessage *msg;
4690 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4693 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4694 count = sig->param_count - 2;
4696 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4697 count = sig->param_count;
4700 for (i = 0; i < count; i++) {
4705 if (sig->params [i]->byref)
4706 vpos = *((gpointer *)params [i]);
4710 type = sig->params [i]->type;
4711 class = mono_class_from_mono_type (sig->params [i]);
4713 if (class->valuetype)
4714 arg = mono_value_box (domain, class, vpos);
4716 arg = *((MonoObject **)vpos);
4718 mono_array_setref (msg->args, i, arg);
4721 if (cb != NULL && state != NULL) {
4722 *cb = *((MonoDelegate **)params [i]);
4724 *state = *((MonoObject **)params [i]);
4731 * mono_method_return_message_restore:
4733 * Restore results from message based processing back to arguments pointers
4736 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4738 MonoMethodSignature *sig = mono_method_signature (method);
4739 int i, j, type, size, out_len;
4741 if (out_args == NULL)
4743 out_len = mono_array_length (out_args);
4747 for (i = 0, j = 0; i < sig->param_count; i++) {
4748 MonoType *pt = sig->params [i];
4753 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4755 arg = mono_array_get (out_args, gpointer, j);
4759 case MONO_TYPE_VOID:
4760 g_assert_not_reached ();
4764 case MONO_TYPE_BOOLEAN:
4767 case MONO_TYPE_CHAR:
4774 case MONO_TYPE_VALUETYPE: {
4776 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4777 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4780 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4781 memset (*((gpointer *)params [i]), 0, size);
4785 case MONO_TYPE_STRING:
4786 case MONO_TYPE_CLASS:
4787 case MONO_TYPE_ARRAY:
4788 case MONO_TYPE_SZARRAY:
4789 case MONO_TYPE_OBJECT:
4790 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4793 g_assert_not_reached ();
4802 * mono_load_remote_field:
4803 * @this: pointer to an object
4804 * @klass: klass of the object containing @field
4805 * @field: the field to load
4806 * @res: a storage to store the result
4808 * This method is called by the runtime on attempts to load fields of
4809 * transparent proxy objects. @this points to such TP, @klass is the class of
4810 * the object containing @field. @res is a storage location which can be
4811 * used to store the result.
4813 * Returns: an address pointing to the value of field.
4816 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4818 static MonoMethod *getter = NULL;
4819 MonoDomain *domain = mono_domain_get ();
4820 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4821 MonoClass *field_class;
4822 MonoMethodMessage *msg;
4823 MonoArray *out_args;
4827 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4828 g_assert (res != NULL);
4830 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4831 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4836 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4840 field_class = mono_class_from_mono_type (field->type);
4842 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4843 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4844 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4846 full_name = mono_type_get_full_name (klass);
4847 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4848 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4851 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4853 if (exc) mono_raise_exception ((MonoException *)exc);
4855 if (mono_array_length (out_args) == 0)
4858 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4860 if (field_class->valuetype) {
4861 return ((char *)*res) + sizeof (MonoObject);
4867 * mono_load_remote_field_new:
4872 * Missing documentation.
4875 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
4877 static MonoMethod *getter = NULL;
4878 MonoDomain *domain = mono_domain_get ();
4879 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4880 MonoClass *field_class;
4881 MonoMethodMessage *msg;
4882 MonoArray *out_args;
4883 MonoObject *exc, *res;
4886 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4888 field_class = mono_class_from_mono_type (field->type);
4890 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4892 if (field_class->valuetype) {
4893 res = mono_object_new (domain, field_class);
4894 val = ((gchar *) res) + sizeof (MonoObject);
4898 mono_field_get_value (tp->rp->unwrapped_server, field, val);
4903 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4907 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4908 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4910 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4912 full_name = mono_type_get_full_name (klass);
4913 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4914 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4917 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4919 if (exc) mono_raise_exception ((MonoException *)exc);
4921 if (mono_array_length (out_args) == 0)
4924 res = mono_array_get (out_args, MonoObject *, 0);
4930 * mono_store_remote_field:
4931 * @this: pointer to an object
4932 * @klass: klass of the object containing @field
4933 * @field: the field to load
4934 * @val: the value/object to store
4936 * This method is called by the runtime on attempts to store fields of
4937 * transparent proxy objects. @this points to such TP, @klass is the class of
4938 * the object containing @field. @val is the new value to store in @field.
4941 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
4943 static MonoMethod *setter = NULL;
4944 MonoDomain *domain = mono_domain_get ();
4945 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4946 MonoClass *field_class;
4947 MonoMethodMessage *msg;
4948 MonoArray *out_args;
4953 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4955 field_class = mono_class_from_mono_type (field->type);
4957 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4958 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
4959 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
4964 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4968 if (field_class->valuetype)
4969 arg = mono_value_box (domain, field_class, val);
4971 arg = *((MonoObject **)val);
4974 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4975 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4977 full_name = mono_type_get_full_name (klass);
4978 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4979 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4980 mono_array_setref (msg->args, 2, arg);
4983 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4985 if (exc) mono_raise_exception ((MonoException *)exc);
4989 * mono_store_remote_field_new:
4995 * Missing documentation
4998 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5000 static MonoMethod *setter = NULL;
5001 MonoDomain *domain = mono_domain_get ();
5002 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5003 MonoClass *field_class;
5004 MonoMethodMessage *msg;
5005 MonoArray *out_args;
5009 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5011 field_class = mono_class_from_mono_type (field->type);
5013 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5014 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5015 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5020 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5024 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5025 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5027 full_name = mono_type_get_full_name (klass);
5028 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5029 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5030 mono_array_setref (msg->args, 2, arg);
5033 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5035 if (exc) mono_raise_exception ((MonoException *)exc);
5039 * mono_create_ftnptr:
5041 * Given a function address, create a function descriptor for it.
5042 * This is only needed on IA64.
5045 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5050 mono_domain_lock (domain);
5051 desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5052 mono_domain_unlock (domain);
5064 * mono_get_addr_from_ftnptr:
5066 * Given a pointer to a function descriptor, return the function address.
5067 * This is only needed on IA64.
5070 mono_get_addr_from_ftnptr (gpointer descr)
5073 return *(gpointer*)descr;
5081 * mono_string_chars:
5084 * Returns a pointer to the UCS16 characters stored in the MonoString
5087 mono_string_chars(MonoString *s)
5089 /* This method is here only for documentation extraction, this is a macro */
5093 * mono_string_length:
5096 * Returns the lenght in characters of the string
5099 mono_string_length (MonoString *s)
5101 /* This method is here only for documentation extraction, this is a macro */