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/os/gc_wrapper.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 CREATION_SPEEDUP 1
45 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
46 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
47 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
48 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
50 #define GC_NO_DESCRIPTOR (NULL)
51 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
52 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
53 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
61 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
62 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
64 #define NEED_TO_ZERO_PTRFREE 1
65 #define GC_NO_DESCRIPTOR (NULL)
66 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
67 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
68 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
69 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
70 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
81 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
83 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
84 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
85 static CRITICAL_SECTION ldstr_section;
88 mono_runtime_object_init (MonoObject *this)
90 MonoMethod *method = NULL;
91 MonoClass *klass = this->vtable->klass;
93 method = mono_class_get_method_from_name (klass, ".ctor", 0);
96 if (method->klass->valuetype)
97 this = mono_object_unbox (this);
98 mono_runtime_invoke (method, this, NULL, NULL);
101 /* The pseudo algorithm for type initialization from the spec
102 Note it doesn't say anything about domains - only threads.
104 2. If the type is initialized you are done.
105 2.1. If the type is not yet initialized, try to take an
107 2.2. If successful, record this thread as responsible for
108 initializing the type and proceed to step 2.3.
109 2.2.1. If not, see whether this thread or any thread
110 waiting for this thread to complete already holds the lock.
111 2.2.2. If so, return since blocking would create a deadlock. This thread
112 will now see an incompletely initialized state for the type,
113 but no deadlock will arise.
114 2.2.3 If not, block until the type is initialized then return.
115 2.3 Initialize the parent type and then all interfaces implemented
117 2.4 Execute the type initialization code for this type.
118 2.5 Mark the type as initialized, release the initialization lock,
119 awaken any threads waiting for this type to be initialized,
126 guint32 initializing_tid;
127 guint32 waiting_count;
129 CRITICAL_SECTION initialization_section;
130 } TypeInitializationLock;
132 /* for locking access to type_initialization_hash and blocked_thread_hash */
133 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
134 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
135 static CRITICAL_SECTION type_initialization_section;
137 /* from vtable to lock */
138 static GHashTable *type_initialization_hash;
140 /* from thread id to thread id being waited on */
141 static GHashTable *blocked_thread_hash;
144 static MonoThread *main_thread;
147 * mono_thread_set_main:
148 * @thread: thread to set as the main thread
150 * This function can be used to instruct the runtime to treat @thread
151 * as the main thread, ie, the thread that would normally execute the Main()
152 * method. This basically means that at the end of @thread, the runtime will
153 * wait for the existing foreground threads to quit and other such details.
156 mono_thread_set_main (MonoThread *thread)
158 main_thread = thread;
162 mono_thread_get_main (void)
168 mono_type_initialization_init (void)
170 InitializeCriticalSection (&type_initialization_section);
171 type_initialization_hash = g_hash_table_new (NULL, NULL);
172 blocked_thread_hash = g_hash_table_new (NULL, NULL);
173 InitializeCriticalSection (&ldstr_section);
177 mono_type_initialization_cleanup (void)
180 /* This is causing race conditions with
181 * mono_release_type_locks
183 DeleteCriticalSection (&type_initialization_section);
185 DeleteCriticalSection (&ldstr_section);
189 * get_type_init_exception_for_vtable:
191 * Return the stored type initialization exception for VTABLE.
193 static MonoException*
194 get_type_init_exception_for_vtable (MonoVTable *vtable)
196 MonoDomain *domain = vtable->domain;
197 MonoClass *klass = vtable->klass;
201 g_assert (vtable->init_failed);
204 * If the initializing thread was rudely aborted, the exception is not stored
208 mono_domain_lock (domain);
209 if (domain->type_init_exception_hash)
210 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
211 mono_domain_unlock (domain);
214 if (klass->name_space && *klass->name_space)
215 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
217 full_name = g_strdup (klass->name);
218 ex = mono_get_exception_type_initialization (full_name, NULL);
226 * mono_runtime_class_init:
227 * @vtable: vtable that needs to be initialized
229 * This routine calls the class constructor for @vtable.
232 mono_runtime_class_init (MonoVTable *vtable)
235 MonoException *exc_to_throw;
236 MonoMethod *method = NULL;
242 if (vtable->initialized)
246 klass = vtable->klass;
248 if (!klass->image->checked_module_cctor) {
249 mono_image_check_for_module_cctor (klass->image);
250 if (klass->image->has_module_cctor) {
251 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
252 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
255 method = mono_class_get_cctor (klass);
258 MonoDomain *domain = vtable->domain;
259 TypeInitializationLock *lock;
260 guint32 tid = GetCurrentThreadId();
261 int do_initialization = 0;
262 MonoDomain *last_domain = NULL;
264 mono_type_initialization_lock ();
265 /* double check... */
266 if (vtable->initialized) {
267 mono_type_initialization_unlock ();
270 if (vtable->init_failed) {
271 mono_type_initialization_unlock ();
273 /* The type initialization already failed once, rethrow the same exception */
274 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
277 lock = g_hash_table_lookup (type_initialization_hash, vtable);
279 /* This thread will get to do the initialization */
280 if (mono_domain_get () != domain) {
281 /* Transfer into the target domain */
282 last_domain = mono_domain_get ();
283 if (!mono_domain_set (domain, FALSE)) {
284 vtable->initialized = 1;
285 mono_type_initialization_unlock ();
286 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
289 lock = g_malloc (sizeof(TypeInitializationLock));
290 InitializeCriticalSection (&lock->initialization_section);
291 lock->initializing_tid = tid;
292 lock->waiting_count = 1;
294 /* grab the vtable lock while this thread still owns type_initialization_section */
295 EnterCriticalSection (&lock->initialization_section);
296 g_hash_table_insert (type_initialization_hash, vtable, lock);
297 do_initialization = 1;
300 TypeInitializationLock *pending_lock;
302 if (lock->initializing_tid == tid || lock->done) {
303 mono_type_initialization_unlock ();
306 /* see if the thread doing the initialization is already blocked on this thread */
307 blocked = GUINT_TO_POINTER (lock->initializing_tid);
308 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
309 if (pending_lock->initializing_tid == tid) {
310 if (!pending_lock->done) {
311 mono_type_initialization_unlock ();
314 /* the thread doing the initialization is blocked on this thread,
315 but on a lock that has already been freed. It just hasn't got
320 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
322 ++lock->waiting_count;
323 /* record the fact that we are waiting on the initializing thread */
324 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
326 mono_type_initialization_unlock ();
328 if (do_initialization) {
329 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
331 /* If the initialization failed, mark the class as unusable. */
332 /* Avoid infinite loops */
334 (klass->image == mono_defaults.corlib &&
335 !strcmp (klass->name_space, "System") &&
336 !strcmp (klass->name, "TypeInitializationException")))) {
337 vtable->init_failed = 1;
339 if (klass->name_space && *klass->name_space)
340 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
342 full_name = g_strdup (klass->name);
343 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
347 * Store the exception object so it could be thrown on subsequent
350 mono_domain_lock (domain);
351 if (!domain->type_init_exception_hash)
352 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
353 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
354 mono_domain_unlock (domain);
358 mono_domain_set (last_domain, TRUE);
360 LeaveCriticalSection (&lock->initialization_section);
362 /* this just blocks until the initializing thread is done */
363 EnterCriticalSection (&lock->initialization_section);
364 LeaveCriticalSection (&lock->initialization_section);
367 mono_type_initialization_lock ();
368 if (lock->initializing_tid != tid)
369 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
370 --lock->waiting_count;
371 if (lock->waiting_count == 0) {
372 DeleteCriticalSection (&lock->initialization_section);
373 g_hash_table_remove (type_initialization_hash, vtable);
376 if (!vtable->init_failed)
377 vtable->initialized = 1;
378 mono_type_initialization_unlock ();
380 if (vtable->init_failed) {
381 /* Either we were the initializing thread or we waited for the initialization */
382 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
385 vtable->initialized = 1;
391 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
393 MonoVTable *vtable = (MonoVTable*)key;
395 TypeInitializationLock *lock = (TypeInitializationLock*) value;
396 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
399 * Have to set this since it cannot be set by the normal code in
400 * mono_runtime_class_init (). In this case, the exception object is not stored,
401 * and get_type_init_exception_for_class () needs to be aware of this.
403 vtable->init_failed = 1;
404 LeaveCriticalSection (&lock->initialization_section);
405 --lock->waiting_count;
406 if (lock->waiting_count == 0) {
407 DeleteCriticalSection (&lock->initialization_section);
416 mono_release_type_locks (MonoThread *thread)
418 mono_type_initialization_lock ();
419 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
420 mono_type_initialization_unlock ();
424 default_trampoline (MonoMethod *method)
430 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
432 g_error ("remoting not installed");
437 default_delegate_trampoline (MonoClass *klass)
439 g_assert_not_reached ();
443 static MonoTrampoline arch_create_jit_trampoline = default_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_remoting_trampoline (MonoRemotingTrampoline func)
461 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
465 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
467 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
471 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
472 imt_thunk_builder = func;
475 static MonoCompileFunc default_mono_compile_method = NULL;
478 * mono_install_compile_method:
479 * @func: function to install
481 * This is a VM internal routine
484 mono_install_compile_method (MonoCompileFunc func)
486 default_mono_compile_method = func;
490 * mono_compile_method:
491 * @method: The method to compile.
493 * This JIT-compiles the method, and returns the pointer to the native code
497 mono_compile_method (MonoMethod *method)
499 if (!default_mono_compile_method) {
500 g_error ("compile method called on uninitialized runtime");
503 return default_mono_compile_method (method);
506 static MonoFreeMethodFunc default_mono_free_method = NULL;
509 * mono_install_free_method:
510 * @func: pointer to the MonoFreeMethodFunc used to release a method
512 * This is an internal VM routine, it is used for the engines to
513 * register a handler to release the resources associated with a method.
515 * Methods are freed when no more references to the delegate that holds
519 mono_install_free_method (MonoFreeMethodFunc func)
521 default_mono_free_method = func;
525 * mono_runtime_free_method:
526 * @domain; domain where the method is hosted
527 * @method: method to release
529 * This routine is invoked to free the resources associated with
530 * a method that has been JIT compiled. This is used to discard
531 * methods that were used only temporarily (for example, used in marshalling)
535 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
537 if (default_mono_free_method != NULL)
538 default_mono_free_method (domain, method);
540 mono_free_method (method);
543 static MonoInitVTableFunc init_vtable_func = NULL;
546 * mono_install_init_vtable:
547 * @func: pointer to the function to be installed
549 * Register a function which will be called by the runtime to initialize the
550 * method pointers inside a vtable. The JIT can use this function to load the
551 * vtable from the AOT file for example.
554 mono_install_init_vtable (MonoInitVTableFunc func)
556 init_vtable_func = func;
560 * The vtables in the root appdomain are assumed to be reachable by other
561 * roots, and we don't use typed allocation in the other domains.
564 /* The sync block is no longer a GC pointer */
565 #define GC_HEADER_BITMAP (0)
567 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
570 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
572 MonoClassField *field;
578 max_size = mono_class_data_size (class) / sizeof (gpointer);
580 max_size = class->instance_size / sizeof (gpointer);
581 if (max_size >= size) {
582 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
585 for (p = class; p != NULL; p = p->parent) {
586 gpointer iter = NULL;
587 while ((field = mono_class_get_fields (p, &iter))) {
591 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
594 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
597 /* FIXME: should not happen, flag as type load error */
598 if (field->type->byref)
601 pos = field->offset / sizeof (gpointer);
604 type = mono_type_get_underlying_type (field->type);
605 switch (type->type) {
608 case MONO_TYPE_FNPTR:
610 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
615 if (class->image != mono_defaults.corlib)
618 case MONO_TYPE_STRING:
619 case MONO_TYPE_SZARRAY:
620 case MONO_TYPE_CLASS:
621 case MONO_TYPE_OBJECT:
622 case MONO_TYPE_ARRAY:
623 g_assert ((field->offset % sizeof(gpointer)) == 0);
625 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
626 *max_set = MAX (*max_set, pos);
628 case MONO_TYPE_GENERICINST:
629 if (!mono_type_generic_inst_is_valuetype (type)) {
630 g_assert ((field->offset % sizeof(gpointer)) == 0);
632 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
633 *max_set = MAX (*max_set, pos);
638 case MONO_TYPE_VALUETYPE: {
639 MonoClass *fclass = mono_class_from_mono_type (field->type);
640 if (fclass->has_references) {
641 /* remove the object header */
642 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
656 case MONO_TYPE_BOOLEAN:
660 g_assert_not_reached ();
672 * similar to the above, but sets the bits in the bitmap for any non-ref field
673 * and ignores static fields
676 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
678 MonoClassField *field;
683 max_size = class->instance_size / sizeof (gpointer);
684 if (max_size >= size) {
685 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
688 for (p = class; p != NULL; p = p->parent) {
689 gpointer iter = NULL;
690 while ((field = mono_class_get_fields (p, &iter))) {
693 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
695 /* FIXME: should not happen, flag as type load error */
696 if (field->type->byref)
699 pos = field->offset / sizeof (gpointer);
702 type = mono_type_get_underlying_type (field->type);
703 switch (type->type) {
704 #if SIZEOF_VOID_P == 8
708 case MONO_TYPE_FNPTR:
713 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
714 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
715 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
718 #if SIZEOF_VOID_P == 4
722 case MONO_TYPE_FNPTR:
727 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
728 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
729 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
735 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
736 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
737 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
740 case MONO_TYPE_BOOLEAN:
743 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
745 case MONO_TYPE_STRING:
746 case MONO_TYPE_SZARRAY:
747 case MONO_TYPE_CLASS:
748 case MONO_TYPE_OBJECT:
749 case MONO_TYPE_ARRAY:
751 case MONO_TYPE_GENERICINST:
752 if (!mono_type_generic_inst_is_valuetype (type)) {
757 case MONO_TYPE_VALUETYPE: {
758 MonoClass *fclass = mono_class_from_mono_type (field->type);
759 /* remove the object header */
760 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
764 g_assert_not_reached ();
773 * mono_class_insecure_overlapping:
774 * check if a class with explicit layout has references and non-references
775 * fields overlapping.
777 * Returns: TRUE if it is insecure to load the type.
780 mono_class_insecure_overlapping (MonoClass *klass)
784 gsize default_bitmap [4] = {0};
786 gsize default_nrbitmap [4] = {0};
787 int i, insecure = FALSE;
790 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
791 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
793 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
794 int idx = i % (sizeof (bitmap [0]) * 8);
795 if (bitmap [idx] & nrbitmap [idx]) {
800 if (bitmap != default_bitmap)
802 if (nrbitmap != default_nrbitmap)
805 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
813 mono_string_alloc (int length)
815 return mono_string_new_size (mono_domain_get (), length);
819 mono_class_compute_gc_descriptor (MonoClass *class)
823 gsize default_bitmap [4] = {0};
824 static gboolean gcj_inited = FALSE;
829 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
830 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
831 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
832 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
834 #ifdef HAVE_GC_GCJ_MALLOC
836 GC_init_gcj_malloc (5, NULL);
838 #ifdef GC_REDIRECT_TO_LOCAL
839 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
840 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
842 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
843 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
846 mono_loader_unlock ();
850 mono_class_init (class);
852 if (class->gc_descr_inited)
855 class->gc_descr_inited = TRUE;
856 class->gc_descr = GC_NO_DESCRIPTOR;
858 bitmap = default_bitmap;
859 if (class == mono_defaults.string_class) {
860 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
861 } else if (class->rank) {
862 mono_class_compute_gc_descriptor (class->element_class);
864 /* libgc has no usable support for arrays... */
865 if (!class->element_class->valuetype) {
867 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
868 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
869 class->name_space, class->name);*/
871 /* remove the object header */
872 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
873 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
874 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
875 class->name_space, class->name);*/
876 if (bitmap != default_bitmap)
881 /*static int count = 0;
884 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
886 /* It seems there are issues when the bitmap doesn't fit: play it safe */
888 /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
889 if (bitmap != default_bitmap)
894 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
895 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
896 if (bitmap != default_bitmap)
902 * field_is_special_static:
903 * @fklass: The MonoClass to look up.
904 * @field: The MonoClassField describing the field.
906 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
907 * SPECIAL_STATIC_NONE otherwise.
910 field_is_special_static (MonoClass *fklass, MonoClassField *field)
912 MonoCustomAttrInfo *ainfo;
914 ainfo = mono_custom_attrs_from_field (fklass, field);
917 for (i = 0; i < ainfo->num_attrs; ++i) {
918 MonoClass *klass = ainfo->attrs [i].ctor->klass;
919 if (klass->image == mono_defaults.corlib) {
920 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
921 mono_custom_attrs_free (ainfo);
922 return SPECIAL_STATIC_THREAD;
924 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
925 mono_custom_attrs_free (ainfo);
926 return SPECIAL_STATIC_CONTEXT;
930 mono_custom_attrs_free (ainfo);
931 return SPECIAL_STATIC_NONE;
934 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
935 #define mix(a,b,c) { \
936 a -= c; a ^= rot(c, 4); c += b; \
937 b -= a; b ^= rot(a, 6); a += c; \
938 c -= b; c ^= rot(b, 8); b += a; \
939 a -= c; a ^= rot(c,16); c += b; \
940 b -= a; b ^= rot(a,19); a += c; \
941 c -= b; c ^= rot(b, 4); b += a; \
943 #define final(a,b,c) { \
944 c ^= b; c -= rot(b,14); \
945 a ^= c; a -= rot(c,11); \
946 b ^= a; b -= rot(a,25); \
947 c ^= b; c -= rot(b,16); \
948 a ^= c; a -= rot(c,4); \
949 b ^= a; b -= rot(a,14); \
950 c ^= b; c -= rot(b,24); \
954 mono_method_get_imt_slot (MonoMethod *method) {
955 MonoMethodSignature *sig = mono_method_signature (method);
956 int hashes_count = sig->param_count + 4;
957 guint32 *hashes_start = malloc (hashes_count * sizeof (guint32));
958 guint32 *hashes = hashes_start;
962 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
963 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
964 method->klass->name_space, method->klass->name, method->name);
965 g_assert_not_reached ();
968 /* Initialize hashes */
969 hashes [0] = g_str_hash (method->klass->name);
970 hashes [1] = g_str_hash (method->klass->name_space);
971 hashes [2] = g_str_hash (method->name);
972 hashes [3] = mono_metadata_type_hash (sig->ret);
973 for (i = 0; i < sig->param_count; i++) {
974 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
977 /* Setup internal state */
978 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
980 /* Handle most of the hashes */
981 while (hashes_count > 3) {
990 /* Handle the last 3 hashes (all the case statements fall through) */
991 switch (hashes_count) {
992 case 3 : c += hashes [2];
993 case 2 : b += hashes [1];
994 case 1 : a += hashes [0];
996 case 0: /* nothing left to add */
1000 free (hashes_start);
1001 /* Report the result */
1002 return c % MONO_IMT_SIZE;
1011 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1012 guint32 imt_slot = mono_method_get_imt_slot (method);
1013 MonoImtBuilderEntry *entry;
1015 if (slot_num >= 0 && imt_slot != slot_num) {
1016 /* we build just a single imt slot and this is not it */
1020 entry = malloc (sizeof (MonoImtBuilderEntry));
1021 entry->method = method;
1022 entry->vtable_slot = vtable_slot;
1023 entry->next = imt_builder [imt_slot];
1024 if (imt_builder [imt_slot] != NULL) {
1025 entry->children = imt_builder [imt_slot]->children + 1;
1026 if (entry->children == 1) {
1027 mono_stats.imt_slots_with_collisions++;
1028 *imt_collisions_bitmap |= (1 << imt_slot);
1031 entry->children = 0;
1032 mono_stats.imt_used_slots++;
1034 imt_builder [imt_slot] = entry;
1036 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1037 method, method->klass->name_space, method->klass->name,
1038 method->name, imt_slot, vtable_slot, entry->children);
1044 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1046 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1050 e->method->klass->name_space,
1051 e->method->klass->name,
1054 printf (" * %s: NULL\n", message);
1060 compare_imt_builder_entries (const void *p1, const void *p2) {
1061 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1062 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1064 return (e1->method < e2->method) ? -1 : ((e1->method > e2->method) ? 1 : 0);
1068 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1070 int count = end - start;
1071 int chunk_start = out_array->len;
1074 for (i = start; i < end; ++i) {
1075 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1076 item->method = sorted_array [i]->method;
1077 item->vtable_slot = sorted_array [i]->vtable_slot;
1078 item->is_equals = TRUE;
1080 item->check_target_idx = out_array->len + 1;
1082 item->check_target_idx = 0;
1083 g_ptr_array_add (out_array, item);
1086 int middle = start + count / 2;
1087 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1089 item->method = sorted_array [middle]->method;
1090 item->is_equals = FALSE;
1091 g_ptr_array_add (out_array, item);
1092 imt_emit_ir (sorted_array, start, middle, out_array);
1093 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1099 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1100 int number_of_entries = entries->children + 1;
1101 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1102 GPtrArray *result = g_ptr_array_new ();
1103 MonoImtBuilderEntry *current_entry;
1106 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1107 sorted_array [i] = current_entry;
1109 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1111 /*for (i = 0; i < number_of_entries; i++) {
1112 print_imt_entry (" sorted array:", sorted_array [i], i);
1115 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1117 free (sorted_array);
1122 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry) {
1123 if (imt_builder_entry != NULL) {
1124 if (imt_builder_entry->children == 0) {
1125 /* No collision, return the vtable slot contents */
1126 return vtable->vtable [imt_builder_entry->vtable_slot];
1128 /* Collision, build the thunk */
1129 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1132 result = imt_thunk_builder (vtable, domain, (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len);
1133 for (i = 0; i < imt_ir->len; ++i)
1134 g_free (g_ptr_array_index (imt_ir, i));
1135 g_ptr_array_free (imt_ir, TRUE);
1145 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num) {
1148 guint32 imt_collisions_bitmap = 0;
1149 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1150 int method_count = 0;
1151 gboolean record_method_count_for_max_collisions = FALSE;
1154 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1156 for (i = 0; i < klass->interface_offsets_count; ++i) {
1157 MonoClass *iface = klass->interfaces_packed [i];
1158 int interface_offset = klass->interface_offsets_packed [i];
1159 int method_slot_in_interface;
1160 mono_class_setup_methods (iface);
1161 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1162 MonoMethod *method = iface->methods [method_slot_in_interface];
1163 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1166 if (extra_interfaces) {
1167 int interface_offset = klass->vtable_size;
1169 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1170 MonoClass* iface = list_item->data;
1171 int method_slot_in_interface;
1172 mono_class_setup_methods (iface);
1173 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1174 MonoMethod *method = iface->methods [method_slot_in_interface];
1175 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1177 interface_offset += iface->method.count;
1180 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1181 /* overwrite the imt slot only if we're building all the entries or if
1182 * we're uilding this specific one
1184 if (slot_num < 0 || i == slot_num)
1185 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i]);
1187 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1189 if (imt_builder [i] != NULL) {
1190 int methods_in_slot = imt_builder [i]->children + 1;
1191 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1192 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1193 record_method_count_for_max_collisions = TRUE;
1195 method_count += methods_in_slot;
1199 mono_stats.imt_number_of_methods += method_count;
1200 if (record_method_count_for_max_collisions) {
1201 mono_stats.imt_method_count_when_max_collisions = method_count;
1204 for (i = 0; i < MONO_IMT_SIZE; i++) {
1205 MonoImtBuilderEntry* entry = imt_builder [i];
1206 while (entry != NULL) {
1207 MonoImtBuilderEntry* next = entry->next;
1213 /* we OR the bitmap since we may build just a single imt slot at a time */
1214 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1218 mono_class_setup_runtime_generic_context (MonoClass *class, MonoDomain *domain)
1220 MonoVTable *vtable = mono_class_vtable (domain, class);
1221 int depth = class->idepth;
1223 MonoRuntimeGenericSuperInfo *super_infos;
1225 /* We don't allocate arg_infos because we don't use it yet.
1227 super_infos = mono_mempool_alloc0 (domain->mp,
1228 sizeof (MonoRuntimeGenericSuperInfo) * depth + sizeof (MonoRuntimeGenericContext));
1230 vtable->runtime_generic_context = (MonoRuntimeGenericContext*) (super_infos + depth);
1233 for (super = class; super; super = super->parent) {
1234 vtable = mono_class_vtable (domain, super);
1236 super_infos [depth].static_data = vtable->data;
1243 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1244 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1247 static gpointer imt_trampoline = NULL;
1250 mono_install_imt_trampoline (gpointer tramp_code)
1252 imt_trampoline = tramp_code;
1255 static gpointer vtable_trampoline = NULL;
1258 mono_install_vtable_trampoline (gpointer tramp_code)
1260 vtable_trampoline = tramp_code;
1264 * mono_vtable_build_imt_slot:
1265 * @vtable: virtual object table struct
1266 * @imt_slot: slot in the IMT table
1268 * Fill the given @imt_slot in the IMT table of @vtable with
1269 * a trampoline or a thunk for the case of collisions.
1270 * This is part of the internal mono API.
1273 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1275 gpointer *imt = (gpointer*)vtable;
1276 imt -= MONO_IMT_SIZE;
1277 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1279 /* no support for extra interfaces: the proxy objects will need
1280 * to build the complete IMT
1281 * Update and heck needs to ahppen inside the proper domain lock, as all
1282 * the changes made to a MonoVTable.
1284 mono_domain_lock (vtable->domain);
1285 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1286 if (imt [imt_slot] == imt_trampoline)
1287 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1288 mono_domain_unlock (vtable->domain);
1291 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
1294 * mono_class_vtable:
1295 * @domain: the application domain
1296 * @class: the class to initialize
1298 * VTables are domain specific because we create domain specific code, and
1299 * they contain the domain specific static class data.
1302 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1304 MonoClassRuntimeInfo *runtime_info;
1308 /* this check can be inlined in jitted code, too */
1309 runtime_info = class->runtime_info;
1310 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1311 return runtime_info->domain_vtables [domain->domain_id];
1312 return mono_class_create_runtime_vtable (domain, class);
1316 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
1319 MonoClassRuntimeInfo *runtime_info, *old_info;
1320 MonoClassField *field;
1323 int imt_table_bytes = 0;
1324 gboolean inited = FALSE;
1325 guint32 vtable_size, class_size;
1327 guint32 constant_cols [MONO_CONSTANT_SIZE];
1329 gpointer *interface_offsets;
1331 mono_domain_lock (domain);
1332 runtime_info = class->runtime_info;
1333 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1334 mono_domain_unlock (domain);
1335 return runtime_info->domain_vtables [domain->domain_id];
1337 if (!class->inited || class->exception_type) {
1338 if (!mono_class_init (class) || class->exception_type){
1340 mono_domain_unlock (domain);
1341 exc = mono_class_get_exception_for_failure (class);
1343 mono_raise_exception (exc);
1347 mono_class_init (class);
1349 /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
1350 if (class->image->dynamic)
1351 mono_class_setup_vtable (class);
1354 vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1355 if (class->interface_offsets_count) {
1356 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1357 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1358 mono_stats.imt_number_of_tables++;
1359 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1362 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1363 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1366 mono_stats.used_class_count++;
1367 mono_stats.class_vtable_size += vtable_size;
1368 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
1371 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1373 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1375 vt->rank = class->rank;
1376 vt->domain = domain;
1378 mono_class_compute_gc_descriptor (class);
1380 * We can't use typed allocation in the non-root domains, since the
1381 * collector needs the GC descriptor stored in the vtable even after
1382 * the mempool containing the vtable is destroyed when the domain is
1383 * unloaded. An alternative might be to allocate vtables in the GC
1384 * heap, but this does not seem to work (it leads to crashes inside
1385 * libgc). If that approach is tried, two gc descriptors need to be
1386 * allocated for each class: one for the root domain, and one for all
1387 * other domains. The second descriptor should contain a bit for the
1388 * vtable field in MonoObject, since we can no longer assume the
1389 * vtable is reachable by other roots after the appdomain is unloaded.
1391 #ifdef HAVE_BOEHM_GC
1392 if (domain != mono_get_root_domain ())
1393 vt->gc_descr = GC_NO_DESCRIPTOR;
1396 vt->gc_descr = class->gc_descr;
1398 if ((class_size = mono_class_data_size (class))) {
1399 if (class->has_static_refs) {
1400 gpointer statics_gc_descr;
1402 gsize default_bitmap [4] = {0};
1405 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1406 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1407 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1408 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1409 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1410 if (bitmap != default_bitmap)
1413 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1415 mono_stats.class_static_data_size += class_size;
1420 while ((field = mono_class_get_fields (class, &iter))) {
1421 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1423 if (mono_field_is_deleted (field))
1425 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1426 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1427 if (special_static != SPECIAL_STATIC_NONE) {
1428 guint32 size, offset;
1430 size = mono_type_size (field->type, &align);
1431 offset = mono_alloc_special_static_data (special_static, size, align);
1432 if (!domain->special_static_fields)
1433 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1434 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1438 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1439 MonoClass *fklass = mono_class_from_mono_type (field->type);
1440 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1441 t = (char*)vt->data + field->offset;
1442 if (fklass->valuetype) {
1443 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1445 /* it's a pointer type: add check */
1446 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1447 *t = *(char *)field->data;
1451 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1454 /* later do this only on demand if needed */
1456 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1458 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1460 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1461 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1462 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1467 vt->max_interface_id = class->max_interface_id;
1468 vt->interface_bitmap = class->interface_bitmap;
1470 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1471 // class->name, class->interface_offsets_count);
1473 if (! ARCH_USE_IMT) {
1474 /* initialize interface offsets */
1475 for (i = 0; i < class->interface_offsets_count; ++i) {
1476 int interface_id = class->interfaces_packed [i]->interface_id;
1477 int slot = class->interface_offsets_packed [i];
1478 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1483 * arch_create_jit_trampoline () can recursively call this function again
1484 * because it compiles icall methods right away.
1486 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1487 * as we change the code in appdomain.c to invalidate vtables by
1488 * looking at the possible MonoClasses created for the domain.
1490 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1491 /* class->runtime_info is protected by the loader lock, both when
1492 * it it enlarged and when it is stored info.
1494 mono_loader_lock ();
1495 old_info = class->runtime_info;
1496 if (old_info && old_info->max_domain >= domain->domain_id) {
1497 /* someone already created a large enough runtime info */
1498 old_info->domain_vtables [domain->domain_id] = vt;
1500 int new_size = domain->domain_id;
1502 new_size = MAX (new_size, old_info->max_domain);
1504 /* make the new size a power of two */
1506 while (new_size > i)
1509 /* this is a bounded memory retention issue: may want to
1510 * handle it differently when we'll have a rcu-like system.
1512 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1513 runtime_info->max_domain = new_size - 1;
1514 /* copy the stuff from the older info */
1516 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1518 runtime_info->domain_vtables [domain->domain_id] = vt;
1519 /* keep this last (add membarrier) */
1520 class->runtime_info = runtime_info;
1522 mono_loader_unlock ();
1524 /* initialize vtable */
1525 if (init_vtable_func)
1526 inited = init_vtable_func (vt);
1529 mono_class_setup_vtable (class);
1531 for (i = 0; i < class->vtable_size; ++i) {
1534 if ((cm = class->vtable [i])) {
1535 if (mono_method_signature (cm)->generic_param_count)
1536 vt->vtable [i] = cm;
1538 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1543 if (ARCH_USE_IMT && imt_table_bytes) {
1544 /* Now that the vtable is full, we can actually fill up the IMT */
1545 if (imt_trampoline) {
1546 /* lazy construction of the IMT entries enabled */
1547 for (i = 0; i < MONO_IMT_SIZE; ++i)
1548 interface_offsets [i] = imt_trampoline;
1550 build_imt (class, vt, domain, interface_offsets, NULL);
1554 if (class->generic_class)
1555 mono_class_setup_runtime_generic_context (class, domain);
1557 mono_domain_unlock (domain);
1559 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1560 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1561 MonoException *exc = mono_class_get_exception_for_failure (class);
1563 mono_raise_exception (exc);
1566 /* make sure the the parent is initialized */
1568 mono_class_vtable (domain, class->parent);
1570 vt->type = mono_type_get_object (domain, &class->byval_arg);
1571 if (class->contextbound)
1580 * mono_class_proxy_vtable:
1581 * @domain: the application domain
1582 * @remove_class: the remote class
1584 * Creates a vtable for transparent proxies. It is basically
1585 * a copy of the real vtable of the class wrapped in @remote_class,
1586 * but all function pointers invoke the remoting functions, and
1587 * vtable->klass points to the transparent proxy class, and not to @class.
1590 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1592 MonoVTable *vt, *pvt;
1593 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1595 GSList *extra_interfaces = NULL;
1596 MonoClass *class = remote_class->proxy_class;
1597 gpointer *interface_offsets;
1599 vt = mono_class_vtable (domain, class);
1600 max_interface_id = vt->max_interface_id;
1602 /* Calculate vtable space for extra interfaces */
1603 for (j = 0; j < remote_class->interface_count; j++) {
1604 MonoClass* iclass = remote_class->interfaces[j];
1608 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
1609 continue; /* interface implemented by the class */
1610 if (g_slist_find (extra_interfaces, iclass))
1613 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1615 method_count = mono_class_num_methods (iclass);
1617 ifaces = mono_class_get_implemented_interfaces (iclass);
1619 for (i = 0; i < ifaces->len; ++i) {
1620 MonoClass *ic = g_ptr_array_index (ifaces, i);
1621 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
1622 continue; /* interface implemented by the class */
1623 if (g_slist_find (extra_interfaces, ic))
1625 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1626 method_count += mono_class_num_methods (ic);
1628 g_ptr_array_free (ifaces, TRUE);
1631 extra_interface_vtsize += method_count * sizeof (gpointer);
1632 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1636 mono_stats.imt_number_of_tables++;
1637 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1638 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
1639 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1641 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1642 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1645 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1647 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1649 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
1651 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
1652 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1654 pvt->klass = mono_defaults.transparent_proxy_class;
1655 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1656 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1658 /* initialize vtable */
1659 mono_class_setup_vtable (class);
1660 for (i = 0; i < class->vtable_size; ++i) {
1663 if ((cm = class->vtable [i]))
1664 pvt->vtable [i] = mono_method_signature (cm)->generic_param_count
1665 ? cm : arch_create_remoting_trampoline (cm, target_type);
1668 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1669 /* create trampolines for abstract methods */
1670 for (k = class; k; k = k->parent) {
1672 gpointer iter = NULL;
1673 while ((m = mono_class_get_methods (k, &iter)))
1674 if (!pvt->vtable [m->slot])
1675 pvt->vtable [m->slot] = mono_method_signature (m)->generic_param_count ? m : arch_create_remoting_trampoline (m, target_type);
1679 pvt->max_interface_id = max_interface_id;
1680 pvt->interface_bitmap = mono_mempool_alloc0 (domain->mp, sizeof (guint8) * (max_interface_id/8 + 1 ));
1682 if (! ARCH_USE_IMT) {
1683 /* initialize interface offsets */
1684 for (i = 0; i < class->interface_offsets_count; ++i) {
1685 int interface_id = class->interfaces_packed [i]->interface_id;
1686 int slot = class->interface_offsets_packed [i];
1687 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
1690 for (i = 0; i < class->interface_offsets_count; ++i) {
1691 int interface_id = class->interfaces_packed [i]->interface_id;
1692 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
1695 if (extra_interfaces) {
1696 int slot = class->vtable_size;
1702 /* Create trampolines for the methods of the interfaces */
1703 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1704 interf = list_item->data;
1706 if (! ARCH_USE_IMT) {
1707 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1709 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
1713 while ((cm = mono_class_get_methods (interf, &iter)))
1714 pvt->vtable [slot + j++] = mono_method_signature (cm)->generic_param_count ? cm : arch_create_remoting_trampoline (cm, target_type);
1716 slot += mono_class_num_methods (interf);
1718 if (! ARCH_USE_IMT) {
1719 g_slist_free (extra_interfaces);
1724 /* Now that the vtable is full, we can actually fill up the IMT */
1725 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
1726 if (extra_interfaces) {
1727 g_slist_free (extra_interfaces);
1735 * mono_class_has_special_static_fields:
1737 * Returns whenever @klass has any thread/context static fields.
1740 mono_class_has_special_static_fields (MonoClass *klass)
1742 MonoClassField *field;
1746 while ((field = mono_class_get_fields (klass, &iter))) {
1747 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1749 if (mono_field_is_deleted (field))
1751 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1752 if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
1761 * create_remote_class_key:
1762 * Creates an array of pointers that can be used as a hash key for a remote class.
1763 * The first element of the array is the number of pointers.
1766 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1771 if (remote_class == NULL) {
1772 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1773 key = g_malloc (sizeof(gpointer) * 3);
1774 key [0] = GINT_TO_POINTER (2);
1775 key [1] = mono_defaults.marshalbyrefobject_class;
1776 key [2] = extra_class;
1778 key = g_malloc (sizeof(gpointer) * 2);
1779 key [0] = GINT_TO_POINTER (1);
1780 key [1] = extra_class;
1783 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1784 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1785 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1786 key [1] = remote_class->proxy_class;
1788 // Keep the list of interfaces sorted
1789 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1790 if (extra_class && remote_class->interfaces [i] > extra_class) {
1791 key [j++] = extra_class;
1794 key [j] = remote_class->interfaces [i];
1797 key [j] = extra_class;
1799 // Replace the old class. The interface list is the same
1800 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1801 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1802 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1803 for (i = 0; i < remote_class->interface_count; i++)
1804 key [2 + i] = remote_class->interfaces [i];
1812 * copy_remote_class_key:
1814 * Make a copy of KEY in the mempool MP and return the copy.
1817 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1819 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1820 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1822 memcpy (mp_key, key, key_size);
1828 * mono_remote_class:
1829 * @domain: the application domain
1830 * @class_name: name of the remote class
1832 * Creates and initializes a MonoRemoteClass object for a remote type.
1836 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1838 MonoRemoteClass *rc;
1839 gpointer* key, *mp_key;
1841 key = create_remote_class_key (NULL, proxy_class);
1843 mono_domain_lock (domain);
1844 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1848 mono_domain_unlock (domain);
1852 mp_key = copy_remote_class_key (domain->mp, key);
1856 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1857 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1858 rc->interface_count = 1;
1859 rc->interfaces [0] = proxy_class;
1860 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1862 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1863 rc->interface_count = 0;
1864 rc->proxy_class = proxy_class;
1867 rc->default_vtable = NULL;
1868 rc->xdomain_vtable = NULL;
1869 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1871 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1873 mono_domain_unlock (domain);
1878 * clone_remote_class:
1879 * Creates a copy of the remote_class, adding the provided class or interface
1881 static MonoRemoteClass*
1882 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1884 MonoRemoteClass *rc;
1885 gpointer* key, *mp_key;
1887 key = create_remote_class_key (remote_class, extra_class);
1888 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1894 mp_key = copy_remote_class_key (domain->mp, key);
1898 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1900 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1901 rc->proxy_class = remote_class->proxy_class;
1902 rc->interface_count = remote_class->interface_count + 1;
1904 // Keep the list of interfaces sorted, since the hash key of
1905 // the remote class depends on this
1906 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1907 if (remote_class->interfaces [i] > extra_class && i == j)
1908 rc->interfaces [j++] = extra_class;
1909 rc->interfaces [j] = remote_class->interfaces [i];
1912 rc->interfaces [j] = extra_class;
1914 // Replace the old class. The interface array is the same
1915 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1916 rc->proxy_class = extra_class;
1917 rc->interface_count = remote_class->interface_count;
1918 if (rc->interface_count > 0)
1919 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1922 rc->default_vtable = NULL;
1923 rc->xdomain_vtable = NULL;
1924 rc->proxy_class_name = remote_class->proxy_class_name;
1926 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1932 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1934 mono_domain_lock (domain);
1935 if (rp->target_domain_id != -1) {
1936 if (remote_class->xdomain_vtable == NULL)
1937 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1938 mono_domain_unlock (domain);
1939 return remote_class->xdomain_vtable;
1941 if (remote_class->default_vtable == NULL) {
1944 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1945 klass = mono_class_from_mono_type (type);
1946 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1947 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1949 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1952 mono_domain_unlock (domain);
1953 return remote_class->default_vtable;
1957 * mono_upgrade_remote_class:
1958 * @domain: the application domain
1959 * @tproxy: the proxy whose remote class has to be upgraded.
1960 * @klass: class to which the remote class can be casted.
1962 * Updates the vtable of the remote class by adding the necessary method slots
1963 * and interface offsets so it can be safely casted to klass. klass can be a
1964 * class or an interface.
1967 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1969 MonoTransparentProxy *tproxy;
1970 MonoRemoteClass *remote_class;
1971 gboolean redo_vtable;
1973 mono_domain_lock (domain);
1975 tproxy = (MonoTransparentProxy*) proxy_object;
1976 remote_class = tproxy->remote_class;
1978 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1981 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1982 if (remote_class->interfaces [i] == klass)
1983 redo_vtable = FALSE;
1986 redo_vtable = (remote_class->proxy_class != klass);
1990 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1991 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1994 mono_domain_unlock (domain);
1999 * mono_object_get_virtual_method:
2000 * @obj: object to operate on.
2003 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2004 * the instance of a callvirt of method.
2007 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2010 MonoMethod **vtable;
2012 MonoMethod *res = NULL;
2014 klass = mono_object_class (obj);
2015 if (klass == mono_defaults.transparent_proxy_class) {
2016 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2022 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2025 mono_class_setup_vtable (klass);
2026 vtable = klass->vtable;
2028 /* check method->slot is a valid index: perform isinstance? */
2029 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2031 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2033 if (method->slot != -1)
2034 res = vtable [method->slot];
2038 /* It may be an interface, abstract class method or generic method */
2039 if (!res || mono_method_signature (res)->generic_param_count)
2042 /* generic methods demand invoke_with_check */
2043 if (mono_method_signature (res)->generic_param_count)
2044 res = mono_marshal_get_remoting_invoke_with_check (res);
2046 res = mono_marshal_get_remoting_invoke (res);
2055 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2057 g_error ("runtime invoke called on uninitialized runtime");
2061 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2064 * mono_runtime_invoke:
2065 * @method: method to invoke
2066 * @obJ: object instance
2067 * @params: arguments to the method
2068 * @exc: exception information.
2070 * Invokes the method represented by @method on the object @obj.
2072 * obj is the 'this' pointer, it should be NULL for static
2073 * methods, a MonoObject* for object instances and a pointer to
2074 * the value type for value types.
2076 * The params array contains the arguments to the method with the
2077 * same convention: MonoObject* pointers for object instances and
2078 * pointers to the value type otherwise.
2080 * From unmanaged code you'll usually use the
2081 * mono_runtime_invoke() variant.
2083 * Note that this function doesn't handle virtual methods for
2084 * you, it will exec the exact method you pass: we still need to
2085 * expose a function to lookup the derived class implementation
2086 * of a virtual method (there are examples of this in the code,
2089 * You can pass NULL as the exc argument if you don't want to
2090 * catch exceptions, otherwise, *exc will be set to the exception
2091 * thrown, if any. if an exception is thrown, you can't use the
2092 * MonoObject* result from the function.
2094 * If the method returns a value type, it is boxed in an object
2098 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2100 return default_mono_runtime_invoke (method, obj, params, exc);
2104 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2108 gpointer *p = (gpointer*)dest;
2115 case MONO_TYPE_BOOLEAN:
2117 case MONO_TYPE_U1: {
2118 guint8 *p = (guint8*)dest;
2119 *p = value ? *(guint8*)value : 0;
2124 case MONO_TYPE_CHAR: {
2125 guint16 *p = (guint16*)dest;
2126 *p = value ? *(guint16*)value : 0;
2129 #if SIZEOF_VOID_P == 4
2134 case MONO_TYPE_U4: {
2135 gint32 *p = (gint32*)dest;
2136 *p = value ? *(gint32*)value : 0;
2139 #if SIZEOF_VOID_P == 8
2144 case MONO_TYPE_U8: {
2145 gint64 *p = (gint64*)dest;
2146 *p = value ? *(gint64*)value : 0;
2149 case MONO_TYPE_R4: {
2150 float *p = (float*)dest;
2151 *p = value ? *(float*)value : 0;
2154 case MONO_TYPE_R8: {
2155 double *p = (double*)dest;
2156 *p = value ? *(double*)value : 0;
2159 case MONO_TYPE_STRING:
2160 case MONO_TYPE_SZARRAY:
2161 case MONO_TYPE_CLASS:
2162 case MONO_TYPE_OBJECT:
2163 case MONO_TYPE_ARRAY:
2164 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2166 case MONO_TYPE_FNPTR:
2167 case MONO_TYPE_PTR: {
2168 gpointer *p = (gpointer*)dest;
2169 *p = deref_pointer? *(gpointer*)value: value;
2172 case MONO_TYPE_VALUETYPE:
2173 /* note that 't' and 'type->type' can be different */
2174 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2175 t = type->data.klass->enum_basetype->type;
2179 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2181 memset (dest, 0, size);
2183 memcpy (dest, value, size);
2186 case MONO_TYPE_GENERICINST:
2187 t = type->data.generic_class->container_class->byval_arg.type;
2190 g_warning ("got type %x", type->type);
2191 g_assert_not_reached ();
2196 * mono_field_set_value:
2197 * @obj: Instance object
2198 * @field: MonoClassField describing the field to set
2199 * @value: The value to be set
2201 * Sets the value of the field described by @field in the object instance @obj
2202 * to the value passed in @value. This method should only be used for instance
2203 * fields. For static fields, use mono_field_static_set_value.
2205 * The value must be on the native format of the field type.
2208 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2212 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2214 dest = (char*)obj + field->offset;
2215 set_value (field->type, dest, value, FALSE);
2219 * mono_field_static_set_value:
2220 * @field: MonoClassField describing the field to set
2221 * @value: The value to be set
2223 * Sets the value of the static field described by @field
2224 * to the value passed in @value.
2226 * The value must be on the native format of the field type.
2229 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2233 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2234 /* you cant set a constant! */
2235 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2237 dest = (char*)vt->data + field->offset;
2238 set_value (field->type, dest, value, FALSE);
2241 /* Used by the debugger */
2243 mono_vtable_get_static_field_data (MonoVTable *vt)
2249 * mono_field_get_value:
2250 * @obj: Object instance
2251 * @field: MonoClassField describing the field to fetch information from
2252 * @value: pointer to the location where the value will be stored
2254 * Use this routine to get the value of the field @field in the object
2257 * The pointer provided by value must be of the field type, for reference
2258 * types this is a MonoObject*, for value types its the actual pointer to
2263 * mono_field_get_value (obj, int_field, &i);
2266 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2270 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2272 src = (char*)obj + field->offset;
2273 set_value (field->type, value, src, TRUE);
2277 * mono_field_get_value_object:
2278 * @domain: domain where the object will be created (if boxing)
2279 * @field: MonoClassField describing the field to fetch information from
2280 * @obj: The object instance for the field.
2282 * Returns: a new MonoObject with the value from the given field. If the
2283 * field represents a value type, the value is boxed.
2287 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2291 MonoVTable *vtable = NULL;
2293 gboolean is_static = FALSE;
2294 gboolean is_ref = FALSE;
2296 switch (field->type->type) {
2297 case MONO_TYPE_STRING:
2298 case MONO_TYPE_OBJECT:
2299 case MONO_TYPE_CLASS:
2300 case MONO_TYPE_ARRAY:
2301 case MONO_TYPE_SZARRAY:
2306 case MONO_TYPE_BOOLEAN:
2309 case MONO_TYPE_CHAR:
2318 case MONO_TYPE_VALUETYPE:
2319 is_ref = field->type->byref;
2321 case MONO_TYPE_GENERICINST:
2322 is_ref = !field->type->data.generic_class->container_class->valuetype;
2325 g_error ("type 0x%x not handled in "
2326 "mono_field_get_value_object", field->type->type);
2330 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2332 vtable = mono_class_vtable (domain, field->parent);
2333 if (!vtable->initialized)
2334 mono_runtime_class_init (vtable);
2339 mono_field_static_get_value (vtable, field, &o);
2341 mono_field_get_value (obj, field, &o);
2346 /* boxed value type */
2347 klass = mono_class_from_mono_type (field->type);
2348 o = mono_object_new (domain, klass);
2349 v = ((gchar *) o) + sizeof (MonoObject);
2351 mono_field_static_get_value (vtable, field, v);
2353 mono_field_get_value (obj, field, v);
2360 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2363 const char *p = blob;
2364 mono_metadata_decode_blob_size (p, &p);
2367 case MONO_TYPE_BOOLEAN:
2370 *(guint8 *) value = *p;
2372 case MONO_TYPE_CHAR:
2375 *(guint16*) value = read16 (p);
2379 *(guint32*) value = read32 (p);
2383 *(guint64*) value = read64 (p);
2386 readr4 (p, (float*) value);
2389 readr8 (p, (double*) value);
2391 case MONO_TYPE_STRING:
2392 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2394 case MONO_TYPE_CLASS:
2395 *(gpointer*) value = NULL;
2399 g_warning ("type 0x%02x should not be in constant table", type);
2405 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2407 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2408 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2412 * mono_field_static_get_value:
2413 * @vt: vtable to the object
2414 * @field: MonoClassField describing the field to fetch information from
2415 * @value: where the value is returned
2417 * Use this routine to get the value of the static field @field value.
2419 * The pointer provided by value must be of the field type, for reference
2420 * types this is a MonoObject*, for value types its the actual pointer to
2425 * mono_field_static_get_value (vt, int_field, &i);
2428 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2432 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2434 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2435 get_default_field_value (vt->domain, field, value);
2439 src = (char*)vt->data + field->offset;
2440 set_value (field->type, value, src, TRUE);
2444 * mono_property_set_value:
2445 * @prop: MonoProperty to set
2446 * @obj: instance object on which to act
2447 * @params: parameters to pass to the propery
2448 * @exc: optional exception
2450 * Invokes the property's set method with the given arguments on the
2451 * object instance obj (or NULL for static properties).
2453 * You can pass NULL as the exc argument if you don't want to
2454 * catch exceptions, otherwise, *exc will be set to the exception
2455 * thrown, if any. if an exception is thrown, you can't use the
2456 * MonoObject* result from the function.
2459 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2461 default_mono_runtime_invoke (prop->set, obj, params, exc);
2465 * mono_property_get_value:
2466 * @prop: MonoProperty to fetch
2467 * @obj: instance object on which to act
2468 * @params: parameters to pass to the propery
2469 * @exc: optional exception
2471 * Invokes the property's get method with the given arguments on the
2472 * object instance obj (or NULL for static properties).
2474 * You can pass NULL as the exc argument if you don't want to
2475 * catch exceptions, otherwise, *exc will be set to the exception
2476 * thrown, if any. if an exception is thrown, you can't use the
2477 * MonoObject* result from the function.
2479 * Returns: the value from invoking the get method on the property.
2482 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2484 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2488 * mono_nullable_init:
2489 * @buf: The nullable structure to initialize.
2490 * @value: the value to initialize from
2491 * @klass: the type for the object
2493 * Initialize the nullable structure pointed to by @buf from @value which
2494 * should be a boxed value type. The size of @buf should be able to hold
2495 * as much data as the @klass->instance_size (which is the number of bytes
2496 * that will be copies).
2498 * Since Nullables have variable structure, we can not define a C
2499 * structure for them.
2502 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2504 MonoClass *param_class = klass->cast_class;
2506 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2507 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2509 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2511 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2513 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2517 * mono_nullable_box:
2518 * @buf: The buffer representing the data to be boxed
2519 * @klass: the type to box it as.
2521 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2525 mono_nullable_box (guint8 *buf, MonoClass *klass)
2527 MonoClass *param_class = klass->cast_class;
2529 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2530 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2532 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2533 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2534 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2542 * mono_get_delegate_invoke:
2543 * @klass: The delegate class
2545 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2548 mono_get_delegate_invoke (MonoClass *klass)
2552 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2559 * mono_runtime_delegate_invoke:
2560 * @delegate: pointer to a delegate object.
2561 * @params: parameters for the delegate.
2562 * @exc: Pointer to the exception result.
2564 * Invokes the delegate method @delegate with the parameters provided.
2566 * You can pass NULL as the exc argument if you don't want to
2567 * catch exceptions, otherwise, *exc will be set to the exception
2568 * thrown, if any. if an exception is thrown, you can't use the
2569 * MonoObject* result from the function.
2572 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2576 im = mono_get_delegate_invoke (delegate->vtable->klass);
2579 return mono_runtime_invoke (im, delegate, params, exc);
2582 static char **main_args = NULL;
2583 static int num_main_args;
2586 * mono_runtime_get_main_args:
2588 * Returns: a MonoArray with the arguments passed to the main program
2591 mono_runtime_get_main_args (void)
2595 MonoDomain *domain = mono_domain_get ();
2600 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2602 for (i = 0; i < num_main_args; ++i)
2603 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2609 fire_process_exit_event (void)
2611 MonoClassField *field;
2612 MonoDomain *domain = mono_domain_get ();
2614 MonoObject *delegate, *exc;
2616 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2619 if (domain != mono_get_root_domain ())
2622 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2623 if (delegate == NULL)
2628 mono_runtime_delegate_invoke (delegate, pa, &exc);
2632 * mono_runtime_run_main:
2633 * @method: the method to start the application with (usually Main)
2634 * @argc: number of arguments from the command line
2635 * @argv: array of strings from the command line
2636 * @exc: excetption results
2638 * Execute a standard Main() method (argc/argv contains the
2639 * executable name). This method also sets the command line argument value
2640 * needed by System.Environment.
2645 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2649 MonoArray *args = NULL;
2650 MonoDomain *domain = mono_domain_get ();
2651 gchar *utf8_fullpath;
2654 g_assert (method != NULL);
2656 mono_thread_set_main (mono_thread_current ());
2658 main_args = g_new0 (char*, argc);
2659 num_main_args = argc;
2661 if (!g_path_is_absolute (argv [0])) {
2662 gchar *basename = g_path_get_basename (argv [0]);
2663 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2667 utf8_fullpath = mono_utf8_from_external (fullpath);
2668 if(utf8_fullpath == NULL) {
2669 /* Printing the arg text will cause glib to
2670 * whinge about "Invalid UTF-8", but at least
2671 * its relevant, and shows the problem text
2674 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2675 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2682 utf8_fullpath = mono_utf8_from_external (argv[0]);
2683 if(utf8_fullpath == NULL) {
2684 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2685 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2690 main_args [0] = utf8_fullpath;
2692 for (i = 1; i < argc; ++i) {
2695 utf8_arg=mono_utf8_from_external (argv[i]);
2696 if(utf8_arg==NULL) {
2697 /* Ditto the comment about Invalid UTF-8 here */
2698 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2699 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2703 main_args [i] = utf8_arg;
2707 if (mono_method_signature (method)->param_count) {
2708 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2709 for (i = 0; i < argc; ++i) {
2710 /* The encodings should all work, given that
2711 * we've checked all these args for the
2714 gchar *str = mono_utf8_from_external (argv [i]);
2715 MonoString *arg = mono_string_new (domain, str);
2716 mono_array_setref (args, i, arg);
2720 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2723 mono_assembly_set_main (method->klass->image->assembly);
2725 result = mono_runtime_exec_main (method, args, exc);
2726 fire_process_exit_event ();
2730 /* Used in call_unhandled_exception_delegate */
2732 create_unhandled_exception_eventargs (MonoObject *exc)
2736 MonoMethod *method = NULL;
2737 MonoBoolean is_terminating = TRUE;
2740 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2743 mono_class_init (klass);
2745 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2746 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2750 args [1] = &is_terminating;
2752 obj = mono_object_new (mono_domain_get (), klass);
2753 mono_runtime_invoke (method, obj, args, NULL);
2758 /* Used in mono_unhandled_exception */
2760 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2761 MonoObject *e = NULL;
2764 pa [0] = domain->domain;
2765 pa [1] = create_unhandled_exception_eventargs (exc);
2766 mono_runtime_delegate_invoke (delegate, pa, &e);
2769 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2770 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2775 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2778 * mono_runtime_unhandled_exception_policy_set:
2779 * @policy: the new policy
2781 * This is a VM internal routine.
2783 * Sets the runtime policy for handling unhandled exceptions.
2786 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2787 runtime_unhandled_exception_policy = policy;
2791 * mono_runtime_unhandled_exception_policy_get:
2793 * This is a VM internal routine.
2795 * Gets the runtime policy for handling unhandled exceptions.
2797 MonoRuntimeUnhandledExceptionPolicy
2798 mono_runtime_unhandled_exception_policy_get (void) {
2799 return runtime_unhandled_exception_policy;
2803 * mono_unhandled_exception:
2804 * @exc: exception thrown
2806 * This is a VM internal routine.
2808 * We call this function when we detect an unhandled exception
2809 * in the default domain.
2811 * It invokes the * UnhandledException event in AppDomain or prints
2812 * a warning to the console
2815 mono_unhandled_exception (MonoObject *exc)
2817 MonoDomain *current_domain = mono_domain_get ();
2818 MonoDomain *root_domain = mono_get_root_domain ();
2819 MonoClassField *field;
2820 MonoObject *current_appdomain_delegate;
2821 MonoObject *root_appdomain_delegate;
2823 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2824 "UnhandledException");
2827 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2828 gboolean abort_process = (mono_thread_current () == main_thread) ||
2829 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2830 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2831 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2832 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2834 current_appdomain_delegate = NULL;
2837 /* set exitcode only if we will abort the process */
2839 mono_environment_exitcode_set (1);
2840 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2841 mono_print_unhandled_exception (exc);
2843 if (root_appdomain_delegate) {
2844 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2846 if (current_appdomain_delegate) {
2847 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2854 * Launch a new thread to execute a function
2856 * main_func is called back from the thread with main_args as the
2857 * parameter. The callback function is expected to start Main()
2858 * eventually. This function then waits for all managed threads to
2860 * It is not necesseray anymore to execute managed code in a subthread,
2861 * so this function should not be used anymore by default: just
2862 * execute the code and then call mono_thread_manage ().
2865 mono_runtime_exec_managed_code (MonoDomain *domain,
2866 MonoMainThreadFunc main_func,
2869 mono_thread_create (domain, main_func, main_args);
2871 mono_thread_manage ();
2875 * Execute a standard Main() method (args doesn't contain the
2879 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2884 MonoCustomAttrInfo* cinfo;
2885 gboolean has_stathread_attribute;
2886 MonoThread* thread = mono_thread_current ();
2892 domain = mono_object_domain (args);
2893 if (!domain->entry_assembly) {
2895 MonoAssembly *assembly;
2897 assembly = method->klass->image->assembly;
2898 domain->entry_assembly = assembly;
2899 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2901 str = g_strconcat (assembly->image->name, ".config", NULL);
2902 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2906 cinfo = mono_custom_attrs_from_method (method);
2908 static MonoClass *stathread_attribute = NULL;
2909 if (!stathread_attribute)
2910 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
2911 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
2913 mono_custom_attrs_free (cinfo);
2915 has_stathread_attribute = FALSE;
2917 if (has_stathread_attribute) {
2918 thread->apartment_state = ThreadApartmentState_STA;
2919 } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
2920 thread->apartment_state = ThreadApartmentState_Unknown;
2922 thread->apartment_state = ThreadApartmentState_MTA;
2924 mono_thread_init_apartment_state ();
2926 /* FIXME: check signature of method */
2927 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
2929 res = mono_runtime_invoke (method, NULL, pa, exc);
2931 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
2935 mono_environment_exitcode_set (rval);
2937 mono_runtime_invoke (method, NULL, pa, exc);
2941 /* If the return type of Main is void, only
2942 * set the exitcode if an exception was thrown
2943 * (we don't want to blow away an
2944 * explicitly-set exit code)
2947 mono_environment_exitcode_set (rval);
2955 * mono_install_runtime_invoke:
2956 * @func: Function to install
2958 * This is a VM internal routine
2961 mono_install_runtime_invoke (MonoInvokeFunc func)
2963 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2967 * mono_runtime_invoke_array:
2968 * @method: method to invoke
2969 * @obJ: object instance
2970 * @params: arguments to the method
2971 * @exc: exception information.
2973 * Invokes the method represented by @method on the object @obj.
2975 * obj is the 'this' pointer, it should be NULL for static
2976 * methods, a MonoObject* for object instances and a pointer to
2977 * the value type for value types.
2979 * The params array contains the arguments to the method with the
2980 * same convention: MonoObject* pointers for object instances and
2981 * pointers to the value type otherwise. The _invoke_array
2982 * variant takes a C# object[] as the params argument (MonoArray
2983 * *params): in this case the value types are boxed inside the
2984 * respective reference representation.
2986 * From unmanaged code you'll usually use the
2987 * mono_runtime_invoke() variant.
2989 * Note that this function doesn't handle virtual methods for
2990 * you, it will exec the exact method you pass: we still need to
2991 * expose a function to lookup the derived class implementation
2992 * of a virtual method (there are examples of this in the code,
2995 * You can pass NULL as the exc argument if you don't want to
2996 * catch exceptions, otherwise, *exc will be set to the exception
2997 * thrown, if any. if an exception is thrown, you can't use the
2998 * MonoObject* result from the function.
3000 * If the method returns a value type, it is boxed in an object
3004 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3007 MonoMethodSignature *sig = mono_method_signature (method);
3008 gpointer *pa = NULL;
3011 if (NULL != params) {
3012 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3013 for (i = 0; i < mono_array_length (params); i++) {
3014 MonoType *t = sig->params [i];
3020 case MONO_TYPE_BOOLEAN:
3023 case MONO_TYPE_CHAR:
3032 case MONO_TYPE_VALUETYPE:
3033 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3036 g_assert_not_reached ();
3037 /* The runtime invoke wrapper needs the original boxed vtype */
3038 pa [i] = mono_array_get (params, MonoObject*, i);
3040 /* MS seems to create the objects if a null is passed in */
3041 if (!mono_array_get (params, MonoObject*, i))
3042 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3046 * We can't pass the unboxed vtype byref to the callee, since
3047 * that would mean the callee would be able to modify boxed
3048 * primitive types. So we (and MS) make a copy of the boxed
3049 * object, pass that to the callee, and replace the original
3050 * boxed object in the arg array with the copy.
3052 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3053 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3054 mono_array_setref (params, i, copy);
3057 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3060 case MONO_TYPE_STRING:
3061 case MONO_TYPE_OBJECT:
3062 case MONO_TYPE_CLASS:
3063 case MONO_TYPE_ARRAY:
3064 case MONO_TYPE_SZARRAY:
3066 pa [i] = mono_array_addr (params, MonoObject*, i);
3068 pa [i] = mono_array_get (params, MonoObject*, i);
3070 case MONO_TYPE_GENERICINST:
3072 t = &t->data.generic_class->container_class->this_arg;
3074 t = &t->data.generic_class->container_class->byval_arg;
3077 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3082 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3085 if (mono_class_is_nullable (method->klass)) {
3086 /* Need to create a boxed vtype instead */
3092 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3096 obj = mono_object_new (mono_domain_get (), method->klass);
3097 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3098 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3100 if (method->klass->valuetype)
3101 o = mono_object_unbox (obj);
3104 } else if (method->klass->valuetype) {
3105 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3108 mono_runtime_invoke (method, o, pa, exc);
3111 if (mono_class_is_nullable (method->klass)) {
3112 MonoObject *nullable;
3114 /* Convert the unboxed vtype into a Nullable structure */
3115 nullable = mono_object_new (mono_domain_get (), method->klass);
3117 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3118 obj = mono_object_unbox (nullable);
3121 /* obj must be already unboxed if needed */
3122 return mono_runtime_invoke (method, obj, pa, exc);
3127 arith_overflow (void)
3129 mono_raise_exception (mono_get_exception_overflow ());
3133 * mono_object_allocate:
3134 * @size: number of bytes to allocate
3136 * This is a very simplistic routine until we have our GC-aware
3139 * Returns: an allocated object of size @size, or NULL on failure.
3141 static inline void *
3142 mono_object_allocate (size_t size, MonoVTable *vtable)
3145 mono_stats.new_object_count++;
3146 ALLOC_OBJECT (o, vtable, size);
3152 * mono_object_allocate_ptrfree:
3153 * @size: number of bytes to allocate
3155 * Note that the memory allocated is not zeroed.
3156 * Returns: an allocated object of size @size, or NULL on failure.
3158 static inline void *
3159 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3162 mono_stats.new_object_count++;
3163 ALLOC_PTRFREE (o, vtable, size);
3167 static inline void *
3168 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3171 ALLOC_TYPED (o, size, vtable);
3172 mono_stats.new_object_count++;
3179 * @klass: the class of the object that we want to create
3181 * Returns: a newly created object whose definition is
3182 * looked up using @klass. This will not invoke any constructors,
3183 * so the consumer of this routine has to invoke any constructors on
3184 * its own to initialize the object.
3187 mono_object_new (MonoDomain *domain, MonoClass *klass)
3189 MONO_ARCH_SAVE_REGS;
3190 return mono_object_new_specific (mono_class_vtable (domain, klass));
3194 * mono_object_new_specific:
3195 * @vtable: the vtable of the object that we want to create
3197 * Returns: A newly created object with class and domain specified
3201 mono_object_new_specific (MonoVTable *vtable)
3205 MONO_ARCH_SAVE_REGS;
3207 /* check for is_com_object for COM Interop */
3208 if (vtable->remote || vtable->klass->is_com_object)
3211 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3214 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3217 mono_class_init (klass);
3219 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3221 vtable->domain->create_proxy_for_type_method = im;
3224 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3226 o = mono_runtime_invoke (im, NULL, pa, NULL);
3227 if (o != NULL) return o;
3230 return mono_object_new_alloc_specific (vtable);
3234 mono_object_new_alloc_specific (MonoVTable *vtable)
3238 if (!vtable->klass->has_references) {
3239 o = mono_object_new_ptrfree (vtable);
3240 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3241 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3243 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3244 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3246 if (vtable->klass->has_finalize)
3247 mono_object_register_finalizer (o);
3249 mono_profiler_allocation (o, vtable->klass);
3254 mono_object_new_fast (MonoVTable *vtable)
3257 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3262 mono_object_new_ptrfree (MonoVTable *vtable)
3265 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3266 #if NEED_TO_ZERO_PTRFREE
3267 /* an inline memset is much faster for the common vcase of small objects
3268 * note we assume the allocated size is a multiple of sizeof (void*).
3270 if (vtable->klass->instance_size < 128) {
3272 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3273 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3279 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3286 mono_object_new_ptrfree_box (MonoVTable *vtable)
3289 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3290 /* the object will be boxed right away, no need to memzero it */
3295 * mono_class_get_allocation_ftn:
3297 * @for_box: the object will be used for boxing
3298 * @pass_size_in_words:
3300 * Return the allocation function appropriate for the given class.
3304 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3306 *pass_size_in_words = FALSE;
3308 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3309 return mono_object_new_specific;
3311 if (!vtable->klass->has_references) {
3312 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3314 return mono_object_new_ptrfree_box;
3315 return mono_object_new_ptrfree;
3318 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3320 return mono_object_new_fast;
3323 * FIXME: This is actually slower than mono_object_new_fast, because
3324 * of the overhead of parameter passing.
3327 *pass_size_in_words = TRUE;
3328 #ifdef GC_REDIRECT_TO_LOCAL
3329 return GC_local_gcj_fast_malloc;
3331 return GC_gcj_fast_malloc;
3336 return mono_object_new_specific;
3340 * mono_object_new_from_token:
3341 * @image: Context where the type_token is hosted
3342 * @token: a token of the type that we want to create
3344 * Returns: A newly created object whose definition is
3345 * looked up using @token in the @image image
3348 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3352 class = mono_class_get (image, token);
3354 return mono_object_new (domain, class);
3359 * mono_object_clone:
3360 * @obj: the object to clone
3362 * Returns: A newly created object who is a shallow copy of @obj
3365 mono_object_clone (MonoObject *obj)
3370 size = obj->vtable->klass->instance_size;
3371 o = mono_object_allocate (size, obj->vtable);
3372 /* do not copy the sync state */
3373 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3376 if (obj->vtable->klass->has_references)
3377 mono_gc_wbarrier_object (o);
3379 mono_profiler_allocation (o, obj->vtable->klass);
3381 if (obj->vtable->klass->has_finalize)
3382 mono_object_register_finalizer (o);
3387 * mono_array_full_copy:
3388 * @src: source array to copy
3389 * @dest: destination array
3391 * Copies the content of one array to another with exactly the same type and size.
3394 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3397 MonoClass *klass = src->obj.vtable->klass;
3399 MONO_ARCH_SAVE_REGS;
3401 g_assert (klass == dest->obj.vtable->klass);
3403 size = mono_array_length (src);
3404 g_assert (size == mono_array_length (dest));
3405 size *= mono_array_element_size (klass);
3407 if (klass->valuetype) {
3408 if (klass->has_references)
3409 mono_value_copy_array (dest, 0, src, mono_array_length (src));
3411 memcpy (&dest->vector, &src->vector, size);
3413 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3416 memcpy (&dest->vector, &src->vector, size);
3421 * mono_array_clone_in_domain:
3422 * @domain: the domain in which the array will be cloned into
3423 * @array: the array to clone
3425 * This routine returns a copy of the array that is hosted on the
3426 * specified MonoDomain.
3429 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3434 MonoClass *klass = array->obj.vtable->klass;
3436 MONO_ARCH_SAVE_REGS;
3438 if (array->bounds == NULL) {
3439 size = mono_array_length (array);
3440 o = mono_array_new_full (domain, klass, &size, NULL);
3442 size *= mono_array_element_size (klass);
3444 if (klass->valuetype) {
3445 if (klass->has_references)
3446 mono_value_copy_array (o, 0, array, mono_array_length (array));
3448 memcpy (&o->vector, &array->vector, size);
3450 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3453 memcpy (&o->vector, &array->vector, size);
3458 sizes = alloca (klass->rank * sizeof(guint32) * 2);
3459 size = mono_array_element_size (klass);
3460 for (i = 0; i < klass->rank; ++i) {
3461 sizes [i] = array->bounds [i].length;
3462 size *= array->bounds [i].length;
3463 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3465 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3467 if (klass->valuetype) {
3468 if (klass->has_references)
3469 mono_value_copy_array (o, 0, array, mono_array_length (array));
3471 memcpy (&o->vector, &array->vector, size);
3473 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3476 memcpy (&o->vector, &array->vector, size);
3484 * @array: the array to clone
3486 * Returns: A newly created array who is a shallow copy of @array
3489 mono_array_clone (MonoArray *array)
3491 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3494 /* helper macros to check for overflow when calculating the size of arrays */
3495 #define MYGUINT32_MAX 4294967295U
3496 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3497 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
3498 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3499 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
3500 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
3503 * mono_array_new_full:
3504 * @domain: domain where the object is created
3505 * @array_class: array class
3506 * @lengths: lengths for each dimension in the array
3507 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3509 * This routine creates a new array objects with the given dimensions,
3510 * lower bounds and type.
3513 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
3515 guint32 byte_len, len, bounds_size;
3521 if (!array_class->inited)
3522 mono_class_init (array_class);
3524 byte_len = mono_array_element_size (array_class);
3527 /* A single dimensional array with a 0 lower bound is the same as an szarray */
3528 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3534 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3536 for (i = 0; i < array_class->rank; ++i) {
3537 if ((int) lengths [i] < 0)
3539 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3540 mono_gc_out_of_memory (MYGUINT32_MAX);
3545 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3546 mono_gc_out_of_memory (MYGUINT32_MAX);
3548 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3549 mono_gc_out_of_memory (MYGUINT32_MAX);
3550 byte_len += sizeof (MonoArray);
3553 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3554 mono_gc_out_of_memory (MYGUINT32_MAX);
3555 byte_len = (byte_len + 3) & ~3;
3556 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3557 mono_gc_out_of_memory (MYGUINT32_MAX);
3558 byte_len += bounds_size;
3561 * Following three lines almost taken from mono_object_new ():
3562 * they need to be kept in sync.
3564 vtable = mono_class_vtable (domain, array_class);
3565 if (!array_class->has_references) {
3566 o = mono_object_allocate_ptrfree (byte_len, vtable);
3567 #if NEED_TO_ZERO_PTRFREE
3568 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3570 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3571 o = mono_object_allocate_spec (byte_len, vtable);
3573 o = mono_object_allocate (byte_len, vtable);
3576 array = (MonoArray*)o;
3577 array->max_length = len;
3580 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3581 array->bounds = bounds;
3582 for (i = 0; i < array_class->rank; ++i) {
3583 bounds [i].length = lengths [i];
3585 bounds [i].lower_bound = lower_bounds [i];
3589 mono_profiler_allocation (o, array_class);
3596 * @domain: domain where the object is created
3597 * @eclass: element class
3598 * @n: number of array elements
3600 * This routine creates a new szarray with @n elements of type @eclass.
3603 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
3607 MONO_ARCH_SAVE_REGS;
3609 ac = mono_array_class_get (eclass, 1);
3610 g_assert (ac != NULL);
3612 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3616 * mono_array_new_specific:
3617 * @vtable: a vtable in the appropriate domain for an initialized class
3618 * @n: number of array elements
3620 * This routine is a fast alternative to mono_array_new() for code which
3621 * can be sure about the domain it operates in.
3624 mono_array_new_specific (MonoVTable *vtable, guint32 n)
3628 guint32 byte_len, elem_size;
3630 MONO_ARCH_SAVE_REGS;
3635 elem_size = mono_array_element_size (vtable->klass);
3636 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
3637 mono_gc_out_of_memory (MYGUINT32_MAX);
3638 byte_len = n * elem_size;
3639 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3640 mono_gc_out_of_memory (MYGUINT32_MAX);
3641 byte_len += sizeof (MonoArray);
3642 if (!vtable->klass->has_references) {
3643 o = mono_object_allocate_ptrfree (byte_len, vtable);
3644 #if NEED_TO_ZERO_PTRFREE
3645 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3647 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3648 o = mono_object_allocate_spec (byte_len, vtable);
3650 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3651 o = mono_object_allocate (byte_len, vtable);
3654 ao = (MonoArray *)o;
3657 mono_profiler_allocation (o, vtable->klass);
3663 * mono_string_new_utf16:
3664 * @text: a pointer to an utf16 string
3665 * @len: the length of the string
3667 * Returns: A newly created string object which contains @text.
3670 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3674 s = mono_string_new_size (domain, len);
3675 g_assert (s != NULL);
3677 memcpy (mono_string_chars (s), text, len * 2);
3683 * mono_string_new_size:
3684 * @text: a pointer to an utf16 string
3685 * @len: the length of the string
3687 * Returns: A newly created string object of @len
3690 mono_string_new_size (MonoDomain *domain, gint32 len)
3694 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3696 /* overflow ? can't fit it, can't allocate it! */
3698 mono_gc_out_of_memory (-1);
3700 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3702 s = mono_object_allocate_ptrfree (size, vtable);
3705 #if NEED_TO_ZERO_PTRFREE
3708 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3714 * mono_string_new_len:
3715 * @text: a pointer to an utf8 string
3716 * @length: number of bytes in @text to consider
3718 * Returns: A newly created string object which contains @text.
3721 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3723 GError *error = NULL;
3724 MonoString *o = NULL;
3726 glong items_written;
3728 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3731 o = mono_string_new_utf16 (domain, ut, items_written);
3733 g_error_free (error);
3742 * @text: a pointer to an utf8 string
3744 * Returns: A newly created string object which contains @text.
3747 mono_string_new (MonoDomain *domain, const char *text)
3749 GError *error = NULL;
3750 MonoString *o = NULL;
3752 glong items_written;
3757 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3760 o = mono_string_new_utf16 (domain, ut, items_written);
3762 g_error_free (error);
3770 * mono_string_new_wrapper:
3771 * @text: pointer to utf8 characters.
3773 * Helper function to create a string object from @text in the current domain.
3776 mono_string_new_wrapper (const char *text)
3778 MonoDomain *domain = mono_domain_get ();
3780 MONO_ARCH_SAVE_REGS;
3783 return mono_string_new (domain, text);
3790 * @class: the class of the value
3791 * @value: a pointer to the unboxed data
3793 * Returns: A newly created object which contains @value.
3796 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3802 g_assert (class->valuetype);
3804 vtable = mono_class_vtable (domain, class);
3805 size = mono_class_instance_size (class);
3806 res = mono_object_allocate (size, vtable);
3807 mono_profiler_allocation (res, class);
3809 size = size - sizeof (MonoObject);
3812 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3815 #if NO_UNALIGNED_ACCESS
3816 memcpy ((char *)res + sizeof (MonoObject), value, size);
3820 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3823 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3826 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3829 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3832 memcpy ((char *)res + sizeof (MonoObject), value, size);
3835 if (class->has_finalize)
3836 mono_object_register_finalizer (res);
3842 * @dest: destination pointer
3843 * @src: source pointer
3844 * @klass: a valuetype class
3846 * Copy a valuetype from @src to @dest. This function must be used
3847 * when @klass contains references fields.
3850 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3852 int size = mono_class_value_size (klass, NULL);
3853 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3854 memcpy (dest, src, size);
3858 * mono_value_copy_array:
3859 * @dest: destination array
3860 * @dest_idx: index in the @dest array
3861 * @src: source pointer
3862 * @count: number of items
3864 * Copy @count valuetype items from @src to @dest. This function must be used
3865 * when @klass contains references fields.
3866 * Overlap is handled.
3869 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3871 int size = mono_array_element_size (dest->obj.vtable->klass);
3872 char *d = mono_array_addr_with_size (dest, size, dest_idx);
3873 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3874 memmove (d, src, size * count);
3878 * mono_object_get_domain:
3879 * @obj: object to query
3881 * Returns: the MonoDomain where the object is hosted
3884 mono_object_get_domain (MonoObject *obj)
3886 return mono_object_domain (obj);
3890 * mono_object_get_class:
3891 * @obj: object to query
3893 * Returns: the MonOClass of the object.
3896 mono_object_get_class (MonoObject *obj)
3898 return mono_object_class (obj);
3901 * mono_object_get_size:
3902 * @o: object to query
3904 * Returns: the size, in bytes, of @o
3907 mono_object_get_size (MonoObject* o)
3909 MonoClass* klass = mono_object_class (o);
3910 if (klass == mono_defaults.string_class) {
3911 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
3912 } else if (o->vtable->rank) {
3913 MonoArray *array = (MonoArray*)o;
3914 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
3915 if (array->bounds) {
3918 size += sizeof (MonoArrayBounds) * o->vtable->rank;
3922 return mono_class_instance_size (klass);
3927 * mono_object_unbox:
3928 * @obj: object to unbox
3930 * Returns: a pointer to the start of the valuetype boxed in this
3933 * This method will assert if the object passed is not a valuetype.
3936 mono_object_unbox (MonoObject *obj)
3938 /* add assert for valuetypes? */
3939 g_assert (obj->vtable->klass->valuetype);
3940 return ((char*)obj) + sizeof (MonoObject);
3944 * mono_object_isinst:
3946 * @klass: a pointer to a class
3948 * Returns: @obj if @obj is derived from @klass
3951 mono_object_isinst (MonoObject *obj, MonoClass *klass)
3954 mono_class_init (klass);
3956 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3957 return mono_object_isinst_mbyref (obj, klass);
3962 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
3966 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
3975 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3976 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
3980 MonoClass *oklass = vt->klass;
3981 if ((oklass == mono_defaults.transparent_proxy_class))
3982 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
3984 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
3988 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
3990 MonoDomain *domain = mono_domain_get ();
3992 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
3993 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
3994 MonoMethod *im = NULL;
3997 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
3998 im = mono_object_get_virtual_method (rp, im);
4001 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4004 res = mono_runtime_invoke (im, rp, pa, NULL);
4006 if (*(MonoBoolean *) mono_object_unbox(res)) {
4007 /* Update the vtable of the remote type, so it can safely cast to this new type */
4008 mono_upgrade_remote_class (domain, obj, klass);
4017 * mono_object_castclass_mbyref:
4019 * @klass: a pointer to a class
4021 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4024 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4026 if (!obj) return NULL;
4027 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4029 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4031 "InvalidCastException"));
4036 MonoDomain *orig_domain;
4042 str_lookup (MonoDomain *domain, gpointer user_data)
4044 LDStrInfo *info = user_data;
4045 if (info->res || domain == info->orig_domain)
4047 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4053 mono_string_get_pinned (MonoString *str)
4057 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4058 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4059 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4060 news->length = mono_string_length (str);
4065 #define mono_string_get_pinned(str) (str)
4069 mono_string_is_interned_lookup (MonoString *str, int insert)
4071 MonoGHashTable *ldstr_table;
4075 domain = ((MonoObject *)str)->vtable->domain;
4076 ldstr_table = domain->ldstr_table;
4078 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4083 str = mono_string_get_pinned (str);
4084 mono_g_hash_table_insert (ldstr_table, str, str);
4088 LDStrInfo ldstr_info;
4089 ldstr_info.orig_domain = domain;
4090 ldstr_info.ins = str;
4091 ldstr_info.res = NULL;
4093 mono_domain_foreach (str_lookup, &ldstr_info);
4094 if (ldstr_info.res) {
4096 * the string was already interned in some other domain:
4097 * intern it in the current one as well.
4099 mono_g_hash_table_insert (ldstr_table, str, str);
4109 * mono_string_is_interned:
4110 * @o: String to probe
4112 * Returns whether the string has been interned.
4115 mono_string_is_interned (MonoString *o)
4117 return mono_string_is_interned_lookup (o, FALSE);
4121 * mono_string_intern:
4122 * @o: String to intern
4124 * Interns the string passed.
4125 * Returns: The interned string.
4128 mono_string_intern (MonoString *str)
4130 return mono_string_is_interned_lookup (str, TRUE);
4135 * @domain: the domain where the string will be used.
4136 * @image: a metadata context
4137 * @idx: index into the user string table.
4139 * Implementation for the ldstr opcode.
4140 * Returns: a loaded string from the @image/@idx combination.
4143 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4145 MONO_ARCH_SAVE_REGS;
4148 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4150 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4154 * mono_ldstr_metdata_sig
4155 * @domain: the domain for the string
4156 * @sig: the signature of a metadata string
4158 * Returns: a MonoString for a string stored in the metadata
4161 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4163 const char *str = sig;
4164 MonoString *o, *interned;
4167 len2 = mono_metadata_decode_blob_size (str, &str);
4170 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4171 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4174 guint16 *p2 = (guint16*)mono_string_chars (o);
4175 for (i = 0; i < len2; ++i) {
4176 *p2 = GUINT16_FROM_LE (*p2);
4182 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4184 /* o will get garbage collected */
4188 o = mono_string_get_pinned (o);
4189 mono_g_hash_table_insert (domain->ldstr_table, o, o);
4196 * mono_string_to_utf8:
4197 * @s: a System.String
4199 * Return the UTF8 representation for @s.
4200 * the resulting buffer nedds to be freed with g_free().
4203 mono_string_to_utf8 (MonoString *s)
4206 GError *error = NULL;
4212 return g_strdup ("");
4214 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
4216 MonoException *exc = mono_get_exception_argument ("string", error->message);
4217 g_error_free (error);
4218 mono_raise_exception(exc);
4225 * mono_string_to_utf16:
4228 * Return an null-terminated array of the utf-16 chars
4229 * contained in @s. The result must be freed with g_free().
4230 * This is a temporary helper until our string implementation
4231 * is reworked to always include the null terminating char.
4234 mono_string_to_utf16 (MonoString *s)
4241 as = g_malloc ((s->length * 2) + 2);
4242 as [(s->length * 2)] = '\0';
4243 as [(s->length * 2) + 1] = '\0';
4246 return (gunichar2 *)(as);
4249 memcpy (as, mono_string_chars(s), s->length * 2);
4250 return (gunichar2 *)(as);
4254 * mono_string_from_utf16:
4255 * @data: the UTF16 string (LPWSTR) to convert
4257 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4259 * Returns: a MonoString.
4262 mono_string_from_utf16 (gunichar2 *data)
4264 MonoDomain *domain = mono_domain_get ();
4270 while (data [len]) len++;
4272 return mono_string_new_utf16 (domain, data, len);
4276 * mono_string_to_utf8_mp:
4277 * @s: a System.String
4279 * Same as mono_string_to_utf8, but allocate the string from a mempool.
4282 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4284 char *r = mono_string_to_utf8 (s);
4291 len = strlen (r) + 1;
4292 mp_s = mono_mempool_alloc (mp, len);
4293 memcpy (mp_s, r, len);
4301 default_ex_handler (MonoException *ex)
4303 MonoObject *o = (MonoObject*)ex;
4304 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4308 static MonoExceptionFunc ex_handler = default_ex_handler;
4311 * mono_install_handler:
4312 * @func: exception handler
4314 * This is an internal JIT routine used to install the handler for exceptions
4318 mono_install_handler (MonoExceptionFunc func)
4320 ex_handler = func? func: default_ex_handler;
4324 * mono_raise_exception:
4325 * @ex: exception object
4327 * Signal the runtime that the exception @ex has been raised in unmanaged code.
4330 mono_raise_exception (MonoException *ex)
4333 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4334 * that will cause gcc to omit the function epilog, causing problems when
4335 * the JIT tries to walk the stack, since the return address on the stack
4336 * will point into the next function in the executable, not this one.
4339 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4340 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4346 * mono_wait_handle_new:
4347 * @domain: Domain where the object will be created
4348 * @handle: Handle for the wait handle
4350 * Returns: A new MonoWaitHandle created in the given domain for the given handle
4353 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4355 MonoWaitHandle *res;
4356 gpointer params [1];
4357 static MonoMethod *handle_set;
4359 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4361 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
4363 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4365 params [0] = &handle;
4366 mono_runtime_invoke (handle_set, res, params, NULL);
4372 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4374 static MonoClassField *f_os_handle;
4375 static MonoClassField *f_safe_handle;
4377 if (!f_os_handle && !f_safe_handle) {
4378 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4379 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4384 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4388 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4394 * mono_async_result_new:
4395 * @domain:domain where the object will be created.
4396 * @handle: wait handle.
4397 * @state: state to pass to AsyncResult
4398 * @data: C closure data.
4400 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4401 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4405 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4407 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4408 MonoMethod *method = mono_get_context_capture_method ();
4410 /* we must capture the execution context from the original thread */
4412 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4413 /* note: result may be null if the flow is suppressed */
4417 MONO_OBJECT_SETREF (res, object_data, object_data);
4418 MONO_OBJECT_SETREF (res, async_state, state);
4420 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4422 res->sync_completed = FALSE;
4423 res->completed = FALSE;
4429 mono_message_init (MonoDomain *domain,
4430 MonoMethodMessage *this,
4431 MonoReflectionMethod *method,
4432 MonoArray *out_args)
4434 MonoMethodSignature *sig = mono_method_signature (method->method);
4440 MONO_OBJECT_SETREF (this, method, method);
4442 MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
4443 MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
4444 this->async_result = NULL;
4445 this->call_type = CallType_Sync;
4447 names = g_new (char *, sig->param_count);
4448 mono_method_get_param_names (method->method, (const char **) names);
4449 MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
4451 for (i = 0; i < sig->param_count; i++) {
4452 name = mono_string_new (domain, names [i]);
4453 mono_array_setref (this->names, i, name);
4457 for (i = 0, j = 0; i < sig->param_count; i++) {
4459 if (sig->params [i]->byref) {
4461 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4462 mono_array_setref (this->args, i, arg);
4466 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4470 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4473 mono_array_set (this->arg_types, guint8, i, arg_type);
4478 * mono_remoting_invoke:
4479 * @real_proxy: pointer to a RealProxy object
4480 * @msg: The MonoMethodMessage to execute
4481 * @exc: used to store exceptions
4482 * @out_args: used to store output arguments
4484 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4485 * IMessage interface and it is not trivial to extract results from there. So
4486 * we call an helper method PrivateInvoke instead of calling
4487 * RealProxy::Invoke() directly.
4489 * Returns: the result object.
4492 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
4493 MonoObject **exc, MonoArray **out_args)
4495 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4498 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4501 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4503 real_proxy->vtable->domain->private_invoke_method = im;
4506 pa [0] = real_proxy;
4511 return mono_runtime_invoke (im, NULL, pa, exc);
4515 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
4516 MonoObject **exc, MonoArray **out_args)
4520 MonoMethodSignature *sig;
4522 int i, j, outarg_count = 0;
4524 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4526 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4527 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4528 target = tp->rp->unwrapped_server;
4530 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4534 domain = mono_domain_get ();
4535 method = msg->method->method;
4536 sig = mono_method_signature (method);
4538 for (i = 0; i < sig->param_count; i++) {
4539 if (sig->params [i]->byref)
4543 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4544 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
4547 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4549 for (i = 0, j = 0; i < sig->param_count; i++) {
4550 if (sig->params [i]->byref) {
4552 arg = mono_array_get (msg->args, gpointer, i);
4553 mono_array_setref (*out_args, j, arg);
4562 * mono_print_unhandled_exception:
4563 * @exc: The exception
4565 * Prints the unhandled exception.
4568 mono_print_unhandled_exception (MonoObject *exc)
4570 char *message = (char *) "";
4574 gboolean free_message = FALSE;
4576 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4577 klass = exc->vtable->klass;
4579 while (klass && method == NULL) {
4580 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4582 klass = klass->parent;
4587 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4589 message = mono_string_to_utf8 (str);
4590 free_message = TRUE;
4595 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4596 * exc->vtable->klass->name, message);
4598 g_printerr ("\nUnhandled Exception: %s\n", message);
4605 * mono_delegate_ctor:
4606 * @this: pointer to an uninitialized delegate object
4607 * @target: target object
4608 * @addr: pointer to native code
4610 * This is used to initialize a delegate. We also insert the method_info if
4611 * we find the info with mono_jit_info_table_find().
4614 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4616 MonoDomain *domain = mono_domain_get ();
4617 MonoDelegate *delegate = (MonoDelegate *)this;
4618 MonoMethod *method = NULL;
4625 class = this->vtable->klass;
4626 mono_stats.delegate_creations++;
4628 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4629 method = ji->method;
4630 MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, method, NULL));
4633 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4635 method = mono_marshal_get_remoting_invoke (method);
4636 delegate->method_ptr = mono_compile_method (method);
4637 MONO_OBJECT_SETREF (delegate, target, target);
4638 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4639 method = mono_marshal_get_unbox_wrapper (method);
4640 delegate->method_ptr = mono_compile_method (method);
4641 MONO_OBJECT_SETREF (delegate, target, target);
4643 delegate->method_ptr = addr;
4644 MONO_OBJECT_SETREF (delegate, target, target);
4647 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4651 * mono_method_call_message_new:
4652 * @method: method to encapsulate
4653 * @params: parameters to the method
4654 * @invoke: optional, delegate invoke.
4655 * @cb: async callback delegate.
4656 * @state: state passed to the async callback.
4658 * Translates arguments pointers into a MonoMethodMessage.
4661 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4662 MonoDelegate **cb, MonoObject **state)
4664 MonoDomain *domain = mono_domain_get ();
4665 MonoMethodSignature *sig = mono_method_signature (method);
4666 MonoMethodMessage *msg;
4669 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4672 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4673 count = sig->param_count - 2;
4675 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4676 count = sig->param_count;
4679 for (i = 0; i < count; i++) {
4684 if (sig->params [i]->byref)
4685 vpos = *((gpointer *)params [i]);
4689 type = sig->params [i]->type;
4690 class = mono_class_from_mono_type (sig->params [i]);
4692 if (class->valuetype)
4693 arg = mono_value_box (domain, class, vpos);
4695 arg = *((MonoObject **)vpos);
4697 mono_array_setref (msg->args, i, arg);
4700 if (cb != NULL && state != NULL) {
4701 *cb = *((MonoDelegate **)params [i]);
4703 *state = *((MonoObject **)params [i]);
4710 * mono_method_return_message_restore:
4712 * Restore results from message based processing back to arguments pointers
4715 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4717 MonoMethodSignature *sig = mono_method_signature (method);
4718 int i, j, type, size, out_len;
4720 if (out_args == NULL)
4722 out_len = mono_array_length (out_args);
4726 for (i = 0, j = 0; i < sig->param_count; i++) {
4727 MonoType *pt = sig->params [i];
4732 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4734 arg = mono_array_get (out_args, gpointer, j);
4738 case MONO_TYPE_VOID:
4739 g_assert_not_reached ();
4743 case MONO_TYPE_BOOLEAN:
4746 case MONO_TYPE_CHAR:
4753 case MONO_TYPE_VALUETYPE: {
4755 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4756 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4759 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4760 memset (*((gpointer *)params [i]), 0, size);
4764 case MONO_TYPE_STRING:
4765 case MONO_TYPE_CLASS:
4766 case MONO_TYPE_ARRAY:
4767 case MONO_TYPE_SZARRAY:
4768 case MONO_TYPE_OBJECT:
4769 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4772 g_assert_not_reached ();
4781 * mono_load_remote_field:
4782 * @this: pointer to an object
4783 * @klass: klass of the object containing @field
4784 * @field: the field to load
4785 * @res: a storage to store the result
4787 * This method is called by the runtime on attempts to load fields of
4788 * transparent proxy objects. @this points to such TP, @klass is the class of
4789 * the object containing @field. @res is a storage location which can be
4790 * used to store the result.
4792 * Returns: an address pointing to the value of field.
4795 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4797 static MonoMethod *getter = NULL;
4798 MonoDomain *domain = mono_domain_get ();
4799 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4800 MonoClass *field_class;
4801 MonoMethodMessage *msg;
4802 MonoArray *out_args;
4806 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4807 g_assert (res != NULL);
4809 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4810 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4815 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4819 field_class = mono_class_from_mono_type (field->type);
4821 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4822 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4823 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4825 full_name = mono_type_get_full_name (klass);
4826 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4827 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4830 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4832 if (exc) mono_raise_exception ((MonoException *)exc);
4834 if (mono_array_length (out_args) == 0)
4837 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4839 if (field_class->valuetype) {
4840 return ((char *)*res) + sizeof (MonoObject);
4846 * mono_load_remote_field_new:
4851 * Missing documentation.
4854 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
4856 static MonoMethod *getter = NULL;
4857 MonoDomain *domain = mono_domain_get ();
4858 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4859 MonoClass *field_class;
4860 MonoMethodMessage *msg;
4861 MonoArray *out_args;
4862 MonoObject *exc, *res;
4865 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4867 field_class = mono_class_from_mono_type (field->type);
4869 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4871 if (field_class->valuetype) {
4872 res = mono_object_new (domain, field_class);
4873 val = ((gchar *) res) + sizeof (MonoObject);
4877 mono_field_get_value (tp->rp->unwrapped_server, field, val);
4882 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4886 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4887 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4889 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4891 full_name = mono_type_get_full_name (klass);
4892 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4893 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4896 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4898 if (exc) mono_raise_exception ((MonoException *)exc);
4900 if (mono_array_length (out_args) == 0)
4903 res = mono_array_get (out_args, MonoObject *, 0);
4909 * mono_store_remote_field:
4910 * @this: pointer to an object
4911 * @klass: klass of the object containing @field
4912 * @field: the field to load
4913 * @val: the value/object to store
4915 * This method is called by the runtime on attempts to store fields of
4916 * transparent proxy objects. @this points to such TP, @klass is the class of
4917 * the object containing @field. @val is the new value to store in @field.
4920 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
4922 static MonoMethod *setter = NULL;
4923 MonoDomain *domain = mono_domain_get ();
4924 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4925 MonoClass *field_class;
4926 MonoMethodMessage *msg;
4927 MonoArray *out_args;
4932 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4934 field_class = mono_class_from_mono_type (field->type);
4936 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4937 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
4938 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
4943 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4947 if (field_class->valuetype)
4948 arg = mono_value_box (domain, field_class, val);
4950 arg = *((MonoObject **)val);
4953 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4954 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4956 full_name = mono_type_get_full_name (klass);
4957 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4958 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4959 mono_array_setref (msg->args, 2, arg);
4962 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4964 if (exc) mono_raise_exception ((MonoException *)exc);
4968 * mono_store_remote_field_new:
4974 * Missing documentation
4977 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
4979 static MonoMethod *setter = NULL;
4980 MonoDomain *domain = mono_domain_get ();
4981 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4982 MonoClass *field_class;
4983 MonoMethodMessage *msg;
4984 MonoArray *out_args;
4988 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4990 field_class = mono_class_from_mono_type (field->type);
4992 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4993 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
4994 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
4999 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5003 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5004 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5006 full_name = mono_type_get_full_name (klass);
5007 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5008 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5009 mono_array_setref (msg->args, 2, arg);
5012 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5014 if (exc) mono_raise_exception ((MonoException *)exc);
5018 * mono_get_addr_from_ftnptr:
5020 * Given a pointer to a function descriptor, return the function address.
5021 * This is only needed on IA64.
5024 mono_get_addr_from_ftnptr (gpointer descr)
5027 return *(gpointer*)descr;
5035 * mono_string_chars:
5038 * Returns a pointer to the UCS16 characters stored in the MonoString
5041 mono_string_chars(MonoString *s)
5043 /* This method is here only for documentation extraction, this is a macro */
5047 * mono_string_length:
5050 * Returns the lenght in characters of the string
5053 mono_string_length (MonoString *s)
5055 /* This method is here only for documentation extraction, this is a macro */