2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include "cominterop.h"
48 #define NEED_TO_ZERO_PTRFREE 1
49 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
50 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
51 #ifdef HAVE_GC_GCJ_MALLOC
52 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
60 #define GC_NO_DESCRIPTOR (NULL)
61 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
63 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
65 #define NEED_TO_ZERO_PTRFREE 1
66 #define GC_NO_DESCRIPTOR (NULL)
67 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
68 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
69 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
82 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
83 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
84 static CRITICAL_SECTION ldstr_section;
86 static gboolean profile_allocs = TRUE;
89 mono_runtime_object_init (MonoObject *this)
91 MonoMethod *method = NULL;
92 MonoClass *klass = this->vtable->klass;
94 method = mono_class_get_method_from_name (klass, ".ctor", 0);
97 if (method->klass->valuetype)
98 this = mono_object_unbox (this);
99 mono_runtime_invoke (method, this, NULL, NULL);
102 /* The pseudo algorithm for type initialization from the spec
103 Note it doesn't say anything about domains - only threads.
105 2. If the type is initialized you are done.
106 2.1. If the type is not yet initialized, try to take an
108 2.2. If successful, record this thread as responsible for
109 initializing the type and proceed to step 2.3.
110 2.2.1. If not, see whether this thread or any thread
111 waiting for this thread to complete already holds the lock.
112 2.2.2. If so, return since blocking would create a deadlock. This thread
113 will now see an incompletely initialized state for the type,
114 but no deadlock will arise.
115 2.2.3 If not, block until the type is initialized then return.
116 2.3 Initialize the parent type and then all interfaces implemented
118 2.4 Execute the type initialization code for this type.
119 2.5 Mark the type as initialized, release the initialization lock,
120 awaken any threads waiting for this type to be initialized,
127 guint32 initializing_tid;
128 guint32 waiting_count;
130 CRITICAL_SECTION initialization_section;
131 } TypeInitializationLock;
133 /* for locking access to type_initialization_hash and blocked_thread_hash */
134 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
135 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
136 static CRITICAL_SECTION type_initialization_section;
138 /* from vtable to lock */
139 static GHashTable *type_initialization_hash;
141 /* from thread id to thread id being waited on */
142 static GHashTable *blocked_thread_hash;
145 static MonoThread *main_thread;
147 /* Functions supplied by the runtime */
148 static MonoRuntimeCallbacks callbacks;
151 * mono_thread_set_main:
152 * @thread: thread to set as the main thread
154 * This function can be used to instruct the runtime to treat @thread
155 * as the main thread, ie, the thread that would normally execute the Main()
156 * method. This basically means that at the end of @thread, the runtime will
157 * wait for the existing foreground threads to quit and other such details.
160 mono_thread_set_main (MonoThread *thread)
162 main_thread = thread;
166 mono_thread_get_main (void)
172 mono_type_initialization_init (void)
174 InitializeCriticalSection (&type_initialization_section);
175 type_initialization_hash = g_hash_table_new (NULL, NULL);
176 blocked_thread_hash = g_hash_table_new (NULL, NULL);
177 InitializeCriticalSection (&ldstr_section);
181 mono_type_initialization_cleanup (void)
184 /* This is causing race conditions with
185 * mono_release_type_locks
187 DeleteCriticalSection (&type_initialization_section);
189 DeleteCriticalSection (&ldstr_section);
193 * get_type_init_exception_for_vtable:
195 * Return the stored type initialization exception for VTABLE.
197 static MonoException*
198 get_type_init_exception_for_vtable (MonoVTable *vtable)
200 MonoDomain *domain = vtable->domain;
201 MonoClass *klass = vtable->klass;
205 g_assert (vtable->init_failed);
208 * If the initializing thread was rudely aborted, the exception is not stored
212 mono_domain_lock (domain);
213 if (domain->type_init_exception_hash)
214 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
215 mono_domain_unlock (domain);
218 if (klass->name_space && *klass->name_space)
219 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
221 full_name = g_strdup (klass->name);
222 ex = mono_get_exception_type_initialization (full_name, NULL);
229 * mono_runtime_class_init:
230 * @vtable: vtable that needs to be initialized
232 * This routine calls the class constructor for @vtable.
235 mono_runtime_class_init (MonoVTable *vtable)
237 mono_runtime_class_init_full (vtable, TRUE);
241 * mono_runtime_class_init_full:
242 * @vtable that neeeds to be initialized
243 * @raise_exception is TRUE, exceptions are raised intead of returned
247 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
250 MonoException *exc_to_throw;
251 MonoMethod *method = NULL;
257 if (vtable->initialized)
261 klass = vtable->klass;
263 if (!klass->image->checked_module_cctor) {
264 mono_image_check_for_module_cctor (klass->image);
265 if (klass->image->has_module_cctor) {
266 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
267 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
270 mono_runtime_class_init (module_vtable);
273 method = mono_class_get_cctor (klass);
276 MonoDomain *domain = vtable->domain;
277 TypeInitializationLock *lock;
278 guint32 tid = GetCurrentThreadId();
279 int do_initialization = 0;
280 MonoDomain *last_domain = NULL;
282 mono_type_initialization_lock ();
283 /* double check... */
284 if (vtable->initialized) {
285 mono_type_initialization_unlock ();
288 if (vtable->init_aborted) {
290 * The current thread was aborting while running the .cctor the last time,
291 * so let's try again.
293 * The Mono Debugger calls Thread.Abort() on the current thread to abort a
294 * method call (after an expression evaluation timeout, for instance).
296 vtable->init_aborted = 0;
297 vtable->init_failed = 0;
299 if (vtable->init_failed) {
300 mono_type_initialization_unlock ();
302 /* The type initialization already failed once, rethrow the same exception */
304 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
305 return get_type_init_exception_for_vtable (vtable);
307 lock = g_hash_table_lookup (type_initialization_hash, vtable);
309 /* This thread will get to do the initialization */
310 if (mono_domain_get () != domain) {
311 /* Transfer into the target domain */
312 last_domain = mono_domain_get ();
313 if (!mono_domain_set (domain, FALSE)) {
314 vtable->initialized = 1;
315 mono_type_initialization_unlock ();
317 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
318 return mono_get_exception_appdomain_unloaded ();
321 lock = g_malloc (sizeof(TypeInitializationLock));
322 InitializeCriticalSection (&lock->initialization_section);
323 lock->initializing_tid = tid;
324 lock->waiting_count = 1;
326 /* grab the vtable lock while this thread still owns type_initialization_section */
327 EnterCriticalSection (&lock->initialization_section);
328 g_hash_table_insert (type_initialization_hash, vtable, lock);
329 do_initialization = 1;
332 TypeInitializationLock *pending_lock;
334 if (lock->initializing_tid == tid || lock->done) {
335 mono_type_initialization_unlock ();
338 /* see if the thread doing the initialization is already blocked on this thread */
339 blocked = GUINT_TO_POINTER (lock->initializing_tid);
340 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
341 if (pending_lock->initializing_tid == tid) {
342 if (!pending_lock->done) {
343 mono_type_initialization_unlock ();
346 /* the thread doing the initialization is blocked on this thread,
347 but on a lock that has already been freed. It just hasn't got
352 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
354 ++lock->waiting_count;
355 /* record the fact that we are waiting on the initializing thread */
356 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
358 mono_type_initialization_unlock ();
360 if (do_initialization) {
361 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
363 /* If the initialization failed, mark the class as unusable. */
364 /* Avoid infinite loops */
366 (klass->image == mono_defaults.corlib &&
367 !strcmp (klass->name_space, "System") &&
368 !strcmp (klass->name, "TypeInitializationException")))) {
369 vtable->init_failed = 1;
371 if (klass->name_space && *klass->name_space)
372 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
374 full_name = g_strdup (klass->name);
375 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
379 MonoClass *exc_klass = exc->object.vtable->klass;
381 if (exc_klass->image == mono_defaults.corlib &&
382 !strcmp (exc_klass->name_space, "System.Threading") &&
383 !strcmp (exc_klass->name, "ThreadAbortException")) {
385 * Set `init_aborted' in addition to `init_failed' if the
386 * current thread was aborted while running the .cctor.
388 vtable->init_aborted = 1;
393 * Store the exception object so it could be thrown on subsequent
396 mono_domain_lock (domain);
397 if (!domain->type_init_exception_hash)
398 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
399 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
400 mono_domain_unlock (domain);
404 mono_domain_set (last_domain, TRUE);
406 LeaveCriticalSection (&lock->initialization_section);
408 /* this just blocks until the initializing thread is done */
409 EnterCriticalSection (&lock->initialization_section);
410 LeaveCriticalSection (&lock->initialization_section);
413 mono_type_initialization_lock ();
414 if (lock->initializing_tid != tid)
415 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
416 --lock->waiting_count;
417 if (lock->waiting_count == 0) {
418 DeleteCriticalSection (&lock->initialization_section);
419 g_hash_table_remove (type_initialization_hash, vtable);
422 if (!vtable->init_failed)
423 vtable->initialized = 1;
424 mono_type_initialization_unlock ();
426 if (vtable->init_failed) {
427 /* Either we were the initializing thread or we waited for the initialization */
429 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
430 return get_type_init_exception_for_vtable (vtable);
433 vtable->initialized = 1;
440 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
442 MonoVTable *vtable = (MonoVTable*)key;
444 TypeInitializationLock *lock = (TypeInitializationLock*) value;
445 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
448 * Have to set this since it cannot be set by the normal code in
449 * mono_runtime_class_init (). In this case, the exception object is not stored,
450 * and get_type_init_exception_for_class () needs to be aware of this.
452 vtable->init_failed = 1;
453 LeaveCriticalSection (&lock->initialization_section);
454 --lock->waiting_count;
455 if (lock->waiting_count == 0) {
456 DeleteCriticalSection (&lock->initialization_section);
465 mono_release_type_locks (MonoInternalThread *thread)
467 mono_type_initialization_lock ();
468 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
469 mono_type_initialization_unlock ();
473 default_trampoline (MonoMethod *method)
479 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
481 g_assert_not_reached ();
487 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
489 g_error ("remoting not installed");
494 default_delegate_trampoline (MonoClass *klass)
496 g_assert_not_reached ();
500 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
501 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
502 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
503 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
504 static MonoImtThunkBuilder imt_thunk_builder = NULL;
505 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
506 #if (MONO_IMT_SIZE > 32)
507 #error "MONO_IMT_SIZE cannot be larger than 32"
511 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
513 memcpy (&callbacks, cbs, sizeof (*cbs));
516 MonoRuntimeCallbacks*
517 mono_get_runtime_callbacks (void)
523 mono_install_trampoline (MonoTrampoline func)
525 arch_create_jit_trampoline = func? func: default_trampoline;
529 mono_install_jump_trampoline (MonoJumpTrampoline func)
531 arch_create_jump_trampoline = func? func: default_jump_trampoline;
535 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
537 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
541 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
543 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
547 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
548 imt_thunk_builder = func;
551 static MonoCompileFunc default_mono_compile_method = NULL;
554 * mono_install_compile_method:
555 * @func: function to install
557 * This is a VM internal routine
560 mono_install_compile_method (MonoCompileFunc func)
562 default_mono_compile_method = func;
566 * mono_compile_method:
567 * @method: The method to compile.
569 * This JIT-compiles the method, and returns the pointer to the native code
573 mono_compile_method (MonoMethod *method)
575 if (!default_mono_compile_method) {
576 g_error ("compile method called on uninitialized runtime");
579 return default_mono_compile_method (method);
583 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
585 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
589 mono_runtime_create_delegate_trampoline (MonoClass *klass)
591 return arch_create_delegate_trampoline (klass);
594 static MonoFreeMethodFunc default_mono_free_method = NULL;
597 * mono_install_free_method:
598 * @func: pointer to the MonoFreeMethodFunc used to release a method
600 * This is an internal VM routine, it is used for the engines to
601 * register a handler to release the resources associated with a method.
603 * Methods are freed when no more references to the delegate that holds
607 mono_install_free_method (MonoFreeMethodFunc func)
609 default_mono_free_method = func;
613 * mono_runtime_free_method:
614 * @domain; domain where the method is hosted
615 * @method: method to release
617 * This routine is invoked to free the resources associated with
618 * a method that has been JIT compiled. This is used to discard
619 * methods that were used only temporarily (for example, used in marshalling)
623 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
625 if (default_mono_free_method != NULL)
626 default_mono_free_method (domain, method);
628 mono_method_clear_object (domain, method);
630 mono_free_method (method);
634 * The vtables in the root appdomain are assumed to be reachable by other
635 * roots, and we don't use typed allocation in the other domains.
638 /* The sync block is no longer a GC pointer */
639 #define GC_HEADER_BITMAP (0)
641 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
644 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
646 MonoClassField *field;
652 max_size = mono_class_data_size (class) / sizeof (gpointer);
654 max_size = class->instance_size / sizeof (gpointer);
655 if (max_size > size) {
656 g_assert (offset <= 0);
657 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
661 for (p = class; p != NULL; p = p->parent) {
662 gpointer iter = NULL;
663 while ((field = mono_class_get_fields (p, &iter))) {
667 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
669 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
672 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
675 /* FIXME: should not happen, flag as type load error */
676 if (field->type->byref)
679 if (static_fields && field->offset == -1)
683 pos = field->offset / sizeof (gpointer);
686 type = mono_type_get_underlying_type (field->type);
687 switch (type->type) {
690 case MONO_TYPE_FNPTR:
692 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
697 if (class->image != mono_defaults.corlib)
700 case MONO_TYPE_STRING:
701 case MONO_TYPE_SZARRAY:
702 case MONO_TYPE_CLASS:
703 case MONO_TYPE_OBJECT:
704 case MONO_TYPE_ARRAY:
705 g_assert ((field->offset % sizeof(gpointer)) == 0);
707 g_assert (pos < size || pos <= max_size);
708 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
709 *max_set = MAX (*max_set, pos);
711 case MONO_TYPE_GENERICINST:
712 if (!mono_type_generic_inst_is_valuetype (type)) {
713 g_assert ((field->offset % sizeof(gpointer)) == 0);
715 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
716 *max_set = MAX (*max_set, pos);
721 case MONO_TYPE_VALUETYPE: {
722 MonoClass *fclass = mono_class_from_mono_type (field->type);
723 if (fclass->has_references) {
724 /* remove the object header */
725 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
739 case MONO_TYPE_BOOLEAN:
743 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
755 * similar to the above, but sets the bits in the bitmap for any non-ref field
756 * and ignores static fields
759 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
761 MonoClassField *field;
766 max_size = class->instance_size / sizeof (gpointer);
767 if (max_size >= size) {
768 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
771 for (p = class; p != NULL; p = p->parent) {
772 gpointer iter = NULL;
773 while ((field = mono_class_get_fields (p, &iter))) {
776 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
778 /* FIXME: should not happen, flag as type load error */
779 if (field->type->byref)
782 pos = field->offset / sizeof (gpointer);
785 type = mono_type_get_underlying_type (field->type);
786 switch (type->type) {
787 #if SIZEOF_VOID_P == 8
791 case MONO_TYPE_FNPTR:
796 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
797 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
798 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
801 #if SIZEOF_VOID_P == 4
805 case MONO_TYPE_FNPTR:
810 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
811 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
812 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
818 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
819 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
820 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
823 case MONO_TYPE_BOOLEAN:
826 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
828 case MONO_TYPE_STRING:
829 case MONO_TYPE_SZARRAY:
830 case MONO_TYPE_CLASS:
831 case MONO_TYPE_OBJECT:
832 case MONO_TYPE_ARRAY:
834 case MONO_TYPE_GENERICINST:
835 if (!mono_type_generic_inst_is_valuetype (type)) {
840 case MONO_TYPE_VALUETYPE: {
841 MonoClass *fclass = mono_class_from_mono_type (field->type);
842 /* remove the object header */
843 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
847 g_assert_not_reached ();
856 * mono_class_insecure_overlapping:
857 * check if a class with explicit layout has references and non-references
858 * fields overlapping.
860 * Returns: TRUE if it is insecure to load the type.
863 mono_class_insecure_overlapping (MonoClass *klass)
867 gsize default_bitmap [4] = {0};
869 gsize default_nrbitmap [4] = {0};
870 int i, insecure = FALSE;
873 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
874 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
876 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
877 int idx = i % (sizeof (bitmap [0]) * 8);
878 if (bitmap [idx] & nrbitmap [idx]) {
883 if (bitmap != default_bitmap)
885 if (nrbitmap != default_nrbitmap)
888 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
896 mono_string_alloc (int length)
898 return mono_string_new_size (mono_domain_get (), length);
902 mono_class_compute_gc_descriptor (MonoClass *class)
906 gsize default_bitmap [4] = {0};
907 static gboolean gcj_inited = FALSE;
912 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
913 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
914 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
915 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
917 #ifdef HAVE_GC_GCJ_MALLOC
919 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
923 #ifdef GC_REDIRECT_TO_LOCAL
924 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
925 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
927 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
928 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
933 mono_loader_unlock ();
937 mono_class_init (class);
939 if (class->gc_descr_inited)
942 class->gc_descr_inited = TRUE;
943 class->gc_descr = GC_NO_DESCRIPTOR;
945 bitmap = default_bitmap;
946 if (class == mono_defaults.string_class) {
947 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
948 } else if (class->rank) {
949 mono_class_compute_gc_descriptor (class->element_class);
950 if (!class->element_class->valuetype) {
952 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
953 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
954 class->name_space, class->name);*/
956 /* remove the object header */
957 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
958 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
959 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
960 class->name_space, class->name);*/
961 if (bitmap != default_bitmap)
965 /*static int count = 0;
968 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
969 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
971 if (class->gc_descr == GC_NO_DESCRIPTOR)
972 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
974 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
975 if (bitmap != default_bitmap)
981 * field_is_special_static:
982 * @fklass: The MonoClass to look up.
983 * @field: The MonoClassField describing the field.
985 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
986 * SPECIAL_STATIC_NONE otherwise.
989 field_is_special_static (MonoClass *fklass, MonoClassField *field)
991 MonoCustomAttrInfo *ainfo;
993 ainfo = mono_custom_attrs_from_field (fklass, field);
996 for (i = 0; i < ainfo->num_attrs; ++i) {
997 MonoClass *klass = ainfo->attrs [i].ctor->klass;
998 if (klass->image == mono_defaults.corlib) {
999 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1000 mono_custom_attrs_free (ainfo);
1001 return SPECIAL_STATIC_THREAD;
1003 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1004 mono_custom_attrs_free (ainfo);
1005 return SPECIAL_STATIC_CONTEXT;
1009 mono_custom_attrs_free (ainfo);
1010 return SPECIAL_STATIC_NONE;
1013 static gpointer imt_trampoline = NULL;
1016 mono_install_imt_trampoline (gpointer tramp_code)
1018 imt_trampoline = tramp_code;
1021 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1022 #define mix(a,b,c) { \
1023 a -= c; a ^= rot(c, 4); c += b; \
1024 b -= a; b ^= rot(a, 6); a += c; \
1025 c -= b; c ^= rot(b, 8); b += a; \
1026 a -= c; a ^= rot(c,16); c += b; \
1027 b -= a; b ^= rot(a,19); a += c; \
1028 c -= b; c ^= rot(b, 4); b += a; \
1030 #define final(a,b,c) { \
1031 c ^= b; c -= rot(b,14); \
1032 a ^= c; a -= rot(c,11); \
1033 b ^= a; b -= rot(a,25); \
1034 c ^= b; c -= rot(b,16); \
1035 a ^= c; a -= rot(c,4); \
1036 b ^= a; b -= rot(a,14); \
1037 c ^= b; c -= rot(b,24); \
1041 * mono_method_get_imt_slot:
1043 * The IMT slot is embedded into AOTed code, so this must return the same value
1044 * for the same method across all executions. This means:
1045 * - pointers shouldn't be used as hash values.
1046 * - mono_metadata_str_hash () should be used for hashing strings.
1049 mono_method_get_imt_slot (MonoMethod *method)
1051 MonoMethodSignature *sig;
1053 guint32 *hashes_start, *hashes;
1057 /* This can be used to stress tests the collision code */
1061 * We do this to simplify generic sharing. It will hurt
1062 * performance in cases where a class implements two different
1063 * instantiations of the same generic interface.
1064 * The code in build_imt_slots () depends on this.
1066 if (method->is_inflated)
1067 method = ((MonoMethodInflated*)method)->declaring;
1069 sig = mono_method_signature (method);
1070 hashes_count = sig->param_count + 4;
1071 hashes_start = malloc (hashes_count * sizeof (guint32));
1072 hashes = hashes_start;
1074 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1075 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1076 method->klass->name_space, method->klass->name, method->name);
1077 g_assert_not_reached ();
1080 /* Initialize hashes */
1081 hashes [0] = mono_metadata_str_hash (method->klass->name);
1082 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1083 hashes [2] = mono_metadata_str_hash (method->name);
1084 hashes [3] = mono_metadata_type_hash (sig->ret);
1085 for (i = 0; i < sig->param_count; i++) {
1086 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1089 /* Setup internal state */
1090 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1092 /* Handle most of the hashes */
1093 while (hashes_count > 3) {
1102 /* Handle the last 3 hashes (all the case statements fall through) */
1103 switch (hashes_count) {
1104 case 3 : c += hashes [2];
1105 case 2 : b += hashes [1];
1106 case 1 : a += hashes [0];
1108 case 0: /* nothing left to add */
1112 free (hashes_start);
1113 /* Report the result */
1114 return c % MONO_IMT_SIZE;
1123 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1124 guint32 imt_slot = mono_method_get_imt_slot (method);
1125 MonoImtBuilderEntry *entry;
1127 if (slot_num >= 0 && imt_slot != slot_num) {
1128 /* we build just a single imt slot and this is not it */
1132 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1133 entry->key = method;
1134 entry->value.vtable_slot = vtable_slot;
1135 entry->next = imt_builder [imt_slot];
1136 if (imt_builder [imt_slot] != NULL) {
1137 entry->children = imt_builder [imt_slot]->children + 1;
1138 if (entry->children == 1) {
1139 mono_stats.imt_slots_with_collisions++;
1140 *imt_collisions_bitmap |= (1 << imt_slot);
1143 entry->children = 0;
1144 mono_stats.imt_used_slots++;
1146 imt_builder [imt_slot] = entry;
1149 char *method_name = mono_method_full_name (method, TRUE);
1150 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1151 method, method_name, imt_slot, vtable_slot, entry->children);
1152 g_free (method_name);
1159 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1161 MonoMethod *method = e->key;
1162 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1166 method->klass->name_space,
1167 method->klass->name,
1170 printf (" * %s: NULL\n", message);
1176 compare_imt_builder_entries (const void *p1, const void *p2) {
1177 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1178 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1180 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1184 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1186 int count = end - start;
1187 int chunk_start = out_array->len;
1190 for (i = start; i < end; ++i) {
1191 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1192 item->key = sorted_array [i]->key;
1193 item->value = sorted_array [i]->value;
1194 item->has_target_code = sorted_array [i]->has_target_code;
1195 item->is_equals = TRUE;
1197 item->check_target_idx = out_array->len + 1;
1199 item->check_target_idx = 0;
1200 g_ptr_array_add (out_array, item);
1203 int middle = start + count / 2;
1204 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1206 item->key = sorted_array [middle]->key;
1207 item->is_equals = FALSE;
1208 g_ptr_array_add (out_array, item);
1209 imt_emit_ir (sorted_array, start, middle, out_array);
1210 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1216 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1217 int number_of_entries = entries->children + 1;
1218 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1219 GPtrArray *result = g_ptr_array_new ();
1220 MonoImtBuilderEntry *current_entry;
1223 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1224 sorted_array [i] = current_entry;
1226 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1228 /*for (i = 0; i < number_of_entries; i++) {
1229 print_imt_entry (" sorted array:", sorted_array [i], i);
1232 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1234 free (sorted_array);
1239 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1241 if (imt_builder_entry != NULL) {
1242 if (imt_builder_entry->children == 0 && !fail_tramp) {
1243 /* No collision, return the vtable slot contents */
1244 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1246 /* Collision, build the thunk */
1247 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1250 result = imt_thunk_builder (vtable, domain,
1251 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1252 for (i = 0; i < imt_ir->len; ++i)
1253 g_free (g_ptr_array_index (imt_ir, i));
1254 g_ptr_array_free (imt_ir, TRUE);
1266 static MonoImtBuilderEntry*
1267 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1270 * LOCKING: requires the loader and domain locks.
1274 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1278 guint32 imt_collisions_bitmap = 0;
1279 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1280 int method_count = 0;
1281 gboolean record_method_count_for_max_collisions = FALSE;
1282 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1285 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1287 for (i = 0; i < klass->interface_offsets_count; ++i) {
1288 MonoClass *iface = klass->interfaces_packed [i];
1289 int interface_offset = klass->interface_offsets_packed [i];
1290 int method_slot_in_interface, vt_slot;
1292 if (mono_class_has_variant_generic_params (iface))
1293 has_variant_iface = TRUE;
1295 vt_slot = interface_offset;
1296 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1299 if (slot_num >= 0 && iface->is_inflated) {
1301 * The imt slot of the method is the same as for its declaring method,
1302 * see the comment in mono_method_get_imt_slot (), so we can
1303 * avoid inflating methods which will be discarded by
1304 * add_imt_builder_entry anyway.
1306 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1307 if (mono_method_get_imt_slot (method) != slot_num) {
1312 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1313 if (method->is_generic) {
1314 has_generic_virtual = TRUE;
1319 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1320 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1325 if (extra_interfaces) {
1326 int interface_offset = klass->vtable_size;
1328 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1329 MonoClass* iface = list_item->data;
1330 int method_slot_in_interface;
1331 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1332 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1333 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1335 interface_offset += iface->method.count;
1338 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1339 /* overwrite the imt slot only if we're building all the entries or if
1340 * we're building this specific one
1342 if (slot_num < 0 || i == slot_num) {
1343 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1346 if (imt_builder [i]) {
1347 MonoImtBuilderEntry *entry;
1349 /* Link entries with imt_builder [i] */
1350 for (entry = entries; entry->next; entry = entry->next) {
1352 MonoMethod *method = (MonoMethod*)entry->key;
1353 char *method_name = mono_method_full_name (method, TRUE);
1354 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1355 g_free (method_name);
1358 entry->next = imt_builder [i];
1359 entries->children += imt_builder [i]->children + 1;
1361 imt_builder [i] = entries;
1364 if (has_generic_virtual || has_variant_iface) {
1366 * There might be collisions later when the the thunk is expanded.
1368 imt_collisions_bitmap |= (1 << i);
1371 * The IMT thunk might be called with an instance of one of the
1372 * generic virtual methods, so has to fallback to the IMT trampoline.
1374 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1376 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1379 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1383 if (imt_builder [i] != NULL) {
1384 int methods_in_slot = imt_builder [i]->children + 1;
1385 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1386 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1387 record_method_count_for_max_collisions = TRUE;
1389 method_count += methods_in_slot;
1393 mono_stats.imt_number_of_methods += method_count;
1394 if (record_method_count_for_max_collisions) {
1395 mono_stats.imt_method_count_when_max_collisions = method_count;
1398 for (i = 0; i < MONO_IMT_SIZE; i++) {
1399 MonoImtBuilderEntry* entry = imt_builder [i];
1400 while (entry != NULL) {
1401 MonoImtBuilderEntry* next = entry->next;
1407 /* we OR the bitmap since we may build just a single imt slot at a time */
1408 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1412 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1413 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1417 * mono_vtable_build_imt_slot:
1418 * @vtable: virtual object table struct
1419 * @imt_slot: slot in the IMT table
1421 * Fill the given @imt_slot in the IMT table of @vtable with
1422 * a trampoline or a thunk for the case of collisions.
1423 * This is part of the internal mono API.
1425 * LOCKING: Take the domain lock.
1428 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1430 gpointer *imt = (gpointer*)vtable;
1431 imt -= MONO_IMT_SIZE;
1432 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1434 /* no support for extra interfaces: the proxy objects will need
1435 * to build the complete IMT
1436 * Update and heck needs to ahppen inside the proper domain lock, as all
1437 * the changes made to a MonoVTable.
1439 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1440 mono_domain_lock (vtable->domain);
1441 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1442 if (imt [imt_slot] == imt_trampoline)
1443 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1444 mono_domain_unlock (vtable->domain);
1445 mono_loader_unlock ();
1450 * The first two free list entries both belong to the wait list: The
1451 * first entry is the pointer to the head of the list and the second
1452 * entry points to the last element. That way appending and removing
1453 * the first element are both O(1) operations.
1455 #define NUM_FREE_LISTS 12
1456 #define FIRST_FREE_LIST_SIZE 64
1457 #define MAX_WAIT_LENGTH 50
1458 #define THUNK_THRESHOLD 10
1461 * LOCKING: The domain lock must be held.
1464 init_thunk_free_lists (MonoDomain *domain)
1466 if (domain->thunk_free_lists)
1468 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1472 list_index_for_size (int item_size)
1475 int size = FIRST_FREE_LIST_SIZE;
1477 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1486 * mono_method_alloc_generic_virtual_thunk:
1488 * @size: size in bytes
1490 * Allocs size bytes to be used for the code of a generic virtual
1491 * thunk. It's either allocated from the domain's code manager or
1492 * reused from a previously invalidated piece.
1494 * LOCKING: The domain lock must be held.
1497 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1499 static gboolean inited = FALSE;
1500 static int generic_virtual_thunks_size = 0;
1504 MonoThunkFreeList **l;
1506 init_thunk_free_lists (domain);
1508 size += sizeof (guint32);
1509 if (size < sizeof (MonoThunkFreeList))
1510 size = sizeof (MonoThunkFreeList);
1512 i = list_index_for_size (size);
1513 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1514 if ((*l)->size >= size) {
1515 MonoThunkFreeList *item = *l;
1517 return ((guint32*)item) + 1;
1521 /* no suitable item found - search lists of larger sizes */
1522 while (++i < NUM_FREE_LISTS) {
1523 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1526 g_assert (item->size > size);
1527 domain->thunk_free_lists [i] = item->next;
1528 return ((guint32*)item) + 1;
1531 /* still nothing found - allocate it */
1533 mono_counters_register ("Generic virtual thunk bytes",
1534 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1537 generic_virtual_thunks_size += size;
1539 p = mono_domain_code_reserve (domain, size);
1546 * LOCKING: The domain lock must be held.
1549 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1552 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1554 init_thunk_free_lists (domain);
1556 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1557 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1558 int length = item->length;
1561 /* unlink the first item from the wait list */
1562 domain->thunk_free_lists [0] = item->next;
1563 domain->thunk_free_lists [0]->length = length - 1;
1565 i = list_index_for_size (item->size);
1567 /* put it in the free list */
1568 item->next = domain->thunk_free_lists [i];
1569 domain->thunk_free_lists [i] = item;
1573 if (domain->thunk_free_lists [1]) {
1574 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1575 domain->thunk_free_lists [0]->length++;
1577 g_assert (!domain->thunk_free_lists [0]);
1579 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1580 domain->thunk_free_lists [0]->length = 1;
1584 typedef struct _GenericVirtualCase {
1588 struct _GenericVirtualCase *next;
1589 } GenericVirtualCase;
1592 * get_generic_virtual_entries:
1594 * Return IMT entries for the generic virtual method instances and
1595 * variant interface methods for vtable slot
1598 static MonoImtBuilderEntry*
1599 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1601 GenericVirtualCase *list;
1602 MonoImtBuilderEntry *entries;
1604 mono_domain_lock (domain);
1605 if (!domain->generic_virtual_cases)
1606 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1608 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1611 for (; list; list = list->next) {
1612 MonoImtBuilderEntry *entry;
1614 if (list->count < THUNK_THRESHOLD)
1617 entry = g_new0 (MonoImtBuilderEntry, 1);
1618 entry->key = list->method;
1619 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1620 entry->has_target_code = 1;
1622 entry->children = entries->children + 1;
1623 entry->next = entries;
1627 mono_domain_unlock (domain);
1629 /* FIXME: Leaking memory ? */
1634 * mono_method_add_generic_virtual_invocation:
1636 * @vtable_slot: pointer to the vtable slot
1637 * @method: the inflated generic virtual method
1638 * @code: the method's code
1640 * Registers a call via unmanaged code to a generic virtual method
1641 * instantiation or variant interface method. If the number of calls reaches a threshold
1642 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1643 * virtual method thunk.
1646 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1647 gpointer *vtable_slot,
1648 MonoMethod *method, gpointer code)
1650 static gboolean inited = FALSE;
1651 static int num_added = 0;
1653 GenericVirtualCase *gvc, *list;
1654 MonoImtBuilderEntry *entries;
1658 mono_domain_lock (domain);
1659 if (!domain->generic_virtual_cases)
1660 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1662 /* Check whether the case was already added */
1663 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1666 if (gvc->method == method)
1671 /* If not found, make a new one */
1673 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1674 gvc->method = method;
1677 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1679 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1682 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1688 if (++gvc->count == THUNK_THRESHOLD) {
1689 gpointer *old_thunk = *vtable_slot;
1690 gpointer vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable) : NULL;
1692 if ((gpointer)vtable_slot < (gpointer)vtable)
1693 /* Force the rebuild of the thunk at the next call */
1694 *vtable_slot = imt_trampoline;
1696 entries = get_generic_virtual_entries (domain, vtable_slot);
1698 sorted = imt_sort_slot_entries (entries);
1700 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1704 MonoImtBuilderEntry *next = entries->next;
1709 for (i = 0; i < sorted->len; ++i)
1710 g_free (g_ptr_array_index (sorted, i));
1711 g_ptr_array_free (sorted, TRUE);
1714 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1715 invalidate_generic_virtual_thunk (domain, old_thunk);
1718 mono_domain_unlock (domain);
1721 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1724 * mono_class_vtable:
1725 * @domain: the application domain
1726 * @class: the class to initialize
1728 * VTables are domain specific because we create domain specific code, and
1729 * they contain the domain specific static class data.
1730 * On failure, NULL is returned, and class->exception_type is set.
1733 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1735 return mono_class_vtable_full (domain, class, FALSE);
1739 * mono_class_vtable_full:
1740 * @domain: the application domain
1741 * @class: the class to initialize
1742 * @raise_on_error if an exception should be raised on failure or not
1744 * VTables are domain specific because we create domain specific code, and
1745 * they contain the domain specific static class data.
1748 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1750 MonoClassRuntimeInfo *runtime_info;
1754 if (class->exception_type) {
1756 mono_raise_exception (mono_class_get_exception_for_failure (class));
1760 /* this check can be inlined in jitted code, too */
1761 runtime_info = class->runtime_info;
1762 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1763 return runtime_info->domain_vtables [domain->domain_id];
1764 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1768 * mono_class_try_get_vtable:
1769 * @domain: the application domain
1770 * @class: the class to initialize
1772 * This function tries to get the associated vtable from @class if
1773 * it was already created.
1776 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1778 MonoClassRuntimeInfo *runtime_info;
1782 runtime_info = class->runtime_info;
1783 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1784 return runtime_info->domain_vtables [domain->domain_id];
1789 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1792 MonoClassRuntimeInfo *runtime_info, *old_info;
1793 MonoClassField *field;
1796 int imt_table_bytes = 0;
1797 guint32 vtable_size, class_size;
1800 gpointer *interface_offsets;
1802 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1803 mono_domain_lock (domain);
1804 runtime_info = class->runtime_info;
1805 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1806 mono_domain_unlock (domain);
1807 mono_loader_unlock ();
1808 return runtime_info->domain_vtables [domain->domain_id];
1810 if (!class->inited || class->exception_type) {
1811 if (!mono_class_init (class) || class->exception_type) {
1812 mono_domain_unlock (domain);
1813 mono_loader_unlock ();
1815 mono_raise_exception (mono_class_get_exception_for_failure (class));
1820 /* Array types require that their element type be valid*/
1821 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1822 MonoClass *element_class = class->element_class;
1823 if (!element_class->inited)
1824 mono_class_init (element_class);
1826 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1827 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1828 mono_class_setup_vtable (element_class);
1830 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1831 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1832 if (class->exception_type == MONO_EXCEPTION_NONE)
1833 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1834 mono_domain_unlock (domain);
1835 mono_loader_unlock ();
1837 mono_raise_exception (mono_class_get_exception_for_failure (class));
1843 * For some classes, mono_class_init () already computed class->vtable_size, and
1844 * that is all that is needed because of the vtable trampolines.
1846 if (!class->vtable_size)
1847 mono_class_setup_vtable (class);
1849 if (class->exception_type) {
1850 mono_domain_unlock (domain);
1851 mono_loader_unlock ();
1853 mono_raise_exception (mono_class_get_exception_for_failure (class));
1858 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1859 if (class->interface_offsets_count) {
1860 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1861 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1862 mono_stats.imt_number_of_tables++;
1863 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1866 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1867 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1870 mono_stats.used_class_count++;
1871 mono_stats.class_vtable_size += vtable_size;
1872 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1875 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1877 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1879 vt->rank = class->rank;
1880 vt->domain = domain;
1882 mono_class_compute_gc_descriptor (class);
1884 * We can't use typed allocation in the non-root domains, since the
1885 * collector needs the GC descriptor stored in the vtable even after
1886 * the mempool containing the vtable is destroyed when the domain is
1887 * unloaded. An alternative might be to allocate vtables in the GC
1888 * heap, but this does not seem to work (it leads to crashes inside
1889 * libgc). If that approach is tried, two gc descriptors need to be
1890 * allocated for each class: one for the root domain, and one for all
1891 * other domains. The second descriptor should contain a bit for the
1892 * vtable field in MonoObject, since we can no longer assume the
1893 * vtable is reachable by other roots after the appdomain is unloaded.
1895 #ifdef HAVE_BOEHM_GC
1896 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1897 vt->gc_descr = GC_NO_DESCRIPTOR;
1900 vt->gc_descr = class->gc_descr;
1902 if ((class_size = mono_class_data_size (class))) {
1903 if (class->has_static_refs) {
1904 gpointer statics_gc_descr;
1906 gsize default_bitmap [4] = {0};
1909 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1910 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1911 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1912 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1913 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1914 if (bitmap != default_bitmap)
1917 vt->data = mono_domain_alloc0 (domain, class_size);
1919 mono_stats.class_static_data_size += class_size;
1924 while ((field = mono_class_get_fields (class, &iter))) {
1925 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1927 if (mono_field_is_deleted (field))
1929 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1930 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1931 if (special_static != SPECIAL_STATIC_NONE) {
1932 guint32 size, offset;
1934 size = mono_type_size (field->type, &align);
1935 offset = mono_alloc_special_static_data (special_static, size, align);
1936 if (!domain->special_static_fields)
1937 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1938 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1940 * This marks the field as special static to speed up the
1941 * checks in mono_field_static_get/set_value ().
1947 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1948 MonoClass *fklass = mono_class_from_mono_type (field->type);
1949 const char *data = mono_field_get_data (field);
1951 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1952 t = (char*)vt->data + field->offset;
1953 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1956 if (fklass->valuetype) {
1957 memcpy (t, data, mono_class_value_size (fklass, NULL));
1959 /* it's a pointer type: add check */
1960 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1967 vt->max_interface_id = class->max_interface_id;
1968 vt->interface_bitmap = class->interface_bitmap;
1970 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1971 // class->name, class->interface_offsets_count);
1973 if (! ARCH_USE_IMT) {
1974 /* initialize interface offsets */
1975 for (i = 0; i < class->interface_offsets_count; ++i) {
1976 int interface_id = class->interfaces_packed [i]->interface_id;
1977 int slot = class->interface_offsets_packed [i];
1978 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1982 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1983 * as we change the code in appdomain.c to invalidate vtables by
1984 * looking at the possible MonoClasses created for the domain.
1986 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1987 /* class->runtime_info is protected by the loader lock, both when
1988 * it it enlarged and when it is stored info.
1991 old_info = class->runtime_info;
1992 if (old_info && old_info->max_domain >= domain->domain_id) {
1993 /* someone already created a large enough runtime info */
1994 mono_memory_barrier ();
1995 old_info->domain_vtables [domain->domain_id] = vt;
1997 int new_size = domain->domain_id;
1999 new_size = MAX (new_size, old_info->max_domain);
2001 /* make the new size a power of two */
2003 while (new_size > i)
2006 /* this is a bounded memory retention issue: may want to
2007 * handle it differently when we'll have a rcu-like system.
2009 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2010 runtime_info->max_domain = new_size - 1;
2011 /* copy the stuff from the older info */
2013 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2015 runtime_info->domain_vtables [domain->domain_id] = vt;
2017 mono_memory_barrier ();
2018 class->runtime_info = runtime_info;
2021 /* Initialize vtable */
2022 if (callbacks.get_vtable_trampoline) {
2023 // This also covers the AOT case
2024 for (i = 0; i < class->vtable_size; ++i) {
2025 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2028 mono_class_setup_vtable (class);
2030 for (i = 0; i < class->vtable_size; ++i) {
2033 if ((cm = class->vtable [i]))
2034 vt->vtable [i] = arch_create_jit_trampoline (cm);
2038 if (ARCH_USE_IMT && imt_table_bytes) {
2039 /* Now that the vtable is full, we can actually fill up the IMT */
2040 if (imt_trampoline) {
2041 /* lazy construction of the IMT entries enabled */
2042 for (i = 0; i < MONO_IMT_SIZE; ++i)
2043 interface_offsets [i] = imt_trampoline;
2045 build_imt (class, vt, domain, interface_offsets, NULL);
2049 mono_domain_unlock (domain);
2050 mono_loader_unlock ();
2052 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2053 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2054 mono_raise_exception (mono_class_get_exception_for_failure (class));
2056 /* make sure the parent is initialized */
2057 /*FIXME shouldn't this fail the current type?*/
2059 mono_class_vtable_full (domain, class->parent, raise_on_error);
2061 /*FIXME check for OOM*/
2062 vt->type = mono_type_get_object (domain, &class->byval_arg);
2064 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class) {
2065 static void *type_desc = NULL;
2069 type_desc = mono_gc_make_descr_from_bitmap (&bmap, 1);
2072 /* This is unregistered in
2073 unregister_vtable_reflection_type() in
2075 mono_gc_register_root ((char*)&vt->type, sizeof (gpointer), type_desc);
2078 if (class->contextbound)
2087 * mono_class_proxy_vtable:
2088 * @domain: the application domain
2089 * @remove_class: the remote class
2091 * Creates a vtable for transparent proxies. It is basically
2092 * a copy of the real vtable of the class wrapped in @remote_class,
2093 * but all function pointers invoke the remoting functions, and
2094 * vtable->klass points to the transparent proxy class, and not to @class.
2097 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2100 MonoVTable *vt, *pvt;
2101 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2103 GSList *extra_interfaces = NULL;
2104 MonoClass *class = remote_class->proxy_class;
2105 gpointer *interface_offsets;
2107 vt = mono_class_vtable (domain, class);
2108 g_assert (vt); /*FIXME property handle failure*/
2109 max_interface_id = vt->max_interface_id;
2111 /* Calculate vtable space for extra interfaces */
2112 for (j = 0; j < remote_class->interface_count; j++) {
2113 MonoClass* iclass = remote_class->interfaces[j];
2117 /*FIXME test for interfaces with variant generic arguments*/
2118 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2119 continue; /* interface implemented by the class */
2120 if (g_slist_find (extra_interfaces, iclass))
2123 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2125 method_count = mono_class_num_methods (iclass);
2127 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2128 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2130 for (i = 0; i < ifaces->len; ++i) {
2131 MonoClass *ic = g_ptr_array_index (ifaces, i);
2132 /*FIXME test for interfaces with variant generic arguments*/
2133 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2134 continue; /* interface implemented by the class */
2135 if (g_slist_find (extra_interfaces, ic))
2137 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2138 method_count += mono_class_num_methods (ic);
2140 g_ptr_array_free (ifaces, TRUE);
2143 extra_interface_vtsize += method_count * sizeof (gpointer);
2144 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2148 mono_stats.imt_number_of_tables++;
2149 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2150 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2151 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2153 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2154 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2157 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2159 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2161 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2163 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2164 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2166 pvt->klass = mono_defaults.transparent_proxy_class;
2167 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2168 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2170 /* initialize vtable */
2171 mono_class_setup_vtable (class);
2172 for (i = 0; i < class->vtable_size; ++i) {
2175 if ((cm = class->vtable [i]))
2176 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2178 pvt->vtable [i] = NULL;
2181 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2182 /* create trampolines for abstract methods */
2183 for (k = class; k; k = k->parent) {
2185 gpointer iter = NULL;
2186 while ((m = mono_class_get_methods (k, &iter)))
2187 if (!pvt->vtable [m->slot])
2188 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2192 pvt->max_interface_id = max_interface_id;
2193 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2195 if (! ARCH_USE_IMT) {
2196 /* initialize interface offsets */
2197 for (i = 0; i < class->interface_offsets_count; ++i) {
2198 int interface_id = class->interfaces_packed [i]->interface_id;
2199 int slot = class->interface_offsets_packed [i];
2200 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2203 for (i = 0; i < class->interface_offsets_count; ++i) {
2204 int interface_id = class->interfaces_packed [i]->interface_id;
2205 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2208 if (extra_interfaces) {
2209 int slot = class->vtable_size;
2215 /* Create trampolines for the methods of the interfaces */
2216 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2217 interf = list_item->data;
2219 if (! ARCH_USE_IMT) {
2220 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2222 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2226 while ((cm = mono_class_get_methods (interf, &iter)))
2227 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2229 slot += mono_class_num_methods (interf);
2231 if (! ARCH_USE_IMT) {
2232 g_slist_free (extra_interfaces);
2237 /* Now that the vtable is full, we can actually fill up the IMT */
2238 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2239 if (extra_interfaces) {
2240 g_slist_free (extra_interfaces);
2248 * mono_class_field_is_special_static:
2250 * Returns whether @field is a thread/context static field.
2253 mono_class_field_is_special_static (MonoClassField *field)
2255 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2257 if (mono_field_is_deleted (field))
2259 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2260 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2267 * mono_class_has_special_static_fields:
2269 * Returns whenever @klass has any thread/context static fields.
2272 mono_class_has_special_static_fields (MonoClass *klass)
2274 MonoClassField *field;
2278 while ((field = mono_class_get_fields (klass, &iter))) {
2279 g_assert (field->parent == klass);
2280 if (mono_class_field_is_special_static (field))
2288 * create_remote_class_key:
2289 * Creates an array of pointers that can be used as a hash key for a remote class.
2290 * The first element of the array is the number of pointers.
2293 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2298 if (remote_class == NULL) {
2299 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2300 key = g_malloc (sizeof(gpointer) * 3);
2301 key [0] = GINT_TO_POINTER (2);
2302 key [1] = mono_defaults.marshalbyrefobject_class;
2303 key [2] = extra_class;
2305 key = g_malloc (sizeof(gpointer) * 2);
2306 key [0] = GINT_TO_POINTER (1);
2307 key [1] = extra_class;
2310 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2311 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2312 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2313 key [1] = remote_class->proxy_class;
2315 // Keep the list of interfaces sorted
2316 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2317 if (extra_class && remote_class->interfaces [i] > extra_class) {
2318 key [j++] = extra_class;
2321 key [j] = remote_class->interfaces [i];
2324 key [j] = extra_class;
2326 // Replace the old class. The interface list is the same
2327 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2328 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2329 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2330 for (i = 0; i < remote_class->interface_count; i++)
2331 key [2 + i] = remote_class->interfaces [i];
2339 * copy_remote_class_key:
2341 * Make a copy of KEY in the domain and return the copy.
2344 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2346 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2347 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2349 memcpy (mp_key, key, key_size);
2355 * mono_remote_class:
2356 * @domain: the application domain
2357 * @class_name: name of the remote class
2359 * Creates and initializes a MonoRemoteClass object for a remote type.
2361 * Can raise an exception on failure.
2364 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2367 MonoRemoteClass *rc;
2368 gpointer* key, *mp_key;
2371 key = create_remote_class_key (NULL, proxy_class);
2373 mono_domain_lock (domain);
2374 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2378 mono_domain_unlock (domain);
2382 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2383 if (!mono_error_ok (&error)) {
2385 mono_domain_unlock (domain);
2386 mono_error_raise_exception (&error);
2389 mp_key = copy_remote_class_key (domain, key);
2393 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2394 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2395 rc->interface_count = 1;
2396 rc->interfaces [0] = proxy_class;
2397 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2399 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2400 rc->interface_count = 0;
2401 rc->proxy_class = proxy_class;
2404 rc->default_vtable = NULL;
2405 rc->xdomain_vtable = NULL;
2406 rc->proxy_class_name = name;
2407 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2409 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2411 mono_domain_unlock (domain);
2416 * clone_remote_class:
2417 * Creates a copy of the remote_class, adding the provided class or interface
2419 static MonoRemoteClass*
2420 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2422 MonoRemoteClass *rc;
2423 gpointer* key, *mp_key;
2425 key = create_remote_class_key (remote_class, extra_class);
2426 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2432 mp_key = copy_remote_class_key (domain, key);
2436 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2438 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2439 rc->proxy_class = remote_class->proxy_class;
2440 rc->interface_count = remote_class->interface_count + 1;
2442 // Keep the list of interfaces sorted, since the hash key of
2443 // the remote class depends on this
2444 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2445 if (remote_class->interfaces [i] > extra_class && i == j)
2446 rc->interfaces [j++] = extra_class;
2447 rc->interfaces [j] = remote_class->interfaces [i];
2450 rc->interfaces [j] = extra_class;
2452 // Replace the old class. The interface array is the same
2453 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2454 rc->proxy_class = extra_class;
2455 rc->interface_count = remote_class->interface_count;
2456 if (rc->interface_count > 0)
2457 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2460 rc->default_vtable = NULL;
2461 rc->xdomain_vtable = NULL;
2462 rc->proxy_class_name = remote_class->proxy_class_name;
2464 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2470 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2472 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2473 mono_domain_lock (domain);
2474 if (rp->target_domain_id != -1) {
2475 if (remote_class->xdomain_vtable == NULL)
2476 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2477 mono_domain_unlock (domain);
2478 mono_loader_unlock ();
2479 return remote_class->xdomain_vtable;
2481 if (remote_class->default_vtable == NULL) {
2484 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2485 klass = mono_class_from_mono_type (type);
2486 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2487 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2489 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2492 mono_domain_unlock (domain);
2493 mono_loader_unlock ();
2494 return remote_class->default_vtable;
2498 * mono_upgrade_remote_class:
2499 * @domain: the application domain
2500 * @tproxy: the proxy whose remote class has to be upgraded.
2501 * @klass: class to which the remote class can be casted.
2503 * Updates the vtable of the remote class by adding the necessary method slots
2504 * and interface offsets so it can be safely casted to klass. klass can be a
2505 * class or an interface.
2508 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2510 MonoTransparentProxy *tproxy;
2511 MonoRemoteClass *remote_class;
2512 gboolean redo_vtable;
2514 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2515 mono_domain_lock (domain);
2517 tproxy = (MonoTransparentProxy*) proxy_object;
2518 remote_class = tproxy->remote_class;
2520 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2523 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2524 if (remote_class->interfaces [i] == klass)
2525 redo_vtable = FALSE;
2528 redo_vtable = (remote_class->proxy_class != klass);
2532 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2533 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2536 mono_domain_unlock (domain);
2537 mono_loader_unlock ();
2542 * mono_object_get_virtual_method:
2543 * @obj: object to operate on.
2546 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2547 * the instance of a callvirt of method.
2550 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2553 MonoMethod **vtable;
2555 MonoMethod *res = NULL;
2557 klass = mono_object_class (obj);
2558 if (klass == mono_defaults.transparent_proxy_class) {
2559 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2565 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2568 mono_class_setup_vtable (klass);
2569 vtable = klass->vtable;
2571 if (method->slot == -1) {
2572 /* method->slot might not be set for instances of generic methods */
2573 if (method->is_inflated) {
2574 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2575 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2578 g_assert_not_reached ();
2582 /* check method->slot is a valid index: perform isinstance? */
2583 if (method->slot != -1) {
2584 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2586 gboolean variance_used = FALSE;
2587 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2588 g_assert (iface_offset > 0);
2589 res = vtable [iface_offset + method->slot];
2592 res = vtable [method->slot];
2597 /* It may be an interface, abstract class method or generic method */
2598 if (!res || mono_method_signature (res)->generic_param_count)
2601 /* generic methods demand invoke_with_check */
2602 if (mono_method_signature (res)->generic_param_count)
2603 res = mono_marshal_get_remoting_invoke_with_check (res);
2606 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2607 res = mono_cominterop_get_invoke (res);
2610 res = mono_marshal_get_remoting_invoke (res);
2613 if (method->is_inflated) {
2614 /* Have to inflate the result */
2615 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2625 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2627 g_error ("runtime invoke called on uninitialized runtime");
2631 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2634 * mono_runtime_invoke:
2635 * @method: method to invoke
2636 * @obJ: object instance
2637 * @params: arguments to the method
2638 * @exc: exception information.
2640 * Invokes the method represented by @method on the object @obj.
2642 * obj is the 'this' pointer, it should be NULL for static
2643 * methods, a MonoObject* for object instances and a pointer to
2644 * the value type for value types.
2646 * The params array contains the arguments to the method with the
2647 * same convention: MonoObject* pointers for object instances and
2648 * pointers to the value type otherwise.
2650 * From unmanaged code you'll usually use the
2651 * mono_runtime_invoke() variant.
2653 * Note that this function doesn't handle virtual methods for
2654 * you, it will exec the exact method you pass: we still need to
2655 * expose a function to lookup the derived class implementation
2656 * of a virtual method (there are examples of this in the code,
2659 * You can pass NULL as the exc argument if you don't want to
2660 * catch exceptions, otherwise, *exc will be set to the exception
2661 * thrown, if any. if an exception is thrown, you can't use the
2662 * MonoObject* result from the function.
2664 * If the method returns a value type, it is boxed in an object
2668 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2672 if (mono_runtime_get_no_exec ())
2673 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2675 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2676 mono_profiler_method_start_invoke (method);
2678 result = default_mono_runtime_invoke (method, obj, params, exc);
2680 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2681 mono_profiler_method_end_invoke (method);
2687 * mono_method_get_unmanaged_thunk:
2688 * @method: method to generate a thunk for.
2690 * Returns an unmanaged->managed thunk that can be used to call
2691 * a managed method directly from C.
2693 * The thunk's C signature closely matches the managed signature:
2695 * C#: public bool Equals (object obj);
2696 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2697 * MonoObject*, MonoException**);
2699 * The 1st ("this") parameter must not be used with static methods:
2701 * C#: public static bool ReferenceEquals (object a, object b);
2702 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2705 * The last argument must be a non-null pointer of a MonoException* pointer.
2706 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2707 * exception has been thrown in managed code. Otherwise it will point
2708 * to the MonoException* caught by the thunk. In this case, the result of
2709 * the thunk is undefined:
2711 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2712 * MonoException *ex = NULL;
2713 * Equals func = mono_method_get_unmanaged_thunk (method);
2714 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2716 * // handle exception
2719 * The calling convention of the thunk matches the platform's default
2720 * convention. This means that under Windows, C declarations must
2721 * contain the __stdcall attribute:
2723 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2724 * MonoObject*, MonoException**);
2728 * Value type arguments and return values are treated as they were objects:
2730 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2731 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2733 * Arguments must be properly boxed upon trunk's invocation, while return
2734 * values must be unboxed.
2737 mono_method_get_unmanaged_thunk (MonoMethod *method)
2739 method = mono_marshal_get_thunk_invoke_wrapper (method);
2740 return mono_compile_method (method);
2744 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2748 /* object fields cannot be byref, so we don't need a
2750 gpointer *p = (gpointer*)dest;
2757 case MONO_TYPE_BOOLEAN:
2759 case MONO_TYPE_U1: {
2760 guint8 *p = (guint8*)dest;
2761 *p = value ? *(guint8*)value : 0;
2766 case MONO_TYPE_CHAR: {
2767 guint16 *p = (guint16*)dest;
2768 *p = value ? *(guint16*)value : 0;
2771 #if SIZEOF_VOID_P == 4
2776 case MONO_TYPE_U4: {
2777 gint32 *p = (gint32*)dest;
2778 *p = value ? *(gint32*)value : 0;
2781 #if SIZEOF_VOID_P == 8
2786 case MONO_TYPE_U8: {
2787 gint64 *p = (gint64*)dest;
2788 *p = value ? *(gint64*)value : 0;
2791 case MONO_TYPE_R4: {
2792 float *p = (float*)dest;
2793 *p = value ? *(float*)value : 0;
2796 case MONO_TYPE_R8: {
2797 double *p = (double*)dest;
2798 *p = value ? *(double*)value : 0;
2801 case MONO_TYPE_STRING:
2802 case MONO_TYPE_SZARRAY:
2803 case MONO_TYPE_CLASS:
2804 case MONO_TYPE_OBJECT:
2805 case MONO_TYPE_ARRAY:
2806 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2808 case MONO_TYPE_FNPTR:
2809 case MONO_TYPE_PTR: {
2810 gpointer *p = (gpointer*)dest;
2811 *p = deref_pointer? *(gpointer*)value: value;
2814 case MONO_TYPE_VALUETYPE:
2815 /* note that 't' and 'type->type' can be different */
2816 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2817 t = mono_class_enum_basetype (type->data.klass)->type;
2820 MonoClass *class = mono_class_from_mono_type (type);
2821 int size = mono_class_value_size (class, NULL);
2823 memset (dest, 0, size);
2825 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2828 case MONO_TYPE_GENERICINST:
2829 t = type->data.generic_class->container_class->byval_arg.type;
2832 g_warning ("got type %x", type->type);
2833 g_assert_not_reached ();
2838 * mono_field_set_value:
2839 * @obj: Instance object
2840 * @field: MonoClassField describing the field to set
2841 * @value: The value to be set
2843 * Sets the value of the field described by @field in the object instance @obj
2844 * to the value passed in @value. This method should only be used for instance
2845 * fields. For static fields, use mono_field_static_set_value.
2847 * The value must be on the native format of the field type.
2850 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2854 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2856 dest = (char*)obj + field->offset;
2857 set_value (field->type, dest, value, FALSE);
2861 * mono_field_static_set_value:
2862 * @field: MonoClassField describing the field to set
2863 * @value: The value to be set
2865 * Sets the value of the static field described by @field
2866 * to the value passed in @value.
2868 * The value must be on the native format of the field type.
2871 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2875 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2876 /* you cant set a constant! */
2877 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2879 if (field->offset == -1) {
2880 /* Special static */
2881 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2882 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2884 dest = (char*)vt->data + field->offset;
2886 set_value (field->type, dest, value, FALSE);
2889 /* Used by the debugger */
2891 mono_vtable_get_static_field_data (MonoVTable *vt)
2897 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
2901 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2902 if (field->offset == -1) {
2903 /* Special static */
2904 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2905 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2907 src = (guint8*)vt->data + field->offset;
2910 src = (guint8*)obj + field->offset;
2917 * mono_field_get_value:
2918 * @obj: Object instance
2919 * @field: MonoClassField describing the field to fetch information from
2920 * @value: pointer to the location where the value will be stored
2922 * Use this routine to get the value of the field @field in the object
2925 * The pointer provided by value must be of the field type, for reference
2926 * types this is a MonoObject*, for value types its the actual pointer to
2931 * mono_field_get_value (obj, int_field, &i);
2934 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2938 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2940 src = (char*)obj + field->offset;
2941 set_value (field->type, value, src, TRUE);
2945 * mono_field_get_value_object:
2946 * @domain: domain where the object will be created (if boxing)
2947 * @field: MonoClassField describing the field to fetch information from
2948 * @obj: The object instance for the field.
2950 * Returns: a new MonoObject with the value from the given field. If the
2951 * field represents a value type, the value is boxed.
2955 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2959 MonoVTable *vtable = NULL;
2961 gboolean is_static = FALSE;
2962 gboolean is_ref = FALSE;
2964 switch (field->type->type) {
2965 case MONO_TYPE_STRING:
2966 case MONO_TYPE_OBJECT:
2967 case MONO_TYPE_CLASS:
2968 case MONO_TYPE_ARRAY:
2969 case MONO_TYPE_SZARRAY:
2974 case MONO_TYPE_BOOLEAN:
2977 case MONO_TYPE_CHAR:
2986 case MONO_TYPE_VALUETYPE:
2987 is_ref = field->type->byref;
2989 case MONO_TYPE_GENERICINST:
2990 is_ref = !field->type->data.generic_class->container_class->valuetype;
2993 g_error ("type 0x%x not handled in "
2994 "mono_field_get_value_object", field->type->type);
2998 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3000 vtable = mono_class_vtable (domain, field->parent);
3002 char *name = mono_type_get_full_name (field->parent);
3003 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
3007 if (!vtable->initialized)
3008 mono_runtime_class_init (vtable);
3013 mono_field_static_get_value (vtable, field, &o);
3015 mono_field_get_value (obj, field, &o);
3020 /* boxed value type */
3021 klass = mono_class_from_mono_type (field->type);
3023 if (mono_class_is_nullable (klass))
3024 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3026 o = mono_object_new (domain, klass);
3027 v = ((gchar *) o) + sizeof (MonoObject);
3029 mono_field_static_get_value (vtable, field, v);
3031 mono_field_get_value (obj, field, v);
3038 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3041 const char *p = blob;
3042 mono_metadata_decode_blob_size (p, &p);
3045 case MONO_TYPE_BOOLEAN:
3048 *(guint8 *) value = *p;
3050 case MONO_TYPE_CHAR:
3053 *(guint16*) value = read16 (p);
3057 *(guint32*) value = read32 (p);
3061 *(guint64*) value = read64 (p);
3064 readr4 (p, (float*) value);
3067 readr8 (p, (double*) value);
3069 case MONO_TYPE_STRING:
3070 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3072 case MONO_TYPE_CLASS:
3073 *(gpointer*) value = NULL;
3077 g_warning ("type 0x%02x should not be in constant table", type);
3083 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3085 MonoTypeEnum def_type;
3088 data = mono_class_get_field_default_value (field, &def_type);
3089 mono_get_constant_value_from_blob (domain, def_type, data, value);
3093 * mono_field_static_get_value:
3094 * @vt: vtable to the object
3095 * @field: MonoClassField describing the field to fetch information from
3096 * @value: where the value is returned
3098 * Use this routine to get the value of the static field @field value.
3100 * The pointer provided by value must be of the field type, for reference
3101 * types this is a MonoObject*, for value types its the actual pointer to
3106 * mono_field_static_get_value (vt, int_field, &i);
3109 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3113 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3115 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3116 get_default_field_value (vt->domain, field, value);
3120 if (field->offset == -1) {
3121 /* Special static */
3122 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3123 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3125 src = (char*)vt->data + field->offset;
3127 set_value (field->type, value, src, TRUE);
3131 * mono_property_set_value:
3132 * @prop: MonoProperty to set
3133 * @obj: instance object on which to act
3134 * @params: parameters to pass to the propery
3135 * @exc: optional exception
3137 * Invokes the property's set method with the given arguments on the
3138 * object instance obj (or NULL for static properties).
3140 * You can pass NULL as the exc argument if you don't want to
3141 * catch exceptions, otherwise, *exc will be set to the exception
3142 * thrown, if any. if an exception is thrown, you can't use the
3143 * MonoObject* result from the function.
3146 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3148 default_mono_runtime_invoke (prop->set, obj, params, exc);
3152 * mono_property_get_value:
3153 * @prop: MonoProperty to fetch
3154 * @obj: instance object on which to act
3155 * @params: parameters to pass to the propery
3156 * @exc: optional exception
3158 * Invokes the property's get method with the given arguments on the
3159 * object instance obj (or NULL for static properties).
3161 * You can pass NULL as the exc argument if you don't want to
3162 * catch exceptions, otherwise, *exc will be set to the exception
3163 * thrown, if any. if an exception is thrown, you can't use the
3164 * MonoObject* result from the function.
3166 * Returns: the value from invoking the get method on the property.
3169 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3171 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3175 * mono_nullable_init:
3176 * @buf: The nullable structure to initialize.
3177 * @value: the value to initialize from
3178 * @klass: the type for the object
3180 * Initialize the nullable structure pointed to by @buf from @value which
3181 * should be a boxed value type. The size of @buf should be able to hold
3182 * as much data as the @klass->instance_size (which is the number of bytes
3183 * that will be copies).
3185 * Since Nullables have variable structure, we can not define a C
3186 * structure for them.
3189 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3191 MonoClass *param_class = klass->cast_class;
3193 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3194 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3196 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3198 if (param_class->has_references)
3199 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3201 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3203 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3208 * mono_nullable_box:
3209 * @buf: The buffer representing the data to be boxed
3210 * @klass: the type to box it as.
3212 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3216 mono_nullable_box (guint8 *buf, MonoClass *klass)
3218 MonoClass *param_class = klass->cast_class;
3220 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3221 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3223 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3224 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3225 if (param_class->has_references)
3226 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3228 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3236 * mono_get_delegate_invoke:
3237 * @klass: The delegate class
3239 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3242 mono_get_delegate_invoke (MonoClass *klass)
3246 /* This is called at runtime, so avoid the slower search in metadata */
3247 mono_class_setup_methods (klass);
3248 if (klass->exception_type)
3250 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3257 * mono_runtime_delegate_invoke:
3258 * @delegate: pointer to a delegate object.
3259 * @params: parameters for the delegate.
3260 * @exc: Pointer to the exception result.
3262 * Invokes the delegate method @delegate with the parameters provided.
3264 * You can pass NULL as the exc argument if you don't want to
3265 * catch exceptions, otherwise, *exc will be set to the exception
3266 * thrown, if any. if an exception is thrown, you can't use the
3267 * MonoObject* result from the function.
3270 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3274 im = mono_get_delegate_invoke (delegate->vtable->klass);
3277 return mono_runtime_invoke (im, delegate, params, exc);
3280 static char **main_args = NULL;
3281 static int num_main_args;
3284 * mono_runtime_get_main_args:
3286 * Returns: a MonoArray with the arguments passed to the main program
3289 mono_runtime_get_main_args (void)
3293 MonoDomain *domain = mono_domain_get ();
3298 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3300 for (i = 0; i < num_main_args; ++i)
3301 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3307 fire_process_exit_event (void)
3309 MonoClassField *field;
3310 MonoDomain *domain = mono_domain_get ();
3312 MonoObject *delegate, *exc;
3314 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3317 if (domain != mono_get_root_domain ())
3320 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3321 if (delegate == NULL)
3326 mono_runtime_delegate_invoke (delegate, pa, &exc);
3330 * mono_runtime_run_main:
3331 * @method: the method to start the application with (usually Main)
3332 * @argc: number of arguments from the command line
3333 * @argv: array of strings from the command line
3334 * @exc: excetption results
3336 * Execute a standard Main() method (argc/argv contains the
3337 * executable name). This method also sets the command line argument value
3338 * needed by System.Environment.
3343 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3347 MonoArray *args = NULL;
3348 MonoDomain *domain = mono_domain_get ();
3349 gchar *utf8_fullpath;
3352 g_assert (method != NULL);
3354 mono_thread_set_main (mono_thread_current ());
3356 main_args = g_new0 (char*, argc);
3357 num_main_args = argc;
3359 if (!g_path_is_absolute (argv [0])) {
3360 gchar *basename = g_path_get_basename (argv [0]);
3361 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3365 utf8_fullpath = mono_utf8_from_external (fullpath);
3366 if(utf8_fullpath == NULL) {
3367 /* Printing the arg text will cause glib to
3368 * whinge about "Invalid UTF-8", but at least
3369 * its relevant, and shows the problem text
3372 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3373 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3380 utf8_fullpath = mono_utf8_from_external (argv[0]);
3381 if(utf8_fullpath == NULL) {
3382 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3383 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3388 main_args [0] = utf8_fullpath;
3390 for (i = 1; i < argc; ++i) {
3393 utf8_arg=mono_utf8_from_external (argv[i]);
3394 if(utf8_arg==NULL) {
3395 /* Ditto the comment about Invalid UTF-8 here */
3396 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3397 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3401 main_args [i] = utf8_arg;
3405 if (mono_method_signature (method)->param_count) {
3406 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3407 for (i = 0; i < argc; ++i) {
3408 /* The encodings should all work, given that
3409 * we've checked all these args for the
3412 gchar *str = mono_utf8_from_external (argv [i]);
3413 MonoString *arg = mono_string_new (domain, str);
3414 mono_array_setref (args, i, arg);
3418 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3421 mono_assembly_set_main (method->klass->image->assembly);
3423 result = mono_runtime_exec_main (method, args, exc);
3424 fire_process_exit_event ();
3429 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3431 static MonoMethod *serialize_method;
3436 if (!serialize_method) {
3437 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3438 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3441 if (!serialize_method) {
3446 g_assert (!mono_object_class (obj)->marshalbyref);
3450 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3458 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3460 static MonoMethod *deserialize_method;
3465 if (!deserialize_method) {
3466 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3467 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3469 if (!deserialize_method) {
3476 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3484 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3486 static MonoMethod *get_proxy_method;
3488 MonoDomain *domain = mono_domain_get ();
3489 MonoRealProxy *real_proxy;
3490 MonoReflectionType *reflection_type;
3491 MonoTransparentProxy *transparent_proxy;
3493 if (!get_proxy_method)
3494 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3496 g_assert (obj->vtable->klass->marshalbyref);
3498 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3499 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3501 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3502 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3505 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3509 return (MonoObject*) transparent_proxy;
3513 * mono_object_xdomain_representation
3515 * @target_domain: a domain
3516 * @exc: pointer to a MonoObject*
3518 * Creates a representation of obj in the domain target_domain. This
3519 * is either a copy of obj arrived through via serialization and
3520 * deserialization or a proxy, depending on whether the object is
3521 * serializable or marshal by ref. obj must not be in target_domain.
3523 * If the object cannot be represented in target_domain, NULL is
3524 * returned and *exc is set to an appropriate exception.
3527 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3529 MonoObject *deserialized = NULL;
3530 gboolean failure = FALSE;
3534 if (mono_object_class (obj)->marshalbyref) {
3535 deserialized = make_transparent_proxy (obj, &failure, exc);
3537 MonoDomain *domain = mono_domain_get ();
3538 MonoObject *serialized;
3540 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3541 serialized = serialize_object (obj, &failure, exc);
3542 mono_domain_set_internal_with_options (target_domain, FALSE);
3544 deserialized = deserialize_object (serialized, &failure, exc);
3545 if (domain != target_domain)
3546 mono_domain_set_internal_with_options (domain, FALSE);
3549 return deserialized;
3552 /* Used in call_unhandled_exception_delegate */
3554 create_unhandled_exception_eventargs (MonoObject *exc)
3558 MonoMethod *method = NULL;
3559 MonoBoolean is_terminating = TRUE;
3562 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3565 mono_class_init (klass);
3567 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3568 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3572 args [1] = &is_terminating;
3574 obj = mono_object_new (mono_domain_get (), klass);
3575 mono_runtime_invoke (method, obj, args, NULL);
3580 /* Used in mono_unhandled_exception */
3582 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3583 MonoObject *e = NULL;
3585 MonoDomain *current_domain = mono_domain_get ();
3587 if (domain != current_domain)
3588 mono_domain_set_internal_with_options (domain, FALSE);
3590 g_assert (domain == mono_object_domain (domain->domain));
3592 if (mono_object_domain (exc) != domain) {
3593 MonoObject *serialization_exc;
3595 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3597 if (serialization_exc) {
3599 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3602 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3603 "System.Runtime.Serialization", "SerializationException",
3604 "Could not serialize unhandled exception.");
3608 g_assert (mono_object_domain (exc) == domain);
3610 pa [0] = domain->domain;
3611 pa [1] = create_unhandled_exception_eventargs (exc);
3612 mono_runtime_delegate_invoke (delegate, pa, &e);
3614 if (domain != current_domain)
3615 mono_domain_set_internal_with_options (current_domain, FALSE);
3619 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3620 if (!mono_error_ok (&error)) {
3621 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3622 mono_error_cleanup (&error);
3624 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3630 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3633 * mono_runtime_unhandled_exception_policy_set:
3634 * @policy: the new policy
3636 * This is a VM internal routine.
3638 * Sets the runtime policy for handling unhandled exceptions.
3641 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3642 runtime_unhandled_exception_policy = policy;
3646 * mono_runtime_unhandled_exception_policy_get:
3648 * This is a VM internal routine.
3650 * Gets the runtime policy for handling unhandled exceptions.
3652 MonoRuntimeUnhandledExceptionPolicy
3653 mono_runtime_unhandled_exception_policy_get (void) {
3654 return runtime_unhandled_exception_policy;
3658 * mono_unhandled_exception:
3659 * @exc: exception thrown
3661 * This is a VM internal routine.
3663 * We call this function when we detect an unhandled exception
3664 * in the default domain.
3666 * It invokes the * UnhandledException event in AppDomain or prints
3667 * a warning to the console
3670 mono_unhandled_exception (MonoObject *exc)
3672 MonoDomain *current_domain = mono_domain_get ();
3673 MonoDomain *root_domain = mono_get_root_domain ();
3674 MonoClassField *field;
3675 MonoObject *current_appdomain_delegate;
3676 MonoObject *root_appdomain_delegate;
3678 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3679 "UnhandledException");
3682 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3683 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3684 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3685 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3686 if (current_domain != root_domain) {
3687 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3689 current_appdomain_delegate = NULL;
3692 /* set exitcode only if we will abort the process */
3694 mono_environment_exitcode_set (1);
3695 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3696 mono_print_unhandled_exception (exc);
3698 if (root_appdomain_delegate) {
3699 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3701 if (current_appdomain_delegate) {
3702 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3709 * Launch a new thread to execute a function
3711 * main_func is called back from the thread with main_args as the
3712 * parameter. The callback function is expected to start Main()
3713 * eventually. This function then waits for all managed threads to
3715 * It is not necesseray anymore to execute managed code in a subthread,
3716 * so this function should not be used anymore by default: just
3717 * execute the code and then call mono_thread_manage ().
3720 mono_runtime_exec_managed_code (MonoDomain *domain,
3721 MonoMainThreadFunc main_func,
3724 mono_thread_create (domain, main_func, main_args);
3726 mono_thread_manage ();
3730 * Execute a standard Main() method (args doesn't contain the
3734 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3739 MonoCustomAttrInfo* cinfo;
3740 gboolean has_stathread_attribute;
3741 MonoInternalThread* thread = mono_thread_internal_current ();
3747 domain = mono_object_domain (args);
3748 if (!domain->entry_assembly) {
3750 MonoAssembly *assembly;
3752 assembly = method->klass->image->assembly;
3753 domain->entry_assembly = assembly;
3754 /* Domains created from another domain already have application_base and configuration_file set */
3755 if (domain->setup->application_base == NULL) {
3756 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3759 if (domain->setup->configuration_file == NULL) {
3760 str = g_strconcat (assembly->image->name, ".config", NULL);
3761 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3763 mono_set_private_bin_path_from_config (domain);
3767 cinfo = mono_custom_attrs_from_method (method);
3769 static MonoClass *stathread_attribute = NULL;
3770 if (!stathread_attribute)
3771 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3772 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3774 mono_custom_attrs_free (cinfo);
3776 has_stathread_attribute = FALSE;
3778 if (has_stathread_attribute) {
3779 thread->apartment_state = ThreadApartmentState_STA;
3781 thread->apartment_state = ThreadApartmentState_MTA;
3783 mono_thread_init_apartment_state ();
3785 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3787 /* FIXME: check signature of method */
3788 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3790 res = mono_runtime_invoke (method, NULL, pa, exc);
3792 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3796 mono_environment_exitcode_set (rval);
3798 mono_runtime_invoke (method, NULL, pa, exc);
3802 /* If the return type of Main is void, only
3803 * set the exitcode if an exception was thrown
3804 * (we don't want to blow away an
3805 * explicitly-set exit code)
3808 mono_environment_exitcode_set (rval);
3812 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3818 * mono_install_runtime_invoke:
3819 * @func: Function to install
3821 * This is a VM internal routine
3824 mono_install_runtime_invoke (MonoInvokeFunc func)
3826 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3831 * mono_runtime_invoke_array:
3832 * @method: method to invoke
3833 * @obJ: object instance
3834 * @params: arguments to the method
3835 * @exc: exception information.
3837 * Invokes the method represented by @method on the object @obj.
3839 * obj is the 'this' pointer, it should be NULL for static
3840 * methods, a MonoObject* for object instances and a pointer to
3841 * the value type for value types.
3843 * The params array contains the arguments to the method with the
3844 * same convention: MonoObject* pointers for object instances and
3845 * pointers to the value type otherwise. The _invoke_array
3846 * variant takes a C# object[] as the params argument (MonoArray
3847 * *params): in this case the value types are boxed inside the
3848 * respective reference representation.
3850 * From unmanaged code you'll usually use the
3851 * mono_runtime_invoke() variant.
3853 * Note that this function doesn't handle virtual methods for
3854 * you, it will exec the exact method you pass: we still need to
3855 * expose a function to lookup the derived class implementation
3856 * of a virtual method (there are examples of this in the code,
3859 * You can pass NULL as the exc argument if you don't want to
3860 * catch exceptions, otherwise, *exc will be set to the exception
3861 * thrown, if any. if an exception is thrown, you can't use the
3862 * MonoObject* result from the function.
3864 * If the method returns a value type, it is boxed in an object
3868 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3871 MonoMethodSignature *sig = mono_method_signature (method);
3872 gpointer *pa = NULL;
3875 gboolean has_byref_nullables = FALSE;
3877 if (NULL != params) {
3878 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3879 for (i = 0; i < mono_array_length (params); i++) {
3880 MonoType *t = sig->params [i];
3886 case MONO_TYPE_BOOLEAN:
3889 case MONO_TYPE_CHAR:
3898 case MONO_TYPE_VALUETYPE:
3899 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3900 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3901 pa [i] = mono_array_get (params, MonoObject*, i);
3903 has_byref_nullables = TRUE;
3905 /* MS seems to create the objects if a null is passed in */
3906 if (!mono_array_get (params, MonoObject*, i))
3907 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3911 * We can't pass the unboxed vtype byref to the callee, since
3912 * that would mean the callee would be able to modify boxed
3913 * primitive types. So we (and MS) make a copy of the boxed
3914 * object, pass that to the callee, and replace the original
3915 * boxed object in the arg array with the copy.
3917 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3918 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3919 mono_array_setref (params, i, copy);
3922 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3925 case MONO_TYPE_STRING:
3926 case MONO_TYPE_OBJECT:
3927 case MONO_TYPE_CLASS:
3928 case MONO_TYPE_ARRAY:
3929 case MONO_TYPE_SZARRAY:
3931 pa [i] = mono_array_addr (params, MonoObject*, i);
3932 // FIXME: I need to check this code path
3934 pa [i] = mono_array_get (params, MonoObject*, i);
3936 case MONO_TYPE_GENERICINST:
3938 t = &t->data.generic_class->container_class->this_arg;
3940 t = &t->data.generic_class->container_class->byval_arg;
3942 case MONO_TYPE_PTR: {
3945 /* The argument should be an IntPtr */
3946 arg = mono_array_get (params, MonoObject*, i);
3950 g_assert (arg->vtable->klass == mono_defaults.int_class);
3951 pa [i] = ((MonoIntPtr*)arg)->m_value;
3956 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3961 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3964 if (mono_class_is_nullable (method->klass)) {
3965 /* Need to create a boxed vtype instead */
3971 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3975 obj = mono_object_new (mono_domain_get (), method->klass);
3976 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3977 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3979 if (method->klass->valuetype)
3980 o = mono_object_unbox (obj);
3983 } else if (method->klass->valuetype) {
3984 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3987 mono_runtime_invoke (method, o, pa, exc);
3990 if (mono_class_is_nullable (method->klass)) {
3991 MonoObject *nullable;
3993 /* Convert the unboxed vtype into a Nullable structure */
3994 nullable = mono_object_new (mono_domain_get (), method->klass);
3996 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3997 obj = mono_object_unbox (nullable);
4000 /* obj must be already unboxed if needed */
4001 res = mono_runtime_invoke (method, obj, pa, exc);
4003 if (sig->ret->type == MONO_TYPE_PTR) {
4004 MonoClass *pointer_class;
4005 static MonoMethod *box_method;
4007 MonoObject *box_exc;
4010 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4011 * convert it to a Pointer object.
4013 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4015 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4017 g_assert (res->vtable->klass == mono_defaults.int_class);
4018 box_args [0] = ((MonoIntPtr*)res)->m_value;
4019 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4020 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4021 g_assert (!box_exc);
4024 if (has_byref_nullables) {
4026 * The runtime invoke wrapper already converted byref nullables back,
4027 * and stored them in pa, we just need to copy them back to the
4030 for (i = 0; i < mono_array_length (params); i++) {
4031 MonoType *t = sig->params [i];
4033 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4034 mono_array_setref (params, i, pa [i]);
4043 arith_overflow (void)
4045 mono_raise_exception (mono_get_exception_overflow ());
4049 * mono_object_allocate:
4050 * @size: number of bytes to allocate
4052 * This is a very simplistic routine until we have our GC-aware
4055 * Returns: an allocated object of size @size, or NULL on failure.
4057 static inline void *
4058 mono_object_allocate (size_t size, MonoVTable *vtable)
4061 mono_stats.new_object_count++;
4062 ALLOC_OBJECT (o, vtable, size);
4068 * mono_object_allocate_ptrfree:
4069 * @size: number of bytes to allocate
4071 * Note that the memory allocated is not zeroed.
4072 * Returns: an allocated object of size @size, or NULL on failure.
4074 static inline void *
4075 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4078 mono_stats.new_object_count++;
4079 ALLOC_PTRFREE (o, vtable, size);
4083 static inline void *
4084 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4087 ALLOC_TYPED (o, size, vtable);
4088 mono_stats.new_object_count++;
4095 * @klass: the class of the object that we want to create
4097 * Returns: a newly created object whose definition is
4098 * looked up using @klass. This will not invoke any constructors,
4099 * so the consumer of this routine has to invoke any constructors on
4100 * its own to initialize the object.
4102 * It returns NULL on failure.
4105 mono_object_new (MonoDomain *domain, MonoClass *klass)
4109 MONO_ARCH_SAVE_REGS;
4110 vtable = mono_class_vtable (domain, klass);
4113 return mono_object_new_specific (vtable);
4117 * mono_object_new_specific:
4118 * @vtable: the vtable of the object that we want to create
4120 * Returns: A newly created object with class and domain specified
4124 mono_object_new_specific (MonoVTable *vtable)
4128 MONO_ARCH_SAVE_REGS;
4130 /* check for is_com_object for COM Interop */
4131 if (vtable->remote || vtable->klass->is_com_object)
4134 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4137 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4140 mono_class_init (klass);
4142 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4144 vtable->domain->create_proxy_for_type_method = im;
4147 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4149 o = mono_runtime_invoke (im, NULL, pa, NULL);
4150 if (o != NULL) return o;
4153 return mono_object_new_alloc_specific (vtable);
4157 mono_object_new_alloc_specific (MonoVTable *vtable)
4161 if (!vtable->klass->has_references) {
4162 o = mono_object_new_ptrfree (vtable);
4163 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4164 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4166 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4167 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4169 if (G_UNLIKELY (vtable->klass->has_finalize))
4170 mono_object_register_finalizer (o);
4172 if (G_UNLIKELY (profile_allocs))
4173 mono_profiler_allocation (o, vtable->klass);
4178 mono_object_new_fast (MonoVTable *vtable)
4181 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4186 mono_object_new_ptrfree (MonoVTable *vtable)
4189 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4190 #if NEED_TO_ZERO_PTRFREE
4191 /* an inline memset is much faster for the common vcase of small objects
4192 * note we assume the allocated size is a multiple of sizeof (void*).
4194 if (vtable->klass->instance_size < 128) {
4196 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4197 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4203 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4210 mono_object_new_ptrfree_box (MonoVTable *vtable)
4213 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4214 /* the object will be boxed right away, no need to memzero it */
4219 * mono_class_get_allocation_ftn:
4221 * @for_box: the object will be used for boxing
4222 * @pass_size_in_words:
4224 * Return the allocation function appropriate for the given class.
4228 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4230 *pass_size_in_words = FALSE;
4232 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4233 profile_allocs = FALSE;
4235 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4236 return mono_object_new_specific;
4238 if (!vtable->klass->has_references) {
4239 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4241 return mono_object_new_ptrfree_box;
4242 return mono_object_new_ptrfree;
4245 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4247 return mono_object_new_fast;
4250 * FIXME: This is actually slower than mono_object_new_fast, because
4251 * of the overhead of parameter passing.
4254 *pass_size_in_words = TRUE;
4255 #ifdef GC_REDIRECT_TO_LOCAL
4256 return GC_local_gcj_fast_malloc;
4258 return GC_gcj_fast_malloc;
4263 return mono_object_new_specific;
4267 * mono_object_new_from_token:
4268 * @image: Context where the type_token is hosted
4269 * @token: a token of the type that we want to create
4271 * Returns: A newly created object whose definition is
4272 * looked up using @token in the @image image
4275 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4279 class = mono_class_get (image, token);
4281 return mono_object_new (domain, class);
4286 * mono_object_clone:
4287 * @obj: the object to clone
4289 * Returns: A newly created object who is a shallow copy of @obj
4292 mono_object_clone (MonoObject *obj)
4295 int size = obj->vtable->klass->instance_size;
4297 o = mono_object_allocate (size, obj->vtable);
4299 if (obj->vtable->klass->has_references) {
4300 mono_gc_wbarrier_object_copy (o, obj);
4302 int size = obj->vtable->klass->instance_size;
4303 /* do not copy the sync state */
4304 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4306 if (G_UNLIKELY (profile_allocs))
4307 mono_profiler_allocation (o, obj->vtable->klass);
4309 if (obj->vtable->klass->has_finalize)
4310 mono_object_register_finalizer (o);
4315 * mono_array_full_copy:
4316 * @src: source array to copy
4317 * @dest: destination array
4319 * Copies the content of one array to another with exactly the same type and size.
4322 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4324 mono_array_size_t size;
4325 MonoClass *klass = src->obj.vtable->klass;
4327 MONO_ARCH_SAVE_REGS;
4329 g_assert (klass == dest->obj.vtable->klass);
4331 size = mono_array_length (src);
4332 g_assert (size == mono_array_length (dest));
4333 size *= mono_array_element_size (klass);
4335 if (klass->element_class->valuetype) {
4336 if (klass->element_class->has_references)
4337 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4339 memcpy (&dest->vector, &src->vector, size);
4341 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4344 memcpy (&dest->vector, &src->vector, size);
4349 * mono_array_clone_in_domain:
4350 * @domain: the domain in which the array will be cloned into
4351 * @array: the array to clone
4353 * This routine returns a copy of the array that is hosted on the
4354 * specified MonoDomain.
4357 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4360 mono_array_size_t size, i;
4361 mono_array_size_t *sizes;
4362 MonoClass *klass = array->obj.vtable->klass;
4364 MONO_ARCH_SAVE_REGS;
4366 if (array->bounds == NULL) {
4367 size = mono_array_length (array);
4368 o = mono_array_new_full (domain, klass, &size, NULL);
4370 size *= mono_array_element_size (klass);
4372 if (klass->element_class->valuetype) {
4373 if (klass->element_class->has_references)
4374 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4376 memcpy (&o->vector, &array->vector, size);
4378 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4381 memcpy (&o->vector, &array->vector, size);
4386 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4387 size = mono_array_element_size (klass);
4388 for (i = 0; i < klass->rank; ++i) {
4389 sizes [i] = array->bounds [i].length;
4390 size *= array->bounds [i].length;
4391 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4393 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4395 if (klass->element_class->valuetype) {
4396 if (klass->element_class->has_references)
4397 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4399 memcpy (&o->vector, &array->vector, size);
4401 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4404 memcpy (&o->vector, &array->vector, size);
4412 * @array: the array to clone
4414 * Returns: A newly created array who is a shallow copy of @array
4417 mono_array_clone (MonoArray *array)
4419 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4422 /* helper macros to check for overflow when calculating the size of arrays */
4423 #ifdef MONO_BIG_ARRAYS
4424 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4425 #define MYGUINT_MAX MYGUINT64_MAX
4426 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4427 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4428 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4429 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4430 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4432 #define MYGUINT32_MAX 4294967295U
4433 #define MYGUINT_MAX MYGUINT32_MAX
4434 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4435 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4436 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4437 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4438 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4442 mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
4444 mono_array_size_t byte_len;
4446 byte_len = mono_array_element_size (class);
4447 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4450 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4452 byte_len += sizeof (MonoArray);
4460 * mono_array_new_full:
4461 * @domain: domain where the object is created
4462 * @array_class: array class
4463 * @lengths: lengths for each dimension in the array
4464 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4466 * This routine creates a new array objects with the given dimensions,
4467 * lower bounds and type.
4470 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4472 mono_array_size_t byte_len, len, bounds_size;
4475 MonoArrayBounds *bounds;
4479 if (!array_class->inited)
4480 mono_class_init (array_class);
4484 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4485 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4487 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4491 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4493 for (i = 0; i < array_class->rank; ++i) {
4494 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4496 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4497 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4502 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4503 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4507 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4508 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4509 byte_len = (byte_len + 3) & ~3;
4510 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4511 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4512 byte_len += bounds_size;
4515 * Following three lines almost taken from mono_object_new ():
4516 * they need to be kept in sync.
4518 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4519 #ifndef HAVE_SGEN_GC
4520 if (!array_class->has_references) {
4521 o = mono_object_allocate_ptrfree (byte_len, vtable);
4522 #if NEED_TO_ZERO_PTRFREE
4523 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4525 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4526 o = mono_object_allocate_spec (byte_len, vtable);
4528 o = mono_object_allocate (byte_len, vtable);
4531 array = (MonoArray*)o;
4532 array->max_length = len;
4535 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4536 array->bounds = bounds;
4540 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4542 o = mono_gc_alloc_vector (vtable, byte_len, len);
4543 array = (MonoArray*)o;
4544 mono_stats.new_object_count++;
4546 bounds = array->bounds;
4550 for (i = 0; i < array_class->rank; ++i) {
4551 bounds [i].length = lengths [i];
4553 bounds [i].lower_bound = lower_bounds [i];
4557 if (G_UNLIKELY (profile_allocs))
4558 mono_profiler_allocation (o, array_class);
4565 * @domain: domain where the object is created
4566 * @eclass: element class
4567 * @n: number of array elements
4569 * This routine creates a new szarray with @n elements of type @eclass.
4572 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4576 MONO_ARCH_SAVE_REGS;
4578 ac = mono_array_class_get (eclass, 1);
4581 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4585 * mono_array_new_specific:
4586 * @vtable: a vtable in the appropriate domain for an initialized class
4587 * @n: number of array elements
4589 * This routine is a fast alternative to mono_array_new() for code which
4590 * can be sure about the domain it operates in.
4593 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4599 MONO_ARCH_SAVE_REGS;
4601 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4606 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4607 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4610 #ifndef HAVE_SGEN_GC
4611 if (!vtable->klass->has_references) {
4612 o = mono_object_allocate_ptrfree (byte_len, vtable);
4613 #if NEED_TO_ZERO_PTRFREE
4614 ((MonoArray*)o)->bounds = NULL;
4615 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4617 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4618 o = mono_object_allocate_spec (byte_len, vtable);
4620 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4621 o = mono_object_allocate (byte_len, vtable);
4624 ao = (MonoArray *)o;
4627 o = mono_gc_alloc_vector (vtable, byte_len, n);
4629 mono_stats.new_object_count++;
4632 if (G_UNLIKELY (profile_allocs))
4633 mono_profiler_allocation (o, vtable->klass);
4639 * mono_string_new_utf16:
4640 * @text: a pointer to an utf16 string
4641 * @len: the length of the string
4643 * Returns: A newly created string object which contains @text.
4646 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4650 s = mono_string_new_size (domain, len);
4651 g_assert (s != NULL);
4653 memcpy (mono_string_chars (s), text, len * 2);
4659 * mono_string_new_size:
4660 * @text: a pointer to an utf16 string
4661 * @len: the length of the string
4663 * Returns: A newly created string object of @len
4666 mono_string_new_size (MonoDomain *domain, gint32 len)
4670 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4672 /* overflow ? can't fit it, can't allocate it! */
4674 mono_gc_out_of_memory (-1);
4676 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4679 #ifndef HAVE_SGEN_GC
4680 s = mono_object_allocate_ptrfree (size, vtable);
4684 s = mono_gc_alloc_string (vtable, size, len);
4686 #if NEED_TO_ZERO_PTRFREE
4689 if (G_UNLIKELY (profile_allocs))
4690 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4696 * mono_string_new_len:
4697 * @text: a pointer to an utf8 string
4698 * @length: number of bytes in @text to consider
4700 * Returns: A newly created string object which contains @text.
4703 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4705 GError *error = NULL;
4706 MonoString *o = NULL;
4708 glong items_written;
4710 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4713 o = mono_string_new_utf16 (domain, ut, items_written);
4715 g_error_free (error);
4724 * @text: a pointer to an utf8 string
4726 * Returns: A newly created string object which contains @text.
4729 mono_string_new (MonoDomain *domain, const char *text)
4731 GError *error = NULL;
4732 MonoString *o = NULL;
4734 glong items_written;
4739 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4742 o = mono_string_new_utf16 (domain, ut, items_written);
4744 g_error_free (error);
4747 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4752 MonoString *o = NULL;
4754 if (!g_utf8_validate (text, -1, &end))
4757 len = g_utf8_strlen (text, -1);
4758 o = mono_string_new_size (domain, len);
4759 str = mono_string_chars (o);
4761 while (text < end) {
4762 *str++ = g_utf8_get_char (text);
4763 text = g_utf8_next_char (text);
4770 * mono_string_new_wrapper:
4771 * @text: pointer to utf8 characters.
4773 * Helper function to create a string object from @text in the current domain.
4776 mono_string_new_wrapper (const char *text)
4778 MonoDomain *domain = mono_domain_get ();
4780 MONO_ARCH_SAVE_REGS;
4783 return mono_string_new (domain, text);
4790 * @class: the class of the value
4791 * @value: a pointer to the unboxed data
4793 * Returns: A newly created object which contains @value.
4796 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4802 g_assert (class->valuetype);
4803 if (mono_class_is_nullable (class))
4804 return mono_nullable_box (value, class);
4806 vtable = mono_class_vtable (domain, class);
4809 size = mono_class_instance_size (class);
4810 res = mono_object_new_alloc_specific (vtable);
4811 if (G_UNLIKELY (profile_allocs))
4812 mono_profiler_allocation (res, class);
4814 size = size - sizeof (MonoObject);
4817 g_assert (size == mono_class_value_size (class, NULL));
4818 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4820 #if NO_UNALIGNED_ACCESS
4821 memcpy ((char *)res + sizeof (MonoObject), value, size);
4825 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4828 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4831 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4834 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4837 memcpy ((char *)res + sizeof (MonoObject), value, size);
4841 if (class->has_finalize)
4842 mono_object_register_finalizer (res);
4848 * @dest: destination pointer
4849 * @src: source pointer
4850 * @klass: a valuetype class
4852 * Copy a valuetype from @src to @dest. This function must be used
4853 * when @klass contains references fields.
4856 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4858 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4862 * mono_value_copy_array:
4863 * @dest: destination array
4864 * @dest_idx: index in the @dest array
4865 * @src: source pointer
4866 * @count: number of items
4868 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4869 * This function must be used when @klass contains references fields.
4870 * Overlap is handled.
4873 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4875 int size = mono_array_element_size (dest->obj.vtable->klass);
4876 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4877 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4878 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4882 * mono_object_get_domain:
4883 * @obj: object to query
4885 * Returns: the MonoDomain where the object is hosted
4888 mono_object_get_domain (MonoObject *obj)
4890 return mono_object_domain (obj);
4894 * mono_object_get_class:
4895 * @obj: object to query
4897 * Returns: the MonOClass of the object.
4900 mono_object_get_class (MonoObject *obj)
4902 return mono_object_class (obj);
4905 * mono_object_get_size:
4906 * @o: object to query
4908 * Returns: the size, in bytes, of @o
4911 mono_object_get_size (MonoObject* o)
4913 MonoClass* klass = mono_object_class (o);
4914 if (klass == mono_defaults.string_class) {
4915 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4916 } else if (o->vtable->rank) {
4917 MonoArray *array = (MonoArray*)o;
4918 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4919 if (array->bounds) {
4922 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4926 return mono_class_instance_size (klass);
4931 * mono_object_unbox:
4932 * @obj: object to unbox
4934 * Returns: a pointer to the start of the valuetype boxed in this
4937 * This method will assert if the object passed is not a valuetype.
4940 mono_object_unbox (MonoObject *obj)
4942 /* add assert for valuetypes? */
4943 g_assert (obj->vtable->klass->valuetype);
4944 return ((char*)obj) + sizeof (MonoObject);
4948 * mono_object_isinst:
4950 * @klass: a pointer to a class
4952 * Returns: @obj if @obj is derived from @klass
4955 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4958 mono_class_init (klass);
4960 if (klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
4961 return mono_object_isinst_mbyref (obj, klass);
4966 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4970 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4979 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4980 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4984 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
4985 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
4988 MonoClass *oklass = vt->klass;
4989 if ((oklass == mono_defaults.transparent_proxy_class))
4990 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4992 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4996 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4998 MonoDomain *domain = mono_domain_get ();
5000 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5001 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5002 MonoMethod *im = NULL;
5005 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5006 im = mono_object_get_virtual_method (rp, im);
5009 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5012 res = mono_runtime_invoke (im, rp, pa, NULL);
5014 if (*(MonoBoolean *) mono_object_unbox(res)) {
5015 /* Update the vtable of the remote type, so it can safely cast to this new type */
5016 mono_upgrade_remote_class (domain, obj, klass);
5025 * mono_object_castclass_mbyref:
5027 * @klass: a pointer to a class
5029 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5032 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5034 if (!obj) return NULL;
5035 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5037 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5039 "InvalidCastException"));
5044 MonoDomain *orig_domain;
5050 str_lookup (MonoDomain *domain, gpointer user_data)
5052 LDStrInfo *info = user_data;
5053 if (info->res || domain == info->orig_domain)
5055 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5061 mono_string_get_pinned (MonoString *str)
5065 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5066 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5067 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5068 news->length = mono_string_length (str);
5073 #define mono_string_get_pinned(str) (str)
5077 mono_string_is_interned_lookup (MonoString *str, int insert)
5079 MonoGHashTable *ldstr_table;
5083 domain = ((MonoObject *)str)->vtable->domain;
5084 ldstr_table = domain->ldstr_table;
5086 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
5091 str = mono_string_get_pinned (str);
5092 mono_g_hash_table_insert (ldstr_table, str, str);
5096 LDStrInfo ldstr_info;
5097 ldstr_info.orig_domain = domain;
5098 ldstr_info.ins = str;
5099 ldstr_info.res = NULL;
5101 mono_domain_foreach (str_lookup, &ldstr_info);
5102 if (ldstr_info.res) {
5104 * the string was already interned in some other domain:
5105 * intern it in the current one as well.
5107 mono_g_hash_table_insert (ldstr_table, str, str);
5117 * mono_string_is_interned:
5118 * @o: String to probe
5120 * Returns whether the string has been interned.
5123 mono_string_is_interned (MonoString *o)
5125 return mono_string_is_interned_lookup (o, FALSE);
5129 * mono_string_intern:
5130 * @o: String to intern
5132 * Interns the string passed.
5133 * Returns: The interned string.
5136 mono_string_intern (MonoString *str)
5138 return mono_string_is_interned_lookup (str, TRUE);
5143 * @domain: the domain where the string will be used.
5144 * @image: a metadata context
5145 * @idx: index into the user string table.
5147 * Implementation for the ldstr opcode.
5148 * Returns: a loaded string from the @image/@idx combination.
5151 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5153 MONO_ARCH_SAVE_REGS;
5155 if (image->dynamic) {
5156 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5157 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5158 mono_profiler_string_allocation (domain, str);
5161 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5162 return NULL; /*FIXME we should probably be raising an exception here*/
5163 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5168 * mono_ldstr_metadata_sig
5169 * @domain: the domain for the string
5170 * @sig: the signature of a metadata string
5172 * Returns: a MonoString for a string stored in the metadata
5175 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5177 const char *str = sig;
5178 MonoString *o, *interned;
5181 len2 = mono_metadata_decode_blob_size (str, &str);
5184 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5185 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5188 guint16 *p2 = (guint16*)mono_string_chars (o);
5189 for (i = 0; i < len2; ++i) {
5190 *p2 = GUINT16_FROM_LE (*p2);
5196 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5198 /* o will get garbage collected */
5202 o = mono_string_get_pinned (o);
5203 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5206 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5207 mono_profiler_string_allocation (domain, o);
5213 * mono_string_to_utf8:
5214 * @s: a System.String
5216 * Return the UTF8 representation for @s.
5217 * the resulting buffer nedds to be freed with g_free().
5219 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5222 mono_string_to_utf8 (MonoString *s)
5225 char *result = mono_string_to_utf8_checked (s, &error);
5227 if (!mono_error_ok (&error))
5228 mono_error_raise_exception (&error);
5233 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5237 GError *gerror = NULL;
5239 mono_error_init (error);
5245 return g_strdup ("");
5247 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5249 mono_error_set_argument (error, "string", "%s", gerror->message);
5250 g_error_free (gerror);
5253 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5254 if (s->length > written) {
5255 /* allocate the total length and copy the part of the string that has been converted */
5256 char *as2 = g_malloc0 (s->length);
5257 memcpy (as2, as, written);
5266 * mono_string_to_utf16:
5269 * Return an null-terminated array of the utf-16 chars
5270 * contained in @s. The result must be freed with g_free().
5271 * This is a temporary helper until our string implementation
5272 * is reworked to always include the null terminating char.
5275 mono_string_to_utf16 (MonoString *s)
5282 as = g_malloc ((s->length * 2) + 2);
5283 as [(s->length * 2)] = '\0';
5284 as [(s->length * 2) + 1] = '\0';
5287 return (gunichar2 *)(as);
5290 memcpy (as, mono_string_chars(s), s->length * 2);
5291 return (gunichar2 *)(as);
5295 * mono_string_from_utf16:
5296 * @data: the UTF16 string (LPWSTR) to convert
5298 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5300 * Returns: a MonoString.
5303 mono_string_from_utf16 (gunichar2 *data)
5305 MonoDomain *domain = mono_domain_get ();
5311 while (data [len]) len++;
5313 return mono_string_new_utf16 (domain, data, len);
5318 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5324 r = mono_string_to_utf8_checked (s, error);
5325 if (!mono_error_ok (error))
5331 len = strlen (r) + 1;
5333 mp_s = mono_mempool_alloc (mp, len);
5335 mp_s = mono_image_alloc (image, len);
5337 memcpy (mp_s, r, len);
5345 * mono_string_to_utf8_image:
5346 * @s: a System.String
5348 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5351 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5353 return mono_string_to_utf8_internal (NULL, image, s, error);
5357 * mono_string_to_utf8_mp:
5358 * @s: a System.String
5360 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5363 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5365 return mono_string_to_utf8_internal (mp, NULL, s, error);
5369 default_ex_handler (MonoException *ex)
5371 MonoObject *o = (MonoObject*)ex;
5372 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5376 static MonoExceptionFunc ex_handler = default_ex_handler;
5379 * mono_install_handler:
5380 * @func: exception handler
5382 * This is an internal JIT routine used to install the handler for exceptions
5386 mono_install_handler (MonoExceptionFunc func)
5388 ex_handler = func? func: default_ex_handler;
5392 * mono_raise_exception:
5393 * @ex: exception object
5395 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5398 mono_raise_exception (MonoException *ex)
5401 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5402 * that will cause gcc to omit the function epilog, causing problems when
5403 * the JIT tries to walk the stack, since the return address on the stack
5404 * will point into the next function in the executable, not this one.
5407 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5408 MonoInternalThread *thread = mono_thread_internal_current ();
5409 g_assert (ex->object.vtable->domain == mono_domain_get ());
5410 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5417 * mono_wait_handle_new:
5418 * @domain: Domain where the object will be created
5419 * @handle: Handle for the wait handle
5421 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5424 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5426 MonoWaitHandle *res;
5427 gpointer params [1];
5428 static MonoMethod *handle_set;
5430 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5432 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5434 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5436 params [0] = &handle;
5437 mono_runtime_invoke (handle_set, res, params, NULL);
5443 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5445 static MonoClassField *f_os_handle;
5446 static MonoClassField *f_safe_handle;
5448 if (!f_os_handle && !f_safe_handle) {
5449 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5450 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5455 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5459 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5466 mono_runtime_capture_context (MonoDomain *domain)
5468 RuntimeInvokeFunction runtime_invoke;
5470 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5471 MonoMethod *method = mono_get_context_capture_method ();
5472 MonoMethod *wrapper;
5475 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5476 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5477 domain->capture_context_method = mono_compile_method (method);
5480 runtime_invoke = domain->capture_context_runtime_invoke;
5482 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5485 * mono_async_result_new:
5486 * @domain:domain where the object will be created.
5487 * @handle: wait handle.
5488 * @state: state to pass to AsyncResult
5489 * @data: C closure data.
5491 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5492 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5496 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5498 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5499 MonoObject *context = mono_runtime_capture_context (domain);
5500 /* we must capture the execution context from the original thread */
5502 MONO_OBJECT_SETREF (res, execution_context, context);
5503 /* note: result may be null if the flow is suppressed */
5507 MONO_OBJECT_SETREF (res, object_data, object_data);
5508 MONO_OBJECT_SETREF (res, async_state, state);
5510 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5512 res->sync_completed = FALSE;
5513 res->completed = FALSE;
5519 mono_message_init (MonoDomain *domain,
5520 MonoMethodMessage *this,
5521 MonoReflectionMethod *method,
5522 MonoArray *out_args)
5524 static MonoClass *object_array_klass;
5525 static MonoClass *byte_array_klass;
5526 static MonoClass *string_array_klass;
5527 MonoMethodSignature *sig = mono_method_signature (method->method);
5533 if (!object_array_klass) {
5536 klass = mono_array_class_get (mono_defaults.object_class, 1);
5539 mono_memory_barrier ();
5540 object_array_klass = klass;
5542 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5545 mono_memory_barrier ();
5546 byte_array_klass = klass;
5548 klass = mono_array_class_get (mono_defaults.string_class, 1);
5551 mono_memory_barrier ();
5552 string_array_klass = klass;
5555 MONO_OBJECT_SETREF (this, method, method);
5557 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5558 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5559 this->async_result = NULL;
5560 this->call_type = CallType_Sync;
5562 names = g_new (char *, sig->param_count);
5563 mono_method_get_param_names (method->method, (const char **) names);
5564 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5566 for (i = 0; i < sig->param_count; i++) {
5567 name = mono_string_new (domain, names [i]);
5568 mono_array_setref (this->names, i, name);
5572 for (i = 0, j = 0; i < sig->param_count; i++) {
5573 if (sig->params [i]->byref) {
5575 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5576 mono_array_setref (this->args, i, arg);
5580 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5584 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5587 mono_array_set (this->arg_types, guint8, i, arg_type);
5592 * mono_remoting_invoke:
5593 * @real_proxy: pointer to a RealProxy object
5594 * @msg: The MonoMethodMessage to execute
5595 * @exc: used to store exceptions
5596 * @out_args: used to store output arguments
5598 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5599 * IMessage interface and it is not trivial to extract results from there. So
5600 * we call an helper method PrivateInvoke instead of calling
5601 * RealProxy::Invoke() directly.
5603 * Returns: the result object.
5606 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5607 MonoObject **exc, MonoArray **out_args)
5609 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5612 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5615 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5617 real_proxy->vtable->domain->private_invoke_method = im;
5620 pa [0] = real_proxy;
5625 return mono_runtime_invoke (im, NULL, pa, exc);
5629 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5630 MonoObject **exc, MonoArray **out_args)
5632 static MonoClass *object_array_klass;
5635 MonoMethodSignature *sig;
5637 int i, j, outarg_count = 0;
5639 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5641 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5642 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5643 target = tp->rp->unwrapped_server;
5645 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5649 domain = mono_domain_get ();
5650 method = msg->method->method;
5651 sig = mono_method_signature (method);
5653 for (i = 0; i < sig->param_count; i++) {
5654 if (sig->params [i]->byref)
5658 if (!object_array_klass) {
5661 klass = mono_array_class_get (mono_defaults.object_class, 1);
5664 mono_memory_barrier ();
5665 object_array_klass = klass;
5668 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5669 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5672 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5674 for (i = 0, j = 0; i < sig->param_count; i++) {
5675 if (sig->params [i]->byref) {
5677 arg = mono_array_get (msg->args, gpointer, i);
5678 mono_array_setref (*out_args, j, arg);
5687 * mono_print_unhandled_exception:
5688 * @exc: The exception
5690 * Prints the unhandled exception.
5693 mono_print_unhandled_exception (MonoObject *exc)
5696 char *message = (char *) "";
5700 gboolean free_message = FALSE;
5702 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5703 klass = exc->vtable->klass;
5705 while (klass && method == NULL) {
5706 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5708 klass = klass->parent;
5713 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5715 message = mono_string_to_utf8_checked (str, &error);
5716 if (!mono_error_ok (&error)) {
5717 mono_error_cleanup (&error);
5718 message = (char *)"";
5720 free_message = TRUE;
5726 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5727 * exc->vtable->klass->name, message);
5729 g_printerr ("\nUnhandled Exception: %s\n", message);
5736 * mono_delegate_ctor:
5737 * @this: pointer to an uninitialized delegate object
5738 * @target: target object
5739 * @addr: pointer to native code
5742 * Initialize a delegate and sets a specific method, not the one
5743 * associated with addr. This is useful when sharing generic code.
5744 * In that case addr will most probably not be associated with the
5745 * correct instantiation of the method.
5748 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5750 MonoDelegate *delegate = (MonoDelegate *)this;
5757 delegate->method = method;
5759 class = this->vtable->klass;
5760 mono_stats.delegate_creations++;
5762 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5764 method = mono_marshal_get_remoting_invoke (method);
5765 delegate->method_ptr = mono_compile_method (method);
5766 MONO_OBJECT_SETREF (delegate, target, target);
5767 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5768 method = mono_marshal_get_unbox_wrapper (method);
5769 delegate->method_ptr = mono_compile_method (method);
5770 MONO_OBJECT_SETREF (delegate, target, target);
5772 delegate->method_ptr = addr;
5773 MONO_OBJECT_SETREF (delegate, target, target);
5776 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5780 * mono_delegate_ctor:
5781 * @this: pointer to an uninitialized delegate object
5782 * @target: target object
5783 * @addr: pointer to native code
5785 * This is used to initialize a delegate.
5788 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5790 MonoDomain *domain = mono_domain_get ();
5792 MonoMethod *method = NULL;
5796 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5797 method = ji->method;
5798 g_assert (!method->klass->generic_container);
5801 mono_delegate_ctor_with_method (this, target, addr, method);
5805 * mono_method_call_message_new:
5806 * @method: method to encapsulate
5807 * @params: parameters to the method
5808 * @invoke: optional, delegate invoke.
5809 * @cb: async callback delegate.
5810 * @state: state passed to the async callback.
5812 * Translates arguments pointers into a MonoMethodMessage.
5815 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5816 MonoDelegate **cb, MonoObject **state)
5818 MonoDomain *domain = mono_domain_get ();
5819 MonoMethodSignature *sig = mono_method_signature (method);
5820 MonoMethodMessage *msg;
5823 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5826 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5827 count = sig->param_count - 2;
5829 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5830 count = sig->param_count;
5833 for (i = 0; i < count; i++) {
5838 if (sig->params [i]->byref)
5839 vpos = *((gpointer *)params [i]);
5843 type = sig->params [i]->type;
5844 class = mono_class_from_mono_type (sig->params [i]);
5846 if (class->valuetype)
5847 arg = mono_value_box (domain, class, vpos);
5849 arg = *((MonoObject **)vpos);
5851 mono_array_setref (msg->args, i, arg);
5854 if (cb != NULL && state != NULL) {
5855 *cb = *((MonoDelegate **)params [i]);
5857 *state = *((MonoObject **)params [i]);
5864 * mono_method_return_message_restore:
5866 * Restore results from message based processing back to arguments pointers
5869 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5871 MonoMethodSignature *sig = mono_method_signature (method);
5872 int i, j, type, size, out_len;
5874 if (out_args == NULL)
5876 out_len = mono_array_length (out_args);
5880 for (i = 0, j = 0; i < sig->param_count; i++) {
5881 MonoType *pt = sig->params [i];
5886 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5888 arg = mono_array_get (out_args, gpointer, j);
5891 g_assert (type != MONO_TYPE_VOID);
5893 if (MONO_TYPE_IS_REFERENCE (pt)) {
5894 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5897 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5898 size = mono_class_value_size (class, NULL);
5899 if (class->has_references)
5900 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5902 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5904 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5905 memset (*((gpointer *)params [i]), 0, size);
5915 * mono_load_remote_field:
5916 * @this: pointer to an object
5917 * @klass: klass of the object containing @field
5918 * @field: the field to load
5919 * @res: a storage to store the result
5921 * This method is called by the runtime on attempts to load fields of
5922 * transparent proxy objects. @this points to such TP, @klass is the class of
5923 * the object containing @field. @res is a storage location which can be
5924 * used to store the result.
5926 * Returns: an address pointing to the value of field.
5929 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5931 static MonoMethod *getter = NULL;
5932 MonoDomain *domain = mono_domain_get ();
5933 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5934 MonoClass *field_class;
5935 MonoMethodMessage *msg;
5936 MonoArray *out_args;
5940 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5941 g_assert (res != NULL);
5943 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5944 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5949 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5953 field_class = mono_class_from_mono_type (field->type);
5955 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5956 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5957 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5959 full_name = mono_type_get_full_name (klass);
5960 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5961 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5964 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5966 if (exc) mono_raise_exception ((MonoException *)exc);
5968 if (mono_array_length (out_args) == 0)
5971 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5973 if (field_class->valuetype) {
5974 return ((char *)*res) + sizeof (MonoObject);
5980 * mono_load_remote_field_new:
5985 * Missing documentation.
5988 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5990 static MonoMethod *getter = NULL;
5991 MonoDomain *domain = mono_domain_get ();
5992 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5993 MonoClass *field_class;
5994 MonoMethodMessage *msg;
5995 MonoArray *out_args;
5996 MonoObject *exc, *res;
5999 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6001 field_class = mono_class_from_mono_type (field->type);
6003 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6005 if (field_class->valuetype) {
6006 res = mono_object_new (domain, field_class);
6007 val = ((gchar *) res) + sizeof (MonoObject);
6011 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6016 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6020 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6021 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6023 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6025 full_name = mono_type_get_full_name (klass);
6026 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6027 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6030 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6032 if (exc) mono_raise_exception ((MonoException *)exc);
6034 if (mono_array_length (out_args) == 0)
6037 res = mono_array_get (out_args, MonoObject *, 0);
6043 * mono_store_remote_field:
6044 * @this: pointer to an object
6045 * @klass: klass of the object containing @field
6046 * @field: the field to load
6047 * @val: the value/object to store
6049 * This method is called by the runtime on attempts to store fields of
6050 * transparent proxy objects. @this points to such TP, @klass is the class of
6051 * the object containing @field. @val is the new value to store in @field.
6054 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6056 static MonoMethod *setter = NULL;
6057 MonoDomain *domain = mono_domain_get ();
6058 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6059 MonoClass *field_class;
6060 MonoMethodMessage *msg;
6061 MonoArray *out_args;
6066 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6068 field_class = mono_class_from_mono_type (field->type);
6070 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6071 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6072 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6077 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6081 if (field_class->valuetype)
6082 arg = mono_value_box (domain, field_class, val);
6084 arg = *((MonoObject **)val);
6087 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6088 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6090 full_name = mono_type_get_full_name (klass);
6091 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6092 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6093 mono_array_setref (msg->args, 2, arg);
6096 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6098 if (exc) mono_raise_exception ((MonoException *)exc);
6102 * mono_store_remote_field_new:
6108 * Missing documentation
6111 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6113 static MonoMethod *setter = NULL;
6114 MonoDomain *domain = mono_domain_get ();
6115 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6116 MonoClass *field_class;
6117 MonoMethodMessage *msg;
6118 MonoArray *out_args;
6122 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6124 field_class = mono_class_from_mono_type (field->type);
6126 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6127 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6128 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6133 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6137 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6138 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6140 full_name = mono_type_get_full_name (klass);
6141 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6142 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6143 mono_array_setref (msg->args, 2, arg);
6146 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6148 if (exc) mono_raise_exception ((MonoException *)exc);
6152 * mono_create_ftnptr:
6154 * Given a function address, create a function descriptor for it.
6155 * This is only needed on some platforms.
6158 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6160 return callbacks.create_ftnptr (domain, addr);
6164 * mono_get_addr_from_ftnptr:
6166 * Given a pointer to a function descriptor, return the function address.
6167 * This is only needed on some platforms.
6170 mono_get_addr_from_ftnptr (gpointer descr)
6172 return callbacks.get_addr_from_ftnptr (descr);
6177 * mono_string_chars:
6180 * Returns a pointer to the UCS16 characters stored in the MonoString
6183 mono_string_chars(MonoString *s)
6185 /* This method is here only for documentation extraction, this is a macro */
6189 * mono_string_length:
6192 * Returns the lenght in characters of the string
6195 mono_string_length (MonoString *s)
6197 /* This method is here only for documentation extraction, this is a macro */