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_failed) {
289 mono_type_initialization_unlock ();
291 /* The type initialization already failed once, rethrow the same exception */
293 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
294 return get_type_init_exception_for_vtable (vtable);
296 lock = g_hash_table_lookup (type_initialization_hash, vtable);
298 /* This thread will get to do the initialization */
299 if (mono_domain_get () != domain) {
300 /* Transfer into the target domain */
301 last_domain = mono_domain_get ();
302 if (!mono_domain_set (domain, FALSE)) {
303 vtable->initialized = 1;
304 mono_type_initialization_unlock ();
306 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
307 return mono_get_exception_appdomain_unloaded ();
310 lock = g_malloc (sizeof(TypeInitializationLock));
311 InitializeCriticalSection (&lock->initialization_section);
312 lock->initializing_tid = tid;
313 lock->waiting_count = 1;
315 /* grab the vtable lock while this thread still owns type_initialization_section */
316 EnterCriticalSection (&lock->initialization_section);
317 g_hash_table_insert (type_initialization_hash, vtable, lock);
318 do_initialization = 1;
321 TypeInitializationLock *pending_lock;
323 if (lock->initializing_tid == tid || lock->done) {
324 mono_type_initialization_unlock ();
327 /* see if the thread doing the initialization is already blocked on this thread */
328 blocked = GUINT_TO_POINTER (lock->initializing_tid);
329 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
330 if (pending_lock->initializing_tid == tid) {
331 if (!pending_lock->done) {
332 mono_type_initialization_unlock ();
335 /* the thread doing the initialization is blocked on this thread,
336 but on a lock that has already been freed. It just hasn't got
341 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
343 ++lock->waiting_count;
344 /* record the fact that we are waiting on the initializing thread */
345 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
347 mono_type_initialization_unlock ();
349 if (do_initialization) {
350 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
352 /* If the initialization failed, mark the class as unusable. */
353 /* Avoid infinite loops */
355 (klass->image == mono_defaults.corlib &&
356 !strcmp (klass->name_space, "System") &&
357 !strcmp (klass->name, "TypeInitializationException")))) {
358 vtable->init_failed = 1;
360 if (klass->name_space && *klass->name_space)
361 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
363 full_name = g_strdup (klass->name);
364 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
368 * Store the exception object so it could be thrown on subsequent
371 mono_domain_lock (domain);
372 if (!domain->type_init_exception_hash)
373 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
374 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
375 mono_domain_unlock (domain);
379 mono_domain_set (last_domain, TRUE);
381 LeaveCriticalSection (&lock->initialization_section);
383 /* this just blocks until the initializing thread is done */
384 EnterCriticalSection (&lock->initialization_section);
385 LeaveCriticalSection (&lock->initialization_section);
388 mono_type_initialization_lock ();
389 if (lock->initializing_tid != tid)
390 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
391 --lock->waiting_count;
392 if (lock->waiting_count == 0) {
393 DeleteCriticalSection (&lock->initialization_section);
394 g_hash_table_remove (type_initialization_hash, vtable);
397 if (!vtable->init_failed)
398 vtable->initialized = 1;
399 mono_type_initialization_unlock ();
401 if (vtable->init_failed) {
402 /* Either we were the initializing thread or we waited for the initialization */
404 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
405 return get_type_init_exception_for_vtable (vtable);
408 vtable->initialized = 1;
415 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
417 MonoVTable *vtable = (MonoVTable*)key;
419 TypeInitializationLock *lock = (TypeInitializationLock*) value;
420 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
423 * Have to set this since it cannot be set by the normal code in
424 * mono_runtime_class_init (). In this case, the exception object is not stored,
425 * and get_type_init_exception_for_class () needs to be aware of this.
427 vtable->init_failed = 1;
428 LeaveCriticalSection (&lock->initialization_section);
429 --lock->waiting_count;
430 if (lock->waiting_count == 0) {
431 DeleteCriticalSection (&lock->initialization_section);
440 mono_release_type_locks (MonoInternalThread *thread)
442 mono_type_initialization_lock ();
443 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
444 mono_type_initialization_unlock ();
448 default_trampoline (MonoMethod *method)
454 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
456 g_assert_not_reached ();
462 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
464 g_error ("remoting not installed");
469 default_delegate_trampoline (MonoClass *klass)
471 g_assert_not_reached ();
475 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
476 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
477 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
478 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
479 static MonoImtThunkBuilder imt_thunk_builder = NULL;
480 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
481 #if (MONO_IMT_SIZE > 32)
482 #error "MONO_IMT_SIZE cannot be larger than 32"
486 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
488 memcpy (&callbacks, cbs, sizeof (*cbs));
491 MonoRuntimeCallbacks*
492 mono_get_runtime_callbacks (void)
498 mono_install_trampoline (MonoTrampoline func)
500 arch_create_jit_trampoline = func? func: default_trampoline;
504 mono_install_jump_trampoline (MonoJumpTrampoline func)
506 arch_create_jump_trampoline = func? func: default_jump_trampoline;
510 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
512 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
516 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
518 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
522 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
523 imt_thunk_builder = func;
526 static MonoCompileFunc default_mono_compile_method = NULL;
529 * mono_install_compile_method:
530 * @func: function to install
532 * This is a VM internal routine
535 mono_install_compile_method (MonoCompileFunc func)
537 default_mono_compile_method = func;
541 * mono_compile_method:
542 * @method: The method to compile.
544 * This JIT-compiles the method, and returns the pointer to the native code
548 mono_compile_method (MonoMethod *method)
550 if (!default_mono_compile_method) {
551 g_error ("compile method called on uninitialized runtime");
554 return default_mono_compile_method (method);
558 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
560 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
564 mono_runtime_create_delegate_trampoline (MonoClass *klass)
566 return arch_create_delegate_trampoline (klass);
569 static MonoFreeMethodFunc default_mono_free_method = NULL;
572 * mono_install_free_method:
573 * @func: pointer to the MonoFreeMethodFunc used to release a method
575 * This is an internal VM routine, it is used for the engines to
576 * register a handler to release the resources associated with a method.
578 * Methods are freed when no more references to the delegate that holds
582 mono_install_free_method (MonoFreeMethodFunc func)
584 default_mono_free_method = func;
588 * mono_runtime_free_method:
589 * @domain; domain where the method is hosted
590 * @method: method to release
592 * This routine is invoked to free the resources associated with
593 * a method that has been JIT compiled. This is used to discard
594 * methods that were used only temporarily (for example, used in marshalling)
598 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
600 if (default_mono_free_method != NULL)
601 default_mono_free_method (domain, method);
603 mono_method_clear_object (domain, method);
605 mono_free_method (method);
609 * The vtables in the root appdomain are assumed to be reachable by other
610 * roots, and we don't use typed allocation in the other domains.
613 /* The sync block is no longer a GC pointer */
614 #define GC_HEADER_BITMAP (0)
616 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
619 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
621 MonoClassField *field;
627 max_size = mono_class_data_size (class) / sizeof (gpointer);
629 max_size = class->instance_size / sizeof (gpointer);
630 if (max_size > size) {
631 g_assert (offset <= 0);
632 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
636 for (p = class; p != NULL; p = p->parent) {
637 gpointer iter = NULL;
638 while ((field = mono_class_get_fields (p, &iter))) {
642 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
644 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
647 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
650 /* FIXME: should not happen, flag as type load error */
651 if (field->type->byref)
654 if (static_fields && field->offset == -1)
658 pos = field->offset / sizeof (gpointer);
661 type = mono_type_get_underlying_type (field->type);
662 switch (type->type) {
665 case MONO_TYPE_FNPTR:
667 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
672 if (class->image != mono_defaults.corlib)
675 case MONO_TYPE_STRING:
676 case MONO_TYPE_SZARRAY:
677 case MONO_TYPE_CLASS:
678 case MONO_TYPE_OBJECT:
679 case MONO_TYPE_ARRAY:
680 g_assert ((field->offset % sizeof(gpointer)) == 0);
682 g_assert (pos < size || pos <= max_size);
683 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
684 *max_set = MAX (*max_set, pos);
686 case MONO_TYPE_GENERICINST:
687 if (!mono_type_generic_inst_is_valuetype (type)) {
688 g_assert ((field->offset % sizeof(gpointer)) == 0);
690 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
691 *max_set = MAX (*max_set, pos);
696 case MONO_TYPE_VALUETYPE: {
697 MonoClass *fclass = mono_class_from_mono_type (field->type);
698 if (fclass->has_references) {
699 /* remove the object header */
700 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
714 case MONO_TYPE_BOOLEAN:
718 g_assert_not_reached ();
730 * similar to the above, but sets the bits in the bitmap for any non-ref field
731 * and ignores static fields
734 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
736 MonoClassField *field;
741 max_size = class->instance_size / sizeof (gpointer);
742 if (max_size >= size) {
743 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
746 for (p = class; p != NULL; p = p->parent) {
747 gpointer iter = NULL;
748 while ((field = mono_class_get_fields (p, &iter))) {
751 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
753 /* FIXME: should not happen, flag as type load error */
754 if (field->type->byref)
757 pos = field->offset / sizeof (gpointer);
760 type = mono_type_get_underlying_type (field->type);
761 switch (type->type) {
762 #if SIZEOF_VOID_P == 8
766 case MONO_TYPE_FNPTR:
771 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
772 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
773 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
776 #if SIZEOF_VOID_P == 4
780 case MONO_TYPE_FNPTR:
785 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
786 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
787 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
793 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
794 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
795 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
798 case MONO_TYPE_BOOLEAN:
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
803 case MONO_TYPE_STRING:
804 case MONO_TYPE_SZARRAY:
805 case MONO_TYPE_CLASS:
806 case MONO_TYPE_OBJECT:
807 case MONO_TYPE_ARRAY:
809 case MONO_TYPE_GENERICINST:
810 if (!mono_type_generic_inst_is_valuetype (type)) {
815 case MONO_TYPE_VALUETYPE: {
816 MonoClass *fclass = mono_class_from_mono_type (field->type);
817 /* remove the object header */
818 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
822 g_assert_not_reached ();
831 * mono_class_insecure_overlapping:
832 * check if a class with explicit layout has references and non-references
833 * fields overlapping.
835 * Returns: TRUE if it is insecure to load the type.
838 mono_class_insecure_overlapping (MonoClass *klass)
842 gsize default_bitmap [4] = {0};
844 gsize default_nrbitmap [4] = {0};
845 int i, insecure = FALSE;
848 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
849 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
851 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
852 int idx = i % (sizeof (bitmap [0]) * 8);
853 if (bitmap [idx] & nrbitmap [idx]) {
858 if (bitmap != default_bitmap)
860 if (nrbitmap != default_nrbitmap)
863 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
871 mono_string_alloc (int length)
873 return mono_string_new_size (mono_domain_get (), length);
877 mono_class_compute_gc_descriptor (MonoClass *class)
881 gsize default_bitmap [4] = {0};
882 static gboolean gcj_inited = FALSE;
887 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
888 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
889 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
890 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
892 #ifdef HAVE_GC_GCJ_MALLOC
894 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
898 #ifdef GC_REDIRECT_TO_LOCAL
899 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
900 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
902 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
903 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
908 mono_loader_unlock ();
912 mono_class_init (class);
914 if (class->gc_descr_inited)
917 class->gc_descr_inited = TRUE;
918 class->gc_descr = GC_NO_DESCRIPTOR;
920 bitmap = default_bitmap;
921 if (class == mono_defaults.string_class) {
922 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
923 } else if (class->rank) {
924 mono_class_compute_gc_descriptor (class->element_class);
925 if (!class->element_class->valuetype) {
927 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
928 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
929 class->name_space, class->name);*/
931 /* remove the object header */
932 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
933 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
934 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
935 class->name_space, class->name);*/
936 if (bitmap != default_bitmap)
940 /*static int count = 0;
943 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
944 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
946 if (class->gc_descr == GC_NO_DESCRIPTOR)
947 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
949 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
950 if (bitmap != default_bitmap)
956 * field_is_special_static:
957 * @fklass: The MonoClass to look up.
958 * @field: The MonoClassField describing the field.
960 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
961 * SPECIAL_STATIC_NONE otherwise.
964 field_is_special_static (MonoClass *fklass, MonoClassField *field)
966 MonoCustomAttrInfo *ainfo;
968 ainfo = mono_custom_attrs_from_field (fklass, field);
971 for (i = 0; i < ainfo->num_attrs; ++i) {
972 MonoClass *klass = ainfo->attrs [i].ctor->klass;
973 if (klass->image == mono_defaults.corlib) {
974 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
975 mono_custom_attrs_free (ainfo);
976 return SPECIAL_STATIC_THREAD;
978 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
979 mono_custom_attrs_free (ainfo);
980 return SPECIAL_STATIC_CONTEXT;
984 mono_custom_attrs_free (ainfo);
985 return SPECIAL_STATIC_NONE;
988 static gpointer imt_trampoline = NULL;
991 mono_install_imt_trampoline (gpointer tramp_code)
993 imt_trampoline = tramp_code;
996 static gpointer vtable_trampoline = NULL;
999 mono_install_vtable_trampoline (gpointer tramp_code)
1001 vtable_trampoline = tramp_code;
1004 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1005 #define mix(a,b,c) { \
1006 a -= c; a ^= rot(c, 4); c += b; \
1007 b -= a; b ^= rot(a, 6); a += c; \
1008 c -= b; c ^= rot(b, 8); b += a; \
1009 a -= c; a ^= rot(c,16); c += b; \
1010 b -= a; b ^= rot(a,19); a += c; \
1011 c -= b; c ^= rot(b, 4); b += a; \
1013 #define final(a,b,c) { \
1014 c ^= b; c -= rot(b,14); \
1015 a ^= c; a -= rot(c,11); \
1016 b ^= a; b -= rot(a,25); \
1017 c ^= b; c -= rot(b,16); \
1018 a ^= c; a -= rot(c,4); \
1019 b ^= a; b -= rot(a,14); \
1020 c ^= b; c -= rot(b,24); \
1024 mono_method_get_imt_slot (MonoMethod *method)
1026 MonoMethodSignature *sig;
1028 guint32 *hashes_start, *hashes;
1032 /* This can be used to stress tests the collision code */
1036 * We do this to simplify generic sharing. It will hurt
1037 * performance in cases where a class implements two different
1038 * instantiations of the same generic interface.
1039 * The code in build_imt_slots () depends on this.
1041 if (method->is_inflated)
1042 method = ((MonoMethodInflated*)method)->declaring;
1044 sig = mono_method_signature (method);
1045 hashes_count = sig->param_count + 4;
1046 hashes_start = malloc (hashes_count * sizeof (guint32));
1047 hashes = hashes_start;
1049 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1050 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1051 method->klass->name_space, method->klass->name, method->name);
1052 g_assert_not_reached ();
1055 /* Initialize hashes */
1056 hashes [0] = g_str_hash (method->klass->name);
1057 hashes [1] = g_str_hash (method->klass->name_space);
1058 hashes [2] = g_str_hash (method->name);
1059 hashes [3] = mono_metadata_type_hash (sig->ret);
1060 for (i = 0; i < sig->param_count; i++) {
1061 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1064 /* Setup internal state */
1065 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1067 /* Handle most of the hashes */
1068 while (hashes_count > 3) {
1077 /* Handle the last 3 hashes (all the case statements fall through) */
1078 switch (hashes_count) {
1079 case 3 : c += hashes [2];
1080 case 2 : b += hashes [1];
1081 case 1 : a += hashes [0];
1083 case 0: /* nothing left to add */
1087 free (hashes_start);
1088 /* Report the result */
1089 return c % MONO_IMT_SIZE;
1098 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1099 guint32 imt_slot = mono_method_get_imt_slot (method);
1100 MonoImtBuilderEntry *entry;
1102 if (slot_num >= 0 && imt_slot != slot_num) {
1103 /* we build just a single imt slot and this is not it */
1107 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1108 entry->key = method;
1109 entry->value.vtable_slot = vtable_slot;
1110 entry->next = imt_builder [imt_slot];
1111 if (imt_builder [imt_slot] != NULL) {
1112 entry->children = imt_builder [imt_slot]->children + 1;
1113 if (entry->children == 1) {
1114 mono_stats.imt_slots_with_collisions++;
1115 *imt_collisions_bitmap |= (1 << imt_slot);
1118 entry->children = 0;
1119 mono_stats.imt_used_slots++;
1121 imt_builder [imt_slot] = entry;
1123 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1124 method, method->klass->name_space, method->klass->name,
1125 method->name, imt_slot, vtable_slot, entry->children);
1131 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1133 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1137 e->method->klass->name_space,
1138 e->method->klass->name,
1141 printf (" * %s: NULL\n", message);
1147 compare_imt_builder_entries (const void *p1, const void *p2) {
1148 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1149 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1151 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1155 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1157 int count = end - start;
1158 int chunk_start = out_array->len;
1161 for (i = start; i < end; ++i) {
1162 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1163 item->key = sorted_array [i]->key;
1164 item->value = sorted_array [i]->value;
1165 item->has_target_code = sorted_array [i]->has_target_code;
1166 item->is_equals = TRUE;
1168 item->check_target_idx = out_array->len + 1;
1170 item->check_target_idx = 0;
1171 g_ptr_array_add (out_array, item);
1174 int middle = start + count / 2;
1175 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1177 item->key = sorted_array [middle]->key;
1178 item->is_equals = FALSE;
1179 g_ptr_array_add (out_array, item);
1180 imt_emit_ir (sorted_array, start, middle, out_array);
1181 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1187 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1188 int number_of_entries = entries->children + 1;
1189 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1190 GPtrArray *result = g_ptr_array_new ();
1191 MonoImtBuilderEntry *current_entry;
1194 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1195 sorted_array [i] = current_entry;
1197 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1199 /*for (i = 0; i < number_of_entries; i++) {
1200 print_imt_entry (" sorted array:", sorted_array [i], i);
1203 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1205 free (sorted_array);
1210 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1212 if (imt_builder_entry != NULL) {
1213 if (imt_builder_entry->children == 0 && !fail_tramp) {
1214 /* No collision, return the vtable slot contents */
1215 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1217 /* Collision, build the thunk */
1218 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1221 result = imt_thunk_builder (vtable, domain,
1222 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1223 for (i = 0; i < imt_ir->len; ++i)
1224 g_free (g_ptr_array_index (imt_ir, i));
1225 g_ptr_array_free (imt_ir, TRUE);
1237 static MonoImtBuilderEntry*
1238 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1241 * LOCKING: requires the loader and domain locks.
1245 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1249 guint32 imt_collisions_bitmap = 0;
1250 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1251 int method_count = 0;
1252 gboolean record_method_count_for_max_collisions = FALSE;
1253 gboolean has_generic_virtual = FALSE;
1256 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1258 for (i = 0; i < klass->interface_offsets_count; ++i) {
1259 MonoClass *iface = klass->interfaces_packed [i];
1260 int interface_offset = klass->interface_offsets_packed [i];
1261 int method_slot_in_interface;
1262 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1265 if (slot_num >= 0 && iface->is_inflated) {
1267 * The imt slot of the method is the same as for its declaring method,
1268 * see the comment in mono_method_get_imt_slot (), so we can
1269 * avoid inflating methods which will be discarded by
1270 * add_imt_builder_entry anyway.
1272 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1273 if (mono_method_get_imt_slot (method) != slot_num)
1276 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1277 if (method->is_generic) {
1278 has_generic_virtual = TRUE;
1281 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1284 if (extra_interfaces) {
1285 int interface_offset = klass->vtable_size;
1287 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1288 MonoClass* iface = list_item->data;
1289 int method_slot_in_interface;
1290 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1291 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1292 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1294 interface_offset += iface->method.count;
1297 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1298 /* overwrite the imt slot only if we're building all the entries or if
1299 * we're building this specific one
1301 if (slot_num < 0 || i == slot_num) {
1302 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1305 if (imt_builder [i]) {
1306 MonoImtBuilderEntry *entry;
1308 /* Link entries with imt_builder [i] */
1309 for (entry = entries; entry->next; entry = entry->next)
1311 entry->next = imt_builder [i];
1312 entries->children += imt_builder [i]->children + 1;
1314 imt_builder [i] = entries;
1317 if (has_generic_virtual) {
1319 * There might be collisions later when the the thunk is expanded.
1321 imt_collisions_bitmap |= (1 << i);
1324 * The IMT thunk might be called with an instance of one of the
1325 * generic virtual methods, so has to fallback to the IMT trampoline.
1327 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1329 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1333 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1335 if (imt_builder [i] != NULL) {
1336 int methods_in_slot = imt_builder [i]->children + 1;
1337 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1338 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1339 record_method_count_for_max_collisions = TRUE;
1341 method_count += methods_in_slot;
1345 mono_stats.imt_number_of_methods += method_count;
1346 if (record_method_count_for_max_collisions) {
1347 mono_stats.imt_method_count_when_max_collisions = method_count;
1350 for (i = 0; i < MONO_IMT_SIZE; i++) {
1351 MonoImtBuilderEntry* entry = imt_builder [i];
1352 while (entry != NULL) {
1353 MonoImtBuilderEntry* next = entry->next;
1359 /* we OR the bitmap since we may build just a single imt slot at a time */
1360 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1364 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1365 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1369 * mono_vtable_build_imt_slot:
1370 * @vtable: virtual object table struct
1371 * @imt_slot: slot in the IMT table
1373 * Fill the given @imt_slot in the IMT table of @vtable with
1374 * a trampoline or a thunk for the case of collisions.
1375 * This is part of the internal mono API.
1377 * LOCKING: Take the domain lock.
1380 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1382 gpointer *imt = (gpointer*)vtable;
1383 imt -= MONO_IMT_SIZE;
1384 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1386 /* no support for extra interfaces: the proxy objects will need
1387 * to build the complete IMT
1388 * Update and heck needs to ahppen inside the proper domain lock, as all
1389 * the changes made to a MonoVTable.
1391 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1392 mono_domain_lock (vtable->domain);
1393 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1394 if (imt [imt_slot] == imt_trampoline)
1395 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1396 mono_domain_unlock (vtable->domain);
1397 mono_loader_unlock ();
1402 * The first two free list entries both belong to the wait list: The
1403 * first entry is the pointer to the head of the list and the second
1404 * entry points to the last element. That way appending and removing
1405 * the first element are both O(1) operations.
1407 #define NUM_FREE_LISTS 12
1408 #define FIRST_FREE_LIST_SIZE 64
1409 #define MAX_WAIT_LENGTH 50
1410 #define THUNK_THRESHOLD 10
1413 * LOCKING: The domain lock must be held.
1416 init_thunk_free_lists (MonoDomain *domain)
1418 if (domain->thunk_free_lists)
1420 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1424 list_index_for_size (int item_size)
1427 int size = FIRST_FREE_LIST_SIZE;
1429 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1438 * mono_method_alloc_generic_virtual_thunk:
1440 * @size: size in bytes
1442 * Allocs size bytes to be used for the code of a generic virtual
1443 * thunk. It's either allocated from the domain's code manager or
1444 * reused from a previously invalidated piece.
1446 * LOCKING: The domain lock must be held.
1449 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1451 static gboolean inited = FALSE;
1452 static int generic_virtual_thunks_size = 0;
1456 MonoThunkFreeList **l;
1458 init_thunk_free_lists (domain);
1460 size += sizeof (guint32);
1461 if (size < sizeof (MonoThunkFreeList))
1462 size = sizeof (MonoThunkFreeList);
1464 i = list_index_for_size (size);
1465 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1466 if ((*l)->size >= size) {
1467 MonoThunkFreeList *item = *l;
1469 return ((guint32*)item) + 1;
1473 /* no suitable item found - search lists of larger sizes */
1474 while (++i < NUM_FREE_LISTS) {
1475 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1478 g_assert (item->size > size);
1479 domain->thunk_free_lists [i] = item->next;
1480 return ((guint32*)item) + 1;
1483 /* still nothing found - allocate it */
1485 mono_counters_register ("Generic virtual thunk bytes",
1486 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1489 generic_virtual_thunks_size += size;
1491 p = mono_domain_code_reserve (domain, size);
1498 * LOCKING: The domain lock must be held.
1501 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1504 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1506 init_thunk_free_lists (domain);
1508 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1509 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1510 int length = item->length;
1513 /* unlink the first item from the wait list */
1514 domain->thunk_free_lists [0] = item->next;
1515 domain->thunk_free_lists [0]->length = length - 1;
1517 i = list_index_for_size (item->size);
1519 /* put it in the free list */
1520 item->next = domain->thunk_free_lists [i];
1521 domain->thunk_free_lists [i] = item;
1525 if (domain->thunk_free_lists [1]) {
1526 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1527 domain->thunk_free_lists [0]->length++;
1529 g_assert (!domain->thunk_free_lists [0]);
1531 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1532 domain->thunk_free_lists [0]->length = 1;
1536 typedef struct _GenericVirtualCase {
1540 struct _GenericVirtualCase *next;
1541 } GenericVirtualCase;
1544 * get_generic_virtual_entries:
1546 * Return IMT entries for the generic virtual method instances for vtable slot
1549 static MonoImtBuilderEntry*
1550 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1552 GenericVirtualCase *list;
1553 MonoImtBuilderEntry *entries;
1555 mono_domain_lock (domain);
1556 if (!domain->generic_virtual_cases)
1557 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1559 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1562 for (; list; list = list->next) {
1563 MonoImtBuilderEntry *entry;
1565 if (list->count < THUNK_THRESHOLD)
1568 entry = g_new0 (MonoImtBuilderEntry, 1);
1569 entry->key = list->method;
1570 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1571 entry->has_target_code = 1;
1573 entry->children = entries->children + 1;
1574 entry->next = entries;
1578 mono_domain_unlock (domain);
1580 /* FIXME: Leaking memory ? */
1585 * mono_method_add_generic_virtual_invocation:
1587 * @vtable_slot: pointer to the vtable slot
1588 * @method: the inflated generic virtual method
1589 * @code: the method's code
1591 * Registers a call via unmanaged code to a generic virtual method
1592 * instantiation. If the number of calls reaches a threshold
1593 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1594 * virtual method thunk.
1597 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1598 gpointer *vtable_slot,
1599 MonoMethod *method, gpointer code)
1601 static gboolean inited = FALSE;
1602 static int num_added = 0;
1604 GenericVirtualCase *gvc, *list;
1605 MonoImtBuilderEntry *entries;
1609 mono_domain_lock (domain);
1610 if (!domain->generic_virtual_cases)
1611 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1613 /* Check whether the case was already added */
1614 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1617 if (gvc->method == method)
1622 /* If not found, make a new one */
1624 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1625 gvc->method = method;
1628 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1630 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1633 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1639 if (++gvc->count == THUNK_THRESHOLD) {
1640 gpointer *old_thunk = *vtable_slot;
1642 if ((gpointer)vtable_slot < (gpointer)vtable)
1643 /* Force the rebuild of the thunk at the next call */
1644 *vtable_slot = imt_trampoline;
1646 entries = get_generic_virtual_entries (domain, vtable_slot);
1648 sorted = imt_sort_slot_entries (entries);
1650 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1654 MonoImtBuilderEntry *next = entries->next;
1659 for (i = 0; i < sorted->len; ++i)
1660 g_free (g_ptr_array_index (sorted, i));
1661 g_ptr_array_free (sorted, TRUE);
1664 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1665 invalidate_generic_virtual_thunk (domain, old_thunk);
1668 mono_domain_unlock (domain);
1671 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1674 * mono_class_vtable:
1675 * @domain: the application domain
1676 * @class: the class to initialize
1678 * VTables are domain specific because we create domain specific code, and
1679 * they contain the domain specific static class data.
1680 * On failure, NULL is returned, and class->exception_type is set.
1683 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1685 return mono_class_vtable_full (domain, class, FALSE);
1689 * mono_class_vtable_full:
1690 * @domain: the application domain
1691 * @class: the class to initialize
1692 * @raise_on_error if an exception should be raised on failure or not
1694 * VTables are domain specific because we create domain specific code, and
1695 * they contain the domain specific static class data.
1698 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1700 MonoClassRuntimeInfo *runtime_info;
1704 if (class->exception_type) {
1706 mono_raise_exception (mono_class_get_exception_for_failure (class));
1710 /* this check can be inlined in jitted code, too */
1711 runtime_info = class->runtime_info;
1712 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1713 return runtime_info->domain_vtables [domain->domain_id];
1714 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1718 * mono_class_try_get_vtable:
1719 * @domain: the application domain
1720 * @class: the class to initialize
1722 * This function tries to get the associated vtable from @class if
1723 * it was already created.
1726 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1728 MonoClassRuntimeInfo *runtime_info;
1732 runtime_info = class->runtime_info;
1733 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1734 return runtime_info->domain_vtables [domain->domain_id];
1739 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1742 MonoClassRuntimeInfo *runtime_info, *old_info;
1743 MonoClassField *field;
1746 int imt_table_bytes = 0;
1747 guint32 vtable_size, class_size;
1750 gpointer *interface_offsets;
1752 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1753 mono_domain_lock (domain);
1754 runtime_info = class->runtime_info;
1755 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1756 mono_domain_unlock (domain);
1757 mono_loader_unlock ();
1758 return runtime_info->domain_vtables [domain->domain_id];
1760 if (!class->inited || class->exception_type) {
1761 if (!mono_class_init (class) || class->exception_type) {
1762 mono_domain_unlock (domain);
1763 mono_loader_unlock ();
1765 mono_raise_exception (mono_class_get_exception_for_failure (class));
1770 /* Array types require that their element type be valid*/
1771 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1772 MonoClass *element_class = class->element_class;
1773 if (!element_class->inited)
1774 mono_class_init (element_class);
1776 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1777 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1778 mono_class_setup_vtable (element_class);
1780 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1781 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1782 if (class->exception_type == MONO_EXCEPTION_NONE)
1783 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1784 mono_domain_unlock (domain);
1785 mono_loader_unlock ();
1787 mono_raise_exception (mono_class_get_exception_for_failure (class));
1793 * For some classes, mono_class_init () already computed class->vtable_size, and
1794 * that is all that is needed because of the vtable trampolines.
1796 if (!class->vtable_size)
1797 mono_class_setup_vtable (class);
1799 if (class->exception_type) {
1800 mono_domain_unlock (domain);
1801 mono_loader_unlock ();
1803 mono_raise_exception (mono_class_get_exception_for_failure (class));
1808 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1809 if (class->interface_offsets_count) {
1810 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1811 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1812 mono_stats.imt_number_of_tables++;
1813 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1816 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1817 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1820 mono_stats.used_class_count++;
1821 mono_stats.class_vtable_size += vtable_size;
1822 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1825 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1827 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1829 vt->rank = class->rank;
1830 vt->domain = domain;
1832 mono_class_compute_gc_descriptor (class);
1834 * We can't use typed allocation in the non-root domains, since the
1835 * collector needs the GC descriptor stored in the vtable even after
1836 * the mempool containing the vtable is destroyed when the domain is
1837 * unloaded. An alternative might be to allocate vtables in the GC
1838 * heap, but this does not seem to work (it leads to crashes inside
1839 * libgc). If that approach is tried, two gc descriptors need to be
1840 * allocated for each class: one for the root domain, and one for all
1841 * other domains. The second descriptor should contain a bit for the
1842 * vtable field in MonoObject, since we can no longer assume the
1843 * vtable is reachable by other roots after the appdomain is unloaded.
1845 #ifdef HAVE_BOEHM_GC
1846 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1847 vt->gc_descr = GC_NO_DESCRIPTOR;
1850 vt->gc_descr = class->gc_descr;
1852 if ((class_size = mono_class_data_size (class))) {
1853 if (class->has_static_refs) {
1854 gpointer statics_gc_descr;
1856 gsize default_bitmap [4] = {0};
1859 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1860 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1861 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1862 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1863 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1864 if (bitmap != default_bitmap)
1867 vt->data = mono_domain_alloc0 (domain, class_size);
1869 mono_stats.class_static_data_size += class_size;
1874 while ((field = mono_class_get_fields (class, &iter))) {
1875 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1877 if (mono_field_is_deleted (field))
1879 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1880 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1881 if (special_static != SPECIAL_STATIC_NONE) {
1882 guint32 size, offset;
1884 size = mono_type_size (field->type, &align);
1885 offset = mono_alloc_special_static_data (special_static, size, align);
1886 if (!domain->special_static_fields)
1887 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1888 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1890 * This marks the field as special static to speed up the
1891 * checks in mono_field_static_get/set_value ().
1897 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1898 MonoClass *fklass = mono_class_from_mono_type (field->type);
1899 const char *data = mono_field_get_data (field);
1901 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1902 t = (char*)vt->data + field->offset;
1903 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1906 if (fklass->valuetype) {
1907 memcpy (t, data, mono_class_value_size (fklass, NULL));
1909 /* it's a pointer type: add check */
1910 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1917 vt->max_interface_id = class->max_interface_id;
1918 vt->interface_bitmap = class->interface_bitmap;
1920 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1921 // class->name, class->interface_offsets_count);
1923 if (! ARCH_USE_IMT) {
1924 /* initialize interface offsets */
1925 for (i = 0; i < class->interface_offsets_count; ++i) {
1926 int interface_id = class->interfaces_packed [i]->interface_id;
1927 int slot = class->interface_offsets_packed [i];
1928 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1932 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1933 * as we change the code in appdomain.c to invalidate vtables by
1934 * looking at the possible MonoClasses created for the domain.
1936 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1937 /* class->runtime_info is protected by the loader lock, both when
1938 * it it enlarged and when it is stored info.
1941 old_info = class->runtime_info;
1942 if (old_info && old_info->max_domain >= domain->domain_id) {
1943 /* someone already created a large enough runtime info */
1944 mono_memory_barrier ();
1945 old_info->domain_vtables [domain->domain_id] = vt;
1947 int new_size = domain->domain_id;
1949 new_size = MAX (new_size, old_info->max_domain);
1951 /* make the new size a power of two */
1953 while (new_size > i)
1956 /* this is a bounded memory retention issue: may want to
1957 * handle it differently when we'll have a rcu-like system.
1959 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1960 runtime_info->max_domain = new_size - 1;
1961 /* copy the stuff from the older info */
1963 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1965 runtime_info->domain_vtables [domain->domain_id] = vt;
1967 mono_memory_barrier ();
1968 class->runtime_info = runtime_info;
1971 /* Initialize vtable */
1972 if (vtable_trampoline) {
1973 // This also covers the AOT case
1974 for (i = 0; i < class->vtable_size; ++i) {
1975 vt->vtable [i] = vtable_trampoline;
1978 mono_class_setup_vtable (class);
1980 for (i = 0; i < class->vtable_size; ++i) {
1983 if ((cm = class->vtable [i]))
1984 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1988 if (ARCH_USE_IMT && imt_table_bytes) {
1989 /* Now that the vtable is full, we can actually fill up the IMT */
1990 if (imt_trampoline) {
1991 /* lazy construction of the IMT entries enabled */
1992 for (i = 0; i < MONO_IMT_SIZE; ++i)
1993 interface_offsets [i] = imt_trampoline;
1995 build_imt (class, vt, domain, interface_offsets, NULL);
1999 mono_domain_unlock (domain);
2000 mono_loader_unlock ();
2002 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
2003 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2004 mono_raise_exception (mono_class_get_exception_for_failure (class));
2006 /* make sure the parent is initialized */
2007 /*FIXME shouldn't this fail the current type?*/
2009 mono_class_vtable_full (domain, class->parent, raise_on_error);
2011 /*FIXME check for OOM*/
2012 vt->type = mono_type_get_object (domain, &class->byval_arg);
2013 if (class->contextbound)
2022 * mono_class_proxy_vtable:
2023 * @domain: the application domain
2024 * @remove_class: the remote class
2026 * Creates a vtable for transparent proxies. It is basically
2027 * a copy of the real vtable of the class wrapped in @remote_class,
2028 * but all function pointers invoke the remoting functions, and
2029 * vtable->klass points to the transparent proxy class, and not to @class.
2032 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2034 MonoVTable *vt, *pvt;
2035 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2037 GSList *extra_interfaces = NULL;
2038 MonoClass *class = remote_class->proxy_class;
2039 gpointer *interface_offsets;
2041 vt = mono_class_vtable (domain, class);
2042 g_assert (vt); /*FIXME property handle failure*/
2043 max_interface_id = vt->max_interface_id;
2045 /* Calculate vtable space for extra interfaces */
2046 for (j = 0; j < remote_class->interface_count; j++) {
2047 MonoClass* iclass = remote_class->interfaces[j];
2051 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2052 continue; /* interface implemented by the class */
2053 if (g_slist_find (extra_interfaces, iclass))
2056 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2058 method_count = mono_class_num_methods (iclass);
2060 ifaces = mono_class_get_implemented_interfaces (iclass);
2062 for (i = 0; i < ifaces->len; ++i) {
2063 MonoClass *ic = g_ptr_array_index (ifaces, i);
2064 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2065 continue; /* interface implemented by the class */
2066 if (g_slist_find (extra_interfaces, ic))
2068 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2069 method_count += mono_class_num_methods (ic);
2071 g_ptr_array_free (ifaces, TRUE);
2074 extra_interface_vtsize += method_count * sizeof (gpointer);
2075 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2079 mono_stats.imt_number_of_tables++;
2080 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2081 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2082 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2084 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2085 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2088 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2090 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2092 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2094 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2095 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2097 pvt->klass = mono_defaults.transparent_proxy_class;
2098 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2099 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2101 /* initialize vtable */
2102 mono_class_setup_vtable (class);
2103 for (i = 0; i < class->vtable_size; ++i) {
2106 if ((cm = class->vtable [i]))
2107 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2109 pvt->vtable [i] = NULL;
2112 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2113 /* create trampolines for abstract methods */
2114 for (k = class; k; k = k->parent) {
2116 gpointer iter = NULL;
2117 while ((m = mono_class_get_methods (k, &iter)))
2118 if (!pvt->vtable [m->slot])
2119 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2123 pvt->max_interface_id = max_interface_id;
2124 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2126 if (! ARCH_USE_IMT) {
2127 /* initialize interface offsets */
2128 for (i = 0; i < class->interface_offsets_count; ++i) {
2129 int interface_id = class->interfaces_packed [i]->interface_id;
2130 int slot = class->interface_offsets_packed [i];
2131 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2134 for (i = 0; i < class->interface_offsets_count; ++i) {
2135 int interface_id = class->interfaces_packed [i]->interface_id;
2136 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2139 if (extra_interfaces) {
2140 int slot = class->vtable_size;
2146 /* Create trampolines for the methods of the interfaces */
2147 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2148 interf = list_item->data;
2150 if (! ARCH_USE_IMT) {
2151 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2153 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2157 while ((cm = mono_class_get_methods (interf, &iter)))
2158 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2160 slot += mono_class_num_methods (interf);
2162 if (! ARCH_USE_IMT) {
2163 g_slist_free (extra_interfaces);
2168 /* Now that the vtable is full, we can actually fill up the IMT */
2169 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2170 if (extra_interfaces) {
2171 g_slist_free (extra_interfaces);
2179 * mono_class_field_is_special_static:
2181 * Returns whether @field is a thread/context static field.
2184 mono_class_field_is_special_static (MonoClassField *field)
2186 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2188 if (mono_field_is_deleted (field))
2190 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2191 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2198 * mono_class_has_special_static_fields:
2200 * Returns whenever @klass has any thread/context static fields.
2203 mono_class_has_special_static_fields (MonoClass *klass)
2205 MonoClassField *field;
2209 while ((field = mono_class_get_fields (klass, &iter))) {
2210 g_assert (field->parent == klass);
2211 if (mono_class_field_is_special_static (field))
2219 * create_remote_class_key:
2220 * Creates an array of pointers that can be used as a hash key for a remote class.
2221 * The first element of the array is the number of pointers.
2224 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2229 if (remote_class == NULL) {
2230 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2231 key = g_malloc (sizeof(gpointer) * 3);
2232 key [0] = GINT_TO_POINTER (2);
2233 key [1] = mono_defaults.marshalbyrefobject_class;
2234 key [2] = extra_class;
2236 key = g_malloc (sizeof(gpointer) * 2);
2237 key [0] = GINT_TO_POINTER (1);
2238 key [1] = extra_class;
2241 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2242 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2243 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2244 key [1] = remote_class->proxy_class;
2246 // Keep the list of interfaces sorted
2247 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2248 if (extra_class && remote_class->interfaces [i] > extra_class) {
2249 key [j++] = extra_class;
2252 key [j] = remote_class->interfaces [i];
2255 key [j] = extra_class;
2257 // Replace the old class. The interface list is the same
2258 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2259 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2260 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2261 for (i = 0; i < remote_class->interface_count; i++)
2262 key [2 + i] = remote_class->interfaces [i];
2270 * copy_remote_class_key:
2272 * Make a copy of KEY in the domain and return the copy.
2275 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2277 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2278 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2280 memcpy (mp_key, key, key_size);
2286 * mono_remote_class:
2287 * @domain: the application domain
2288 * @class_name: name of the remote class
2290 * Creates and initializes a MonoRemoteClass object for a remote type.
2292 * Can raise an exception on failure.
2295 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2298 MonoRemoteClass *rc;
2299 gpointer* key, *mp_key;
2302 key = create_remote_class_key (NULL, proxy_class);
2304 mono_domain_lock (domain);
2305 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2309 mono_domain_unlock (domain);
2313 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2314 if (!mono_error_ok (&error)) {
2316 mono_domain_unlock (domain);
2317 mono_error_raise_exception (&error);
2320 mp_key = copy_remote_class_key (domain, key);
2324 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2325 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2326 rc->interface_count = 1;
2327 rc->interfaces [0] = proxy_class;
2328 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2330 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2331 rc->interface_count = 0;
2332 rc->proxy_class = proxy_class;
2335 rc->default_vtable = NULL;
2336 rc->xdomain_vtable = NULL;
2337 rc->proxy_class_name = name;
2338 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2340 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2342 mono_domain_unlock (domain);
2347 * clone_remote_class:
2348 * Creates a copy of the remote_class, adding the provided class or interface
2350 static MonoRemoteClass*
2351 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2353 MonoRemoteClass *rc;
2354 gpointer* key, *mp_key;
2356 key = create_remote_class_key (remote_class, extra_class);
2357 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2363 mp_key = copy_remote_class_key (domain, key);
2367 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2369 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2370 rc->proxy_class = remote_class->proxy_class;
2371 rc->interface_count = remote_class->interface_count + 1;
2373 // Keep the list of interfaces sorted, since the hash key of
2374 // the remote class depends on this
2375 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2376 if (remote_class->interfaces [i] > extra_class && i == j)
2377 rc->interfaces [j++] = extra_class;
2378 rc->interfaces [j] = remote_class->interfaces [i];
2381 rc->interfaces [j] = extra_class;
2383 // Replace the old class. The interface array is the same
2384 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2385 rc->proxy_class = extra_class;
2386 rc->interface_count = remote_class->interface_count;
2387 if (rc->interface_count > 0)
2388 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2391 rc->default_vtable = NULL;
2392 rc->xdomain_vtable = NULL;
2393 rc->proxy_class_name = remote_class->proxy_class_name;
2395 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2401 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2403 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2404 mono_domain_lock (domain);
2405 if (rp->target_domain_id != -1) {
2406 if (remote_class->xdomain_vtable == NULL)
2407 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2408 mono_domain_unlock (domain);
2409 mono_loader_unlock ();
2410 return remote_class->xdomain_vtable;
2412 if (remote_class->default_vtable == NULL) {
2415 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2416 klass = mono_class_from_mono_type (type);
2417 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2418 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2420 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2423 mono_domain_unlock (domain);
2424 mono_loader_unlock ();
2425 return remote_class->default_vtable;
2429 * mono_upgrade_remote_class:
2430 * @domain: the application domain
2431 * @tproxy: the proxy whose remote class has to be upgraded.
2432 * @klass: class to which the remote class can be casted.
2434 * Updates the vtable of the remote class by adding the necessary method slots
2435 * and interface offsets so it can be safely casted to klass. klass can be a
2436 * class or an interface.
2439 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2441 MonoTransparentProxy *tproxy;
2442 MonoRemoteClass *remote_class;
2443 gboolean redo_vtable;
2445 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2446 mono_domain_lock (domain);
2448 tproxy = (MonoTransparentProxy*) proxy_object;
2449 remote_class = tproxy->remote_class;
2451 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2454 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2455 if (remote_class->interfaces [i] == klass)
2456 redo_vtable = FALSE;
2459 redo_vtable = (remote_class->proxy_class != klass);
2463 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2464 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2467 mono_domain_unlock (domain);
2468 mono_loader_unlock ();
2473 * mono_object_get_virtual_method:
2474 * @obj: object to operate on.
2477 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2478 * the instance of a callvirt of method.
2481 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2484 MonoMethod **vtable;
2486 MonoMethod *res = NULL;
2488 klass = mono_object_class (obj);
2489 if (klass == mono_defaults.transparent_proxy_class) {
2490 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2496 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2499 mono_class_setup_vtable (klass);
2500 vtable = klass->vtable;
2502 if (method->slot == -1) {
2503 /* method->slot might not be set for instances of generic methods */
2504 if (method->is_inflated) {
2505 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2506 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2509 g_assert_not_reached ();
2513 /* check method->slot is a valid index: perform isinstance? */
2514 if (method->slot != -1) {
2515 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2517 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2519 res = vtable [method->slot];
2524 /* It may be an interface, abstract class method or generic method */
2525 if (!res || mono_method_signature (res)->generic_param_count)
2528 /* generic methods demand invoke_with_check */
2529 if (mono_method_signature (res)->generic_param_count)
2530 res = mono_marshal_get_remoting_invoke_with_check (res);
2533 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2534 res = mono_cominterop_get_invoke (res);
2537 res = mono_marshal_get_remoting_invoke (res);
2540 if (method->is_inflated) {
2541 /* Have to inflate the result */
2542 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2552 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2554 g_error ("runtime invoke called on uninitialized runtime");
2558 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2561 * mono_runtime_invoke:
2562 * @method: method to invoke
2563 * @obJ: object instance
2564 * @params: arguments to the method
2565 * @exc: exception information.
2567 * Invokes the method represented by @method on the object @obj.
2569 * obj is the 'this' pointer, it should be NULL for static
2570 * methods, a MonoObject* for object instances and a pointer to
2571 * the value type for value types.
2573 * The params array contains the arguments to the method with the
2574 * same convention: MonoObject* pointers for object instances and
2575 * pointers to the value type otherwise.
2577 * From unmanaged code you'll usually use the
2578 * mono_runtime_invoke() variant.
2580 * Note that this function doesn't handle virtual methods for
2581 * you, it will exec the exact method you pass: we still need to
2582 * expose a function to lookup the derived class implementation
2583 * of a virtual method (there are examples of this in the code,
2586 * You can pass NULL as the exc argument if you don't want to
2587 * catch exceptions, otherwise, *exc will be set to the exception
2588 * thrown, if any. if an exception is thrown, you can't use the
2589 * MonoObject* result from the function.
2591 * If the method returns a value type, it is boxed in an object
2595 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2599 if (mono_runtime_get_no_exec ())
2600 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2602 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2603 mono_profiler_method_start_invoke (method);
2605 result = default_mono_runtime_invoke (method, obj, params, exc);
2607 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2608 mono_profiler_method_end_invoke (method);
2614 * mono_method_get_unmanaged_thunk:
2615 * @method: method to generate a thunk for.
2617 * Returns an unmanaged->managed thunk that can be used to call
2618 * a managed method directly from C.
2620 * The thunk's C signature closely matches the managed signature:
2622 * C#: public bool Equals (object obj);
2623 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2624 * MonoObject*, MonoException**);
2626 * The 1st ("this") parameter must not be used with static methods:
2628 * C#: public static bool ReferenceEquals (object a, object b);
2629 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2632 * The last argument must be a non-null pointer of a MonoException* pointer.
2633 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2634 * exception has been thrown in managed code. Otherwise it will point
2635 * to the MonoException* caught by the thunk. In this case, the result of
2636 * the thunk is undefined:
2638 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2639 * MonoException *ex = NULL;
2640 * Equals func = mono_method_get_unmanaged_thunk (method);
2641 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2643 * // handle exception
2646 * The calling convention of the thunk matches the platform's default
2647 * convention. This means that under Windows, C declarations must
2648 * contain the __stdcall attribute:
2650 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2651 * MonoObject*, MonoException**);
2655 * Value type arguments and return values are treated as they were objects:
2657 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2658 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2660 * Arguments must be properly boxed upon trunk's invocation, while return
2661 * values must be unboxed.
2664 mono_method_get_unmanaged_thunk (MonoMethod *method)
2666 method = mono_marshal_get_thunk_invoke_wrapper (method);
2667 return mono_compile_method (method);
2671 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2675 /* object fields cannot be byref, so we don't need a
2677 gpointer *p = (gpointer*)dest;
2684 case MONO_TYPE_BOOLEAN:
2686 case MONO_TYPE_U1: {
2687 guint8 *p = (guint8*)dest;
2688 *p = value ? *(guint8*)value : 0;
2693 case MONO_TYPE_CHAR: {
2694 guint16 *p = (guint16*)dest;
2695 *p = value ? *(guint16*)value : 0;
2698 #if SIZEOF_VOID_P == 4
2703 case MONO_TYPE_U4: {
2704 gint32 *p = (gint32*)dest;
2705 *p = value ? *(gint32*)value : 0;
2708 #if SIZEOF_VOID_P == 8
2713 case MONO_TYPE_U8: {
2714 gint64 *p = (gint64*)dest;
2715 *p = value ? *(gint64*)value : 0;
2718 case MONO_TYPE_R4: {
2719 float *p = (float*)dest;
2720 *p = value ? *(float*)value : 0;
2723 case MONO_TYPE_R8: {
2724 double *p = (double*)dest;
2725 *p = value ? *(double*)value : 0;
2728 case MONO_TYPE_STRING:
2729 case MONO_TYPE_SZARRAY:
2730 case MONO_TYPE_CLASS:
2731 case MONO_TYPE_OBJECT:
2732 case MONO_TYPE_ARRAY:
2733 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2735 case MONO_TYPE_FNPTR:
2736 case MONO_TYPE_PTR: {
2737 gpointer *p = (gpointer*)dest;
2738 *p = deref_pointer? *(gpointer*)value: value;
2741 case MONO_TYPE_VALUETYPE:
2742 /* note that 't' and 'type->type' can be different */
2743 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2744 t = mono_class_enum_basetype (type->data.klass)->type;
2747 MonoClass *class = mono_class_from_mono_type (type);
2748 int size = mono_class_value_size (class, NULL);
2750 memset (dest, 0, size);
2752 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2755 case MONO_TYPE_GENERICINST:
2756 t = type->data.generic_class->container_class->byval_arg.type;
2759 g_warning ("got type %x", type->type);
2760 g_assert_not_reached ();
2765 * mono_field_set_value:
2766 * @obj: Instance object
2767 * @field: MonoClassField describing the field to set
2768 * @value: The value to be set
2770 * Sets the value of the field described by @field in the object instance @obj
2771 * to the value passed in @value. This method should only be used for instance
2772 * fields. For static fields, use mono_field_static_set_value.
2774 * The value must be on the native format of the field type.
2777 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2781 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2783 dest = (char*)obj + field->offset;
2784 set_value (field->type, dest, value, FALSE);
2788 * mono_field_static_set_value:
2789 * @field: MonoClassField describing the field to set
2790 * @value: The value to be set
2792 * Sets the value of the static field described by @field
2793 * to the value passed in @value.
2795 * The value must be on the native format of the field type.
2798 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2802 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2803 /* you cant set a constant! */
2804 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2806 if (field->offset == -1) {
2807 /* Special static */
2808 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2809 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2811 dest = (char*)vt->data + field->offset;
2813 set_value (field->type, dest, value, FALSE);
2816 /* Used by the debugger */
2818 mono_vtable_get_static_field_data (MonoVTable *vt)
2824 * mono_field_get_value:
2825 * @obj: Object instance
2826 * @field: MonoClassField describing the field to fetch information from
2827 * @value: pointer to the location where the value will be stored
2829 * Use this routine to get the value of the field @field in the object
2832 * The pointer provided by value must be of the field type, for reference
2833 * types this is a MonoObject*, for value types its the actual pointer to
2838 * mono_field_get_value (obj, int_field, &i);
2841 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2845 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2847 src = (char*)obj + field->offset;
2848 set_value (field->type, value, src, TRUE);
2852 * mono_field_get_value_object:
2853 * @domain: domain where the object will be created (if boxing)
2854 * @field: MonoClassField describing the field to fetch information from
2855 * @obj: The object instance for the field.
2857 * Returns: a new MonoObject with the value from the given field. If the
2858 * field represents a value type, the value is boxed.
2862 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2866 MonoVTable *vtable = NULL;
2868 gboolean is_static = FALSE;
2869 gboolean is_ref = FALSE;
2871 switch (field->type->type) {
2872 case MONO_TYPE_STRING:
2873 case MONO_TYPE_OBJECT:
2874 case MONO_TYPE_CLASS:
2875 case MONO_TYPE_ARRAY:
2876 case MONO_TYPE_SZARRAY:
2881 case MONO_TYPE_BOOLEAN:
2884 case MONO_TYPE_CHAR:
2893 case MONO_TYPE_VALUETYPE:
2894 is_ref = field->type->byref;
2896 case MONO_TYPE_GENERICINST:
2897 is_ref = !field->type->data.generic_class->container_class->valuetype;
2900 g_error ("type 0x%x not handled in "
2901 "mono_field_get_value_object", field->type->type);
2905 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2907 vtable = mono_class_vtable (domain, field->parent);
2909 char *name = mono_type_get_full_name (field->parent);
2910 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2914 if (!vtable->initialized)
2915 mono_runtime_class_init (vtable);
2920 mono_field_static_get_value (vtable, field, &o);
2922 mono_field_get_value (obj, field, &o);
2927 /* boxed value type */
2928 klass = mono_class_from_mono_type (field->type);
2929 o = mono_object_new (domain, klass);
2930 v = ((gchar *) o) + sizeof (MonoObject);
2932 mono_field_static_get_value (vtable, field, v);
2934 mono_field_get_value (obj, field, v);
2941 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2944 const char *p = blob;
2945 mono_metadata_decode_blob_size (p, &p);
2948 case MONO_TYPE_BOOLEAN:
2951 *(guint8 *) value = *p;
2953 case MONO_TYPE_CHAR:
2956 *(guint16*) value = read16 (p);
2960 *(guint32*) value = read32 (p);
2964 *(guint64*) value = read64 (p);
2967 readr4 (p, (float*) value);
2970 readr8 (p, (double*) value);
2972 case MONO_TYPE_STRING:
2973 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2975 case MONO_TYPE_CLASS:
2976 *(gpointer*) value = NULL;
2980 g_warning ("type 0x%02x should not be in constant table", type);
2986 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2988 MonoTypeEnum def_type;
2991 data = mono_class_get_field_default_value (field, &def_type);
2992 mono_get_constant_value_from_blob (domain, def_type, data, value);
2996 * mono_field_static_get_value:
2997 * @vt: vtable to the object
2998 * @field: MonoClassField describing the field to fetch information from
2999 * @value: where the value is returned
3001 * Use this routine to get the value of the static field @field value.
3003 * The pointer provided by value must be of the field type, for reference
3004 * types this is a MonoObject*, for value types its the actual pointer to
3009 * mono_field_static_get_value (vt, int_field, &i);
3012 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3016 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3018 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3019 get_default_field_value (vt->domain, field, value);
3023 if (field->offset == -1) {
3024 /* Special static */
3025 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3026 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3028 src = (char*)vt->data + field->offset;
3030 set_value (field->type, value, src, TRUE);
3034 * mono_property_set_value:
3035 * @prop: MonoProperty to set
3036 * @obj: instance object on which to act
3037 * @params: parameters to pass to the propery
3038 * @exc: optional exception
3040 * Invokes the property's set method with the given arguments on the
3041 * object instance obj (or NULL for static properties).
3043 * You can pass NULL as the exc argument if you don't want to
3044 * catch exceptions, otherwise, *exc will be set to the exception
3045 * thrown, if any. if an exception is thrown, you can't use the
3046 * MonoObject* result from the function.
3049 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3051 default_mono_runtime_invoke (prop->set, obj, params, exc);
3055 * mono_property_get_value:
3056 * @prop: MonoProperty to fetch
3057 * @obj: instance object on which to act
3058 * @params: parameters to pass to the propery
3059 * @exc: optional exception
3061 * Invokes the property's get method with the given arguments on the
3062 * object instance obj (or NULL for static properties).
3064 * You can pass NULL as the exc argument if you don't want to
3065 * catch exceptions, otherwise, *exc will be set to the exception
3066 * thrown, if any. if an exception is thrown, you can't use the
3067 * MonoObject* result from the function.
3069 * Returns: the value from invoking the get method on the property.
3072 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3074 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3078 * mono_nullable_init:
3079 * @buf: The nullable structure to initialize.
3080 * @value: the value to initialize from
3081 * @klass: the type for the object
3083 * Initialize the nullable structure pointed to by @buf from @value which
3084 * should be a boxed value type. The size of @buf should be able to hold
3085 * as much data as the @klass->instance_size (which is the number of bytes
3086 * that will be copies).
3088 * Since Nullables have variable structure, we can not define a C
3089 * structure for them.
3092 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3094 MonoClass *param_class = klass->cast_class;
3096 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3097 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3099 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3101 if (param_class->has_references)
3102 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3104 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3106 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3111 * mono_nullable_box:
3112 * @buf: The buffer representing the data to be boxed
3113 * @klass: the type to box it as.
3115 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3119 mono_nullable_box (guint8 *buf, MonoClass *klass)
3121 MonoClass *param_class = klass->cast_class;
3123 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3124 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3126 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3127 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3128 if (param_class->has_references)
3129 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3131 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3139 * mono_get_delegate_invoke:
3140 * @klass: The delegate class
3142 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3145 mono_get_delegate_invoke (MonoClass *klass)
3149 /* This is called at runtime, so avoid the slower search in metadata */
3150 mono_class_setup_methods (klass);
3152 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3159 * mono_runtime_delegate_invoke:
3160 * @delegate: pointer to a delegate object.
3161 * @params: parameters for the delegate.
3162 * @exc: Pointer to the exception result.
3164 * Invokes the delegate method @delegate with the parameters provided.
3166 * You can pass NULL as the exc argument if you don't want to
3167 * catch exceptions, otherwise, *exc will be set to the exception
3168 * thrown, if any. if an exception is thrown, you can't use the
3169 * MonoObject* result from the function.
3172 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3176 im = mono_get_delegate_invoke (delegate->vtable->klass);
3179 return mono_runtime_invoke (im, delegate, params, exc);
3182 static char **main_args = NULL;
3183 static int num_main_args;
3186 * mono_runtime_get_main_args:
3188 * Returns: a MonoArray with the arguments passed to the main program
3191 mono_runtime_get_main_args (void)
3195 MonoDomain *domain = mono_domain_get ();
3200 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3202 for (i = 0; i < num_main_args; ++i)
3203 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3209 fire_process_exit_event (void)
3211 MonoClassField *field;
3212 MonoDomain *domain = mono_domain_get ();
3214 MonoObject *delegate, *exc;
3216 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3219 if (domain != mono_get_root_domain ())
3222 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3223 if (delegate == NULL)
3228 mono_runtime_delegate_invoke (delegate, pa, &exc);
3232 * mono_runtime_run_main:
3233 * @method: the method to start the application with (usually Main)
3234 * @argc: number of arguments from the command line
3235 * @argv: array of strings from the command line
3236 * @exc: excetption results
3238 * Execute a standard Main() method (argc/argv contains the
3239 * executable name). This method also sets the command line argument value
3240 * needed by System.Environment.
3245 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3249 MonoArray *args = NULL;
3250 MonoDomain *domain = mono_domain_get ();
3251 gchar *utf8_fullpath;
3254 g_assert (method != NULL);
3256 mono_thread_set_main (mono_thread_current ());
3258 main_args = g_new0 (char*, argc);
3259 num_main_args = argc;
3261 if (!g_path_is_absolute (argv [0])) {
3262 gchar *basename = g_path_get_basename (argv [0]);
3263 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3267 utf8_fullpath = mono_utf8_from_external (fullpath);
3268 if(utf8_fullpath == NULL) {
3269 /* Printing the arg text will cause glib to
3270 * whinge about "Invalid UTF-8", but at least
3271 * its relevant, and shows the problem text
3274 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3275 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3282 utf8_fullpath = mono_utf8_from_external (argv[0]);
3283 if(utf8_fullpath == NULL) {
3284 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3285 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3290 main_args [0] = utf8_fullpath;
3292 for (i = 1; i < argc; ++i) {
3295 utf8_arg=mono_utf8_from_external (argv[i]);
3296 if(utf8_arg==NULL) {
3297 /* Ditto the comment about Invalid UTF-8 here */
3298 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3299 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3303 main_args [i] = utf8_arg;
3307 if (mono_method_signature (method)->param_count) {
3308 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3309 for (i = 0; i < argc; ++i) {
3310 /* The encodings should all work, given that
3311 * we've checked all these args for the
3314 gchar *str = mono_utf8_from_external (argv [i]);
3315 MonoString *arg = mono_string_new (domain, str);
3316 mono_array_setref (args, i, arg);
3320 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3323 mono_assembly_set_main (method->klass->image->assembly);
3325 result = mono_runtime_exec_main (method, args, exc);
3326 fire_process_exit_event ();
3331 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3333 static MonoMethod *serialize_method;
3338 if (!serialize_method) {
3339 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3340 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3343 if (!serialize_method) {
3348 g_assert (!mono_object_class (obj)->marshalbyref);
3352 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3360 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3362 static MonoMethod *deserialize_method;
3367 if (!deserialize_method) {
3368 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3369 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3371 if (!deserialize_method) {
3378 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3386 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3388 static MonoMethod *get_proxy_method;
3390 MonoDomain *domain = mono_domain_get ();
3391 MonoRealProxy *real_proxy;
3392 MonoReflectionType *reflection_type;
3393 MonoTransparentProxy *transparent_proxy;
3395 if (!get_proxy_method)
3396 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3398 g_assert (obj->vtable->klass->marshalbyref);
3400 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3401 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3403 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3404 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3407 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3411 return (MonoObject*) transparent_proxy;
3415 * mono_object_xdomain_representation
3417 * @target_domain: a domain
3418 * @exc: pointer to a MonoObject*
3420 * Creates a representation of obj in the domain target_domain. This
3421 * is either a copy of obj arrived through via serialization and
3422 * deserialization or a proxy, depending on whether the object is
3423 * serializable or marshal by ref. obj must not be in target_domain.
3425 * If the object cannot be represented in target_domain, NULL is
3426 * returned and *exc is set to an appropriate exception.
3429 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3431 MonoObject *deserialized = NULL;
3432 gboolean failure = FALSE;
3436 if (mono_object_class (obj)->marshalbyref) {
3437 deserialized = make_transparent_proxy (obj, &failure, exc);
3439 MonoDomain *domain = mono_domain_get ();
3440 MonoObject *serialized;
3442 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3443 serialized = serialize_object (obj, &failure, exc);
3444 mono_domain_set_internal_with_options (target_domain, FALSE);
3446 deserialized = deserialize_object (serialized, &failure, exc);
3447 if (domain != target_domain)
3448 mono_domain_set_internal_with_options (domain, FALSE);
3451 return deserialized;
3454 /* Used in call_unhandled_exception_delegate */
3456 create_unhandled_exception_eventargs (MonoObject *exc)
3460 MonoMethod *method = NULL;
3461 MonoBoolean is_terminating = TRUE;
3464 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3467 mono_class_init (klass);
3469 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3470 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3474 args [1] = &is_terminating;
3476 obj = mono_object_new (mono_domain_get (), klass);
3477 mono_runtime_invoke (method, obj, args, NULL);
3482 /* Used in mono_unhandled_exception */
3484 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3485 MonoObject *e = NULL;
3487 MonoDomain *current_domain = mono_domain_get ();
3489 if (domain != current_domain)
3490 mono_domain_set_internal_with_options (domain, FALSE);
3492 g_assert (domain == mono_object_domain (domain->domain));
3494 if (mono_object_domain (exc) != domain) {
3495 MonoObject *serialization_exc;
3497 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3499 if (serialization_exc) {
3501 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3504 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3505 "System.Runtime.Serialization", "SerializationException",
3506 "Could not serialize unhandled exception.");
3510 g_assert (mono_object_domain (exc) == domain);
3512 pa [0] = domain->domain;
3513 pa [1] = create_unhandled_exception_eventargs (exc);
3514 mono_runtime_delegate_invoke (delegate, pa, &e);
3516 if (domain != current_domain)
3517 mono_domain_set_internal_with_options (current_domain, FALSE);
3521 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3522 if (!mono_error_ok (&error)) {
3523 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3524 mono_error_cleanup (&error);
3526 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3532 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3535 * mono_runtime_unhandled_exception_policy_set:
3536 * @policy: the new policy
3538 * This is a VM internal routine.
3540 * Sets the runtime policy for handling unhandled exceptions.
3543 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3544 runtime_unhandled_exception_policy = policy;
3548 * mono_runtime_unhandled_exception_policy_get:
3550 * This is a VM internal routine.
3552 * Gets the runtime policy for handling unhandled exceptions.
3554 MonoRuntimeUnhandledExceptionPolicy
3555 mono_runtime_unhandled_exception_policy_get (void) {
3556 return runtime_unhandled_exception_policy;
3560 * mono_unhandled_exception:
3561 * @exc: exception thrown
3563 * This is a VM internal routine.
3565 * We call this function when we detect an unhandled exception
3566 * in the default domain.
3568 * It invokes the * UnhandledException event in AppDomain or prints
3569 * a warning to the console
3572 mono_unhandled_exception (MonoObject *exc)
3574 MonoDomain *current_domain = mono_domain_get ();
3575 MonoDomain *root_domain = mono_get_root_domain ();
3576 MonoClassField *field;
3577 MonoObject *current_appdomain_delegate;
3578 MonoObject *root_appdomain_delegate;
3580 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3581 "UnhandledException");
3584 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3585 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3586 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3587 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3588 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3589 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3591 current_appdomain_delegate = NULL;
3594 /* set exitcode only if we will abort the process */
3596 mono_environment_exitcode_set (1);
3597 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3598 mono_print_unhandled_exception (exc);
3600 if (root_appdomain_delegate) {
3601 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3603 if (current_appdomain_delegate) {
3604 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3611 * Launch a new thread to execute a function
3613 * main_func is called back from the thread with main_args as the
3614 * parameter. The callback function is expected to start Main()
3615 * eventually. This function then waits for all managed threads to
3617 * It is not necesseray anymore to execute managed code in a subthread,
3618 * so this function should not be used anymore by default: just
3619 * execute the code and then call mono_thread_manage ().
3622 mono_runtime_exec_managed_code (MonoDomain *domain,
3623 MonoMainThreadFunc main_func,
3626 mono_thread_create (domain, main_func, main_args);
3628 mono_thread_manage ();
3632 * Execute a standard Main() method (args doesn't contain the
3636 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3641 MonoCustomAttrInfo* cinfo;
3642 gboolean has_stathread_attribute;
3643 MonoInternalThread* thread = mono_thread_internal_current ();
3649 domain = mono_object_domain (args);
3650 if (!domain->entry_assembly) {
3652 MonoAssembly *assembly;
3654 assembly = method->klass->image->assembly;
3655 domain->entry_assembly = assembly;
3656 /* Domains created from another domain already have application_base and configuration_file set */
3657 if (domain->setup->application_base == NULL) {
3658 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3661 if (domain->setup->configuration_file == NULL) {
3662 str = g_strconcat (assembly->image->name, ".config", NULL);
3663 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3665 mono_set_private_bin_path_from_config (domain);
3669 cinfo = mono_custom_attrs_from_method (method);
3671 static MonoClass *stathread_attribute = NULL;
3672 if (!stathread_attribute)
3673 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3674 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3676 mono_custom_attrs_free (cinfo);
3678 has_stathread_attribute = FALSE;
3680 if (has_stathread_attribute) {
3681 thread->apartment_state = ThreadApartmentState_STA;
3682 } else if (mono_framework_version () == 1) {
3683 thread->apartment_state = ThreadApartmentState_Unknown;
3685 thread->apartment_state = ThreadApartmentState_MTA;
3687 mono_thread_init_apartment_state ();
3689 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3691 /* FIXME: check signature of method */
3692 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3694 res = mono_runtime_invoke (method, NULL, pa, exc);
3696 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3700 mono_environment_exitcode_set (rval);
3702 mono_runtime_invoke (method, NULL, pa, exc);
3706 /* If the return type of Main is void, only
3707 * set the exitcode if an exception was thrown
3708 * (we don't want to blow away an
3709 * explicitly-set exit code)
3712 mono_environment_exitcode_set (rval);
3716 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3722 * mono_install_runtime_invoke:
3723 * @func: Function to install
3725 * This is a VM internal routine
3728 mono_install_runtime_invoke (MonoInvokeFunc func)
3730 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3735 * mono_runtime_invoke_array:
3736 * @method: method to invoke
3737 * @obJ: object instance
3738 * @params: arguments to the method
3739 * @exc: exception information.
3741 * Invokes the method represented by @method on the object @obj.
3743 * obj is the 'this' pointer, it should be NULL for static
3744 * methods, a MonoObject* for object instances and a pointer to
3745 * the value type for value types.
3747 * The params array contains the arguments to the method with the
3748 * same convention: MonoObject* pointers for object instances and
3749 * pointers to the value type otherwise. The _invoke_array
3750 * variant takes a C# object[] as the params argument (MonoArray
3751 * *params): in this case the value types are boxed inside the
3752 * respective reference representation.
3754 * From unmanaged code you'll usually use the
3755 * mono_runtime_invoke() variant.
3757 * Note that this function doesn't handle virtual methods for
3758 * you, it will exec the exact method you pass: we still need to
3759 * expose a function to lookup the derived class implementation
3760 * of a virtual method (there are examples of this in the code,
3763 * You can pass NULL as the exc argument if you don't want to
3764 * catch exceptions, otherwise, *exc will be set to the exception
3765 * thrown, if any. if an exception is thrown, you can't use the
3766 * MonoObject* result from the function.
3768 * If the method returns a value type, it is boxed in an object
3772 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3775 MonoMethodSignature *sig = mono_method_signature (method);
3776 gpointer *pa = NULL;
3779 gboolean has_byref_nullables = FALSE;
3781 if (NULL != params) {
3782 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3783 for (i = 0; i < mono_array_length (params); i++) {
3784 MonoType *t = sig->params [i];
3790 case MONO_TYPE_BOOLEAN:
3793 case MONO_TYPE_CHAR:
3802 case MONO_TYPE_VALUETYPE:
3803 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3804 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3805 pa [i] = mono_array_get (params, MonoObject*, i);
3807 has_byref_nullables = TRUE;
3809 /* MS seems to create the objects if a null is passed in */
3810 if (!mono_array_get (params, MonoObject*, i))
3811 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3815 * We can't pass the unboxed vtype byref to the callee, since
3816 * that would mean the callee would be able to modify boxed
3817 * primitive types. So we (and MS) make a copy of the boxed
3818 * object, pass that to the callee, and replace the original
3819 * boxed object in the arg array with the copy.
3821 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3822 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3823 mono_array_setref (params, i, copy);
3826 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3829 case MONO_TYPE_STRING:
3830 case MONO_TYPE_OBJECT:
3831 case MONO_TYPE_CLASS:
3832 case MONO_TYPE_ARRAY:
3833 case MONO_TYPE_SZARRAY:
3835 pa [i] = mono_array_addr (params, MonoObject*, i);
3836 // FIXME: I need to check this code path
3838 pa [i] = mono_array_get (params, MonoObject*, i);
3840 case MONO_TYPE_GENERICINST:
3842 t = &t->data.generic_class->container_class->this_arg;
3844 t = &t->data.generic_class->container_class->byval_arg;
3846 case MONO_TYPE_PTR: {
3849 /* The argument should be an IntPtr */
3850 arg = mono_array_get (params, MonoObject*, i);
3854 g_assert (arg->vtable->klass == mono_defaults.int_class);
3855 pa [i] = ((MonoIntPtr*)arg)->m_value;
3860 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3865 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3868 if (mono_class_is_nullable (method->klass)) {
3869 /* Need to create a boxed vtype instead */
3875 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3879 obj = mono_object_new (mono_domain_get (), method->klass);
3880 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3881 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3883 if (method->klass->valuetype)
3884 o = mono_object_unbox (obj);
3887 } else if (method->klass->valuetype) {
3888 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3891 mono_runtime_invoke (method, o, pa, exc);
3894 if (mono_class_is_nullable (method->klass)) {
3895 MonoObject *nullable;
3897 /* Convert the unboxed vtype into a Nullable structure */
3898 nullable = mono_object_new (mono_domain_get (), method->klass);
3900 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3901 obj = mono_object_unbox (nullable);
3904 /* obj must be already unboxed if needed */
3905 res = mono_runtime_invoke (method, obj, pa, exc);
3907 if (sig->ret->type == MONO_TYPE_PTR) {
3908 MonoClass *pointer_class;
3909 static MonoMethod *box_method;
3911 MonoObject *box_exc;
3914 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3915 * convert it to a Pointer object.
3917 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3919 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3921 g_assert (res->vtable->klass == mono_defaults.int_class);
3922 box_args [0] = ((MonoIntPtr*)res)->m_value;
3923 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3924 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3925 g_assert (!box_exc);
3928 if (has_byref_nullables) {
3930 * The runtime invoke wrapper already converted byref nullables back,
3931 * and stored them in pa, we just need to copy them back to the
3934 for (i = 0; i < mono_array_length (params); i++) {
3935 MonoType *t = sig->params [i];
3937 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3938 mono_array_setref (params, i, pa [i]);
3947 arith_overflow (void)
3949 mono_raise_exception (mono_get_exception_overflow ());
3953 * mono_object_allocate:
3954 * @size: number of bytes to allocate
3956 * This is a very simplistic routine until we have our GC-aware
3959 * Returns: an allocated object of size @size, or NULL on failure.
3961 static inline void *
3962 mono_object_allocate (size_t size, MonoVTable *vtable)
3965 mono_stats.new_object_count++;
3966 ALLOC_OBJECT (o, vtable, size);
3972 * mono_object_allocate_ptrfree:
3973 * @size: number of bytes to allocate
3975 * Note that the memory allocated is not zeroed.
3976 * Returns: an allocated object of size @size, or NULL on failure.
3978 static inline void *
3979 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3982 mono_stats.new_object_count++;
3983 ALLOC_PTRFREE (o, vtable, size);
3987 static inline void *
3988 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3991 ALLOC_TYPED (o, size, vtable);
3992 mono_stats.new_object_count++;
3999 * @klass: the class of the object that we want to create
4001 * Returns: a newly created object whose definition is
4002 * looked up using @klass. This will not invoke any constructors,
4003 * so the consumer of this routine has to invoke any constructors on
4004 * its own to initialize the object.
4006 * It returns NULL on failure.
4009 mono_object_new (MonoDomain *domain, MonoClass *klass)
4013 MONO_ARCH_SAVE_REGS;
4014 vtable = mono_class_vtable (domain, klass);
4017 return mono_object_new_specific (vtable);
4021 * mono_object_new_specific:
4022 * @vtable: the vtable of the object that we want to create
4024 * Returns: A newly created object with class and domain specified
4028 mono_object_new_specific (MonoVTable *vtable)
4032 MONO_ARCH_SAVE_REGS;
4034 /* check for is_com_object for COM Interop */
4035 if (vtable->remote || vtable->klass->is_com_object)
4038 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4041 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4044 mono_class_init (klass);
4046 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4048 vtable->domain->create_proxy_for_type_method = im;
4051 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4053 o = mono_runtime_invoke (im, NULL, pa, NULL);
4054 if (o != NULL) return o;
4057 return mono_object_new_alloc_specific (vtable);
4061 mono_object_new_alloc_specific (MonoVTable *vtable)
4065 if (!vtable->klass->has_references) {
4066 o = mono_object_new_ptrfree (vtable);
4067 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4068 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4070 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4071 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4073 if (G_UNLIKELY (vtable->klass->has_finalize))
4074 mono_object_register_finalizer (o);
4076 if (G_UNLIKELY (profile_allocs))
4077 mono_profiler_allocation (o, vtable->klass);
4082 mono_object_new_fast (MonoVTable *vtable)
4085 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4090 mono_object_new_ptrfree (MonoVTable *vtable)
4093 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4094 #if NEED_TO_ZERO_PTRFREE
4095 /* an inline memset is much faster for the common vcase of small objects
4096 * note we assume the allocated size is a multiple of sizeof (void*).
4098 if (vtable->klass->instance_size < 128) {
4100 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4101 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4107 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4114 mono_object_new_ptrfree_box (MonoVTable *vtable)
4117 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4118 /* the object will be boxed right away, no need to memzero it */
4123 * mono_class_get_allocation_ftn:
4125 * @for_box: the object will be used for boxing
4126 * @pass_size_in_words:
4128 * Return the allocation function appropriate for the given class.
4132 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4134 *pass_size_in_words = FALSE;
4136 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4137 profile_allocs = FALSE;
4139 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4140 return mono_object_new_specific;
4142 if (!vtable->klass->has_references) {
4143 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4145 return mono_object_new_ptrfree_box;
4146 return mono_object_new_ptrfree;
4149 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4151 return mono_object_new_fast;
4154 * FIXME: This is actually slower than mono_object_new_fast, because
4155 * of the overhead of parameter passing.
4158 *pass_size_in_words = TRUE;
4159 #ifdef GC_REDIRECT_TO_LOCAL
4160 return GC_local_gcj_fast_malloc;
4162 return GC_gcj_fast_malloc;
4167 return mono_object_new_specific;
4171 * mono_object_new_from_token:
4172 * @image: Context where the type_token is hosted
4173 * @token: a token of the type that we want to create
4175 * Returns: A newly created object whose definition is
4176 * looked up using @token in the @image image
4179 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4183 class = mono_class_get (image, token);
4185 return mono_object_new (domain, class);
4190 * mono_object_clone:
4191 * @obj: the object to clone
4193 * Returns: A newly created object who is a shallow copy of @obj
4196 mono_object_clone (MonoObject *obj)
4199 int size = obj->vtable->klass->instance_size;
4201 o = mono_object_allocate (size, obj->vtable);
4203 if (obj->vtable->klass->has_references) {
4204 mono_gc_wbarrier_object_copy (o, obj);
4206 int size = obj->vtable->klass->instance_size;
4207 /* do not copy the sync state */
4208 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4210 if (G_UNLIKELY (profile_allocs))
4211 mono_profiler_allocation (o, obj->vtable->klass);
4213 if (obj->vtable->klass->has_finalize)
4214 mono_object_register_finalizer (o);
4219 * mono_array_full_copy:
4220 * @src: source array to copy
4221 * @dest: destination array
4223 * Copies the content of one array to another with exactly the same type and size.
4226 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4228 mono_array_size_t size;
4229 MonoClass *klass = src->obj.vtable->klass;
4231 MONO_ARCH_SAVE_REGS;
4233 g_assert (klass == dest->obj.vtable->klass);
4235 size = mono_array_length (src);
4236 g_assert (size == mono_array_length (dest));
4237 size *= mono_array_element_size (klass);
4239 if (klass->element_class->valuetype) {
4240 if (klass->element_class->has_references)
4241 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4243 memcpy (&dest->vector, &src->vector, size);
4245 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4248 memcpy (&dest->vector, &src->vector, size);
4253 * mono_array_clone_in_domain:
4254 * @domain: the domain in which the array will be cloned into
4255 * @array: the array to clone
4257 * This routine returns a copy of the array that is hosted on the
4258 * specified MonoDomain.
4261 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4264 mono_array_size_t size, i;
4265 mono_array_size_t *sizes;
4266 MonoClass *klass = array->obj.vtable->klass;
4268 MONO_ARCH_SAVE_REGS;
4270 if (array->bounds == NULL) {
4271 size = mono_array_length (array);
4272 o = mono_array_new_full (domain, klass, &size, NULL);
4274 size *= mono_array_element_size (klass);
4276 if (klass->element_class->valuetype) {
4277 if (klass->element_class->has_references)
4278 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4280 memcpy (&o->vector, &array->vector, size);
4282 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4285 memcpy (&o->vector, &array->vector, size);
4290 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4291 size = mono_array_element_size (klass);
4292 for (i = 0; i < klass->rank; ++i) {
4293 sizes [i] = array->bounds [i].length;
4294 size *= array->bounds [i].length;
4295 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4297 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4299 if (klass->element_class->valuetype) {
4300 if (klass->element_class->has_references)
4301 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4303 memcpy (&o->vector, &array->vector, size);
4305 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4308 memcpy (&o->vector, &array->vector, size);
4316 * @array: the array to clone
4318 * Returns: A newly created array who is a shallow copy of @array
4321 mono_array_clone (MonoArray *array)
4323 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4326 /* helper macros to check for overflow when calculating the size of arrays */
4327 #ifdef MONO_BIG_ARRAYS
4328 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4329 #define MYGUINT_MAX MYGUINT64_MAX
4330 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4331 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4332 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4333 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4334 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4336 #define MYGUINT32_MAX 4294967295U
4337 #define MYGUINT_MAX MYGUINT32_MAX
4338 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4339 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4340 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4341 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4342 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4346 mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
4348 mono_array_size_t byte_len;
4350 byte_len = mono_array_element_size (class);
4351 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4354 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4356 byte_len += sizeof (MonoArray);
4364 * mono_array_new_full:
4365 * @domain: domain where the object is created
4366 * @array_class: array class
4367 * @lengths: lengths for each dimension in the array
4368 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4370 * This routine creates a new array objects with the given dimensions,
4371 * lower bounds and type.
4374 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4376 mono_array_size_t byte_len, len, bounds_size;
4379 MonoArrayBounds *bounds;
4383 if (!array_class->inited)
4384 mono_class_init (array_class);
4388 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4389 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4391 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4395 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4397 for (i = 0; i < array_class->rank; ++i) {
4398 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4400 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4401 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4406 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4407 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4411 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4412 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4413 byte_len = (byte_len + 3) & ~3;
4414 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4415 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4416 byte_len += bounds_size;
4419 * Following three lines almost taken from mono_object_new ():
4420 * they need to be kept in sync.
4422 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4423 #ifndef HAVE_SGEN_GC
4424 if (!array_class->has_references) {
4425 o = mono_object_allocate_ptrfree (byte_len, vtable);
4426 #if NEED_TO_ZERO_PTRFREE
4427 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4429 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4430 o = mono_object_allocate_spec (byte_len, vtable);
4432 o = mono_object_allocate (byte_len, vtable);
4435 array = (MonoArray*)o;
4436 array->max_length = len;
4439 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4440 array->bounds = bounds;
4444 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4446 o = mono_gc_alloc_vector (vtable, byte_len, len);
4447 array = (MonoArray*)o;
4448 mono_stats.new_object_count++;
4450 bounds = array->bounds;
4454 for (i = 0; i < array_class->rank; ++i) {
4455 bounds [i].length = lengths [i];
4457 bounds [i].lower_bound = lower_bounds [i];
4461 if (G_UNLIKELY (profile_allocs))
4462 mono_profiler_allocation (o, array_class);
4469 * @domain: domain where the object is created
4470 * @eclass: element class
4471 * @n: number of array elements
4473 * This routine creates a new szarray with @n elements of type @eclass.
4476 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4480 MONO_ARCH_SAVE_REGS;
4482 ac = mono_array_class_get (eclass, 1);
4485 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4489 * mono_array_new_specific:
4490 * @vtable: a vtable in the appropriate domain for an initialized class
4491 * @n: number of array elements
4493 * This routine is a fast alternative to mono_array_new() for code which
4494 * can be sure about the domain it operates in.
4497 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4503 MONO_ARCH_SAVE_REGS;
4505 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4510 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4511 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4514 #ifndef HAVE_SGEN_GC
4515 if (!vtable->klass->has_references) {
4516 o = mono_object_allocate_ptrfree (byte_len, vtable);
4517 #if NEED_TO_ZERO_PTRFREE
4518 ((MonoArray*)o)->bounds = NULL;
4519 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4521 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4522 o = mono_object_allocate_spec (byte_len, vtable);
4524 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4525 o = mono_object_allocate (byte_len, vtable);
4528 ao = (MonoArray *)o;
4531 o = mono_gc_alloc_vector (vtable, byte_len, n);
4533 mono_stats.new_object_count++;
4536 if (G_UNLIKELY (profile_allocs))
4537 mono_profiler_allocation (o, vtable->klass);
4543 * mono_string_new_utf16:
4544 * @text: a pointer to an utf16 string
4545 * @len: the length of the string
4547 * Returns: A newly created string object which contains @text.
4550 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4554 s = mono_string_new_size (domain, len);
4555 g_assert (s != NULL);
4557 memcpy (mono_string_chars (s), text, len * 2);
4563 * mono_string_new_size:
4564 * @text: a pointer to an utf16 string
4565 * @len: the length of the string
4567 * Returns: A newly created string object of @len
4570 mono_string_new_size (MonoDomain *domain, gint32 len)
4574 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4576 /* overflow ? can't fit it, can't allocate it! */
4578 mono_gc_out_of_memory (-1);
4580 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4583 s = mono_object_allocate_ptrfree (size, vtable);
4586 #if NEED_TO_ZERO_PTRFREE
4589 if (G_UNLIKELY (profile_allocs))
4590 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4596 * mono_string_new_len:
4597 * @text: a pointer to an utf8 string
4598 * @length: number of bytes in @text to consider
4600 * Returns: A newly created string object which contains @text.
4603 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4605 GError *error = NULL;
4606 MonoString *o = NULL;
4608 glong items_written;
4610 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4613 o = mono_string_new_utf16 (domain, ut, items_written);
4615 g_error_free (error);
4624 * @text: a pointer to an utf8 string
4626 * Returns: A newly created string object which contains @text.
4629 mono_string_new (MonoDomain *domain, const char *text)
4631 GError *error = NULL;
4632 MonoString *o = NULL;
4634 glong items_written;
4639 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4642 o = mono_string_new_utf16 (domain, ut, items_written);
4644 g_error_free (error);
4647 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4652 MonoString *o = NULL;
4654 if (!g_utf8_validate (text, -1, &end))
4657 len = g_utf8_strlen (text, -1);
4658 o = mono_string_new_size (domain, len);
4659 str = mono_string_chars (o);
4661 while (text < end) {
4662 *str++ = g_utf8_get_char (text);
4663 text = g_utf8_next_char (text);
4670 * mono_string_new_wrapper:
4671 * @text: pointer to utf8 characters.
4673 * Helper function to create a string object from @text in the current domain.
4676 mono_string_new_wrapper (const char *text)
4678 MonoDomain *domain = mono_domain_get ();
4680 MONO_ARCH_SAVE_REGS;
4683 return mono_string_new (domain, text);
4690 * @class: the class of the value
4691 * @value: a pointer to the unboxed data
4693 * Returns: A newly created object which contains @value.
4696 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4702 g_assert (class->valuetype);
4703 if (mono_class_is_nullable (class))
4704 return mono_nullable_box (value, class);
4706 vtable = mono_class_vtable (domain, class);
4709 size = mono_class_instance_size (class);
4710 res = mono_object_new_alloc_specific (vtable);
4711 if (G_UNLIKELY (profile_allocs))
4712 mono_profiler_allocation (res, class);
4714 size = size - sizeof (MonoObject);
4717 g_assert (size == mono_class_value_size (class, NULL));
4718 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4720 #if NO_UNALIGNED_ACCESS
4721 memcpy ((char *)res + sizeof (MonoObject), value, size);
4725 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4728 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4731 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4734 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4737 memcpy ((char *)res + sizeof (MonoObject), value, size);
4741 if (class->has_finalize)
4742 mono_object_register_finalizer (res);
4748 * @dest: destination pointer
4749 * @src: source pointer
4750 * @klass: a valuetype class
4752 * Copy a valuetype from @src to @dest. This function must be used
4753 * when @klass contains references fields.
4756 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4758 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4762 * mono_value_copy_array:
4763 * @dest: destination array
4764 * @dest_idx: index in the @dest array
4765 * @src: source pointer
4766 * @count: number of items
4768 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4769 * This function must be used when @klass contains references fields.
4770 * Overlap is handled.
4773 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4775 int size = mono_array_element_size (dest->obj.vtable->klass);
4776 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4777 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4778 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4782 * mono_object_get_domain:
4783 * @obj: object to query
4785 * Returns: the MonoDomain where the object is hosted
4788 mono_object_get_domain (MonoObject *obj)
4790 return mono_object_domain (obj);
4794 * mono_object_get_class:
4795 * @obj: object to query
4797 * Returns: the MonOClass of the object.
4800 mono_object_get_class (MonoObject *obj)
4802 return mono_object_class (obj);
4805 * mono_object_get_size:
4806 * @o: object to query
4808 * Returns: the size, in bytes, of @o
4811 mono_object_get_size (MonoObject* o)
4813 MonoClass* klass = mono_object_class (o);
4814 if (klass == mono_defaults.string_class) {
4815 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4816 } else if (o->vtable->rank) {
4817 MonoArray *array = (MonoArray*)o;
4818 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4819 if (array->bounds) {
4822 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4826 return mono_class_instance_size (klass);
4831 * mono_object_unbox:
4832 * @obj: object to unbox
4834 * Returns: a pointer to the start of the valuetype boxed in this
4837 * This method will assert if the object passed is not a valuetype.
4840 mono_object_unbox (MonoObject *obj)
4842 /* add assert for valuetypes? */
4843 g_assert (obj->vtable->klass->valuetype);
4844 return ((char*)obj) + sizeof (MonoObject);
4848 * mono_object_isinst:
4850 * @klass: a pointer to a class
4852 * Returns: @obj if @obj is derived from @klass
4855 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4858 mono_class_init (klass);
4860 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4861 return mono_object_isinst_mbyref (obj, klass);
4866 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4870 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4879 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4880 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4884 MonoClass *oklass = vt->klass;
4885 if ((oklass == mono_defaults.transparent_proxy_class))
4886 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4888 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4892 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4894 MonoDomain *domain = mono_domain_get ();
4896 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4897 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4898 MonoMethod *im = NULL;
4901 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4902 im = mono_object_get_virtual_method (rp, im);
4905 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4908 res = mono_runtime_invoke (im, rp, pa, NULL);
4910 if (*(MonoBoolean *) mono_object_unbox(res)) {
4911 /* Update the vtable of the remote type, so it can safely cast to this new type */
4912 mono_upgrade_remote_class (domain, obj, klass);
4921 * mono_object_castclass_mbyref:
4923 * @klass: a pointer to a class
4925 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4928 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4930 if (!obj) return NULL;
4931 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4933 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4935 "InvalidCastException"));
4940 MonoDomain *orig_domain;
4946 str_lookup (MonoDomain *domain, gpointer user_data)
4948 LDStrInfo *info = user_data;
4949 if (info->res || domain == info->orig_domain)
4951 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4957 mono_string_get_pinned (MonoString *str)
4961 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4962 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4963 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4964 news->length = mono_string_length (str);
4969 #define mono_string_get_pinned(str) (str)
4973 mono_string_is_interned_lookup (MonoString *str, int insert)
4975 MonoGHashTable *ldstr_table;
4979 domain = ((MonoObject *)str)->vtable->domain;
4980 ldstr_table = domain->ldstr_table;
4982 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4987 str = mono_string_get_pinned (str);
4988 mono_g_hash_table_insert (ldstr_table, str, str);
4992 LDStrInfo ldstr_info;
4993 ldstr_info.orig_domain = domain;
4994 ldstr_info.ins = str;
4995 ldstr_info.res = NULL;
4997 mono_domain_foreach (str_lookup, &ldstr_info);
4998 if (ldstr_info.res) {
5000 * the string was already interned in some other domain:
5001 * intern it in the current one as well.
5003 mono_g_hash_table_insert (ldstr_table, str, str);
5013 * mono_string_is_interned:
5014 * @o: String to probe
5016 * Returns whether the string has been interned.
5019 mono_string_is_interned (MonoString *o)
5021 return mono_string_is_interned_lookup (o, FALSE);
5025 * mono_string_intern:
5026 * @o: String to intern
5028 * Interns the string passed.
5029 * Returns: The interned string.
5032 mono_string_intern (MonoString *str)
5034 return mono_string_is_interned_lookup (str, TRUE);
5039 * @domain: the domain where the string will be used.
5040 * @image: a metadata context
5041 * @idx: index into the user string table.
5043 * Implementation for the ldstr opcode.
5044 * Returns: a loaded string from the @image/@idx combination.
5047 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5049 MONO_ARCH_SAVE_REGS;
5051 if (image->dynamic) {
5052 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5053 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5054 mono_profiler_string_allocation (domain, str);
5057 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5058 return NULL; /*FIXME we should probably be raising an exception here*/
5059 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5064 * mono_ldstr_metadata_sig
5065 * @domain: the domain for the string
5066 * @sig: the signature of a metadata string
5068 * Returns: a MonoString for a string stored in the metadata
5071 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5073 const char *str = sig;
5074 MonoString *o, *interned;
5077 len2 = mono_metadata_decode_blob_size (str, &str);
5080 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5081 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5084 guint16 *p2 = (guint16*)mono_string_chars (o);
5085 for (i = 0; i < len2; ++i) {
5086 *p2 = GUINT16_FROM_LE (*p2);
5092 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5094 /* o will get garbage collected */
5098 o = mono_string_get_pinned (o);
5099 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5102 if (mono_profiler_events & MONO_PROFILE_STRING_ALLOC)
5103 mono_profiler_string_allocation (domain, o);
5109 * mono_string_to_utf8:
5110 * @s: a System.String
5112 * Return the UTF8 representation for @s.
5113 * the resulting buffer nedds to be freed with g_free().
5115 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5118 mono_string_to_utf8 (MonoString *s)
5121 char *result = mono_string_to_utf8_checked (s, &error);
5123 if (!mono_error_ok (&error))
5124 mono_error_raise_exception (&error);
5129 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5133 GError *gerror = NULL;
5135 mono_error_init (error);
5141 return g_strdup ("");
5143 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5145 mono_error_set_argument (error, "string", "%s", gerror->message);
5146 g_error_free (gerror);
5149 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5150 if (s->length > written) {
5151 /* allocate the total length and copy the part of the string that has been converted */
5152 char *as2 = g_malloc0 (s->length);
5153 memcpy (as2, as, written);
5162 * mono_string_to_utf16:
5165 * Return an null-terminated array of the utf-16 chars
5166 * contained in @s. The result must be freed with g_free().
5167 * This is a temporary helper until our string implementation
5168 * is reworked to always include the null terminating char.
5171 mono_string_to_utf16 (MonoString *s)
5178 as = g_malloc ((s->length * 2) + 2);
5179 as [(s->length * 2)] = '\0';
5180 as [(s->length * 2) + 1] = '\0';
5183 return (gunichar2 *)(as);
5186 memcpy (as, mono_string_chars(s), s->length * 2);
5187 return (gunichar2 *)(as);
5191 * mono_string_from_utf16:
5192 * @data: the UTF16 string (LPWSTR) to convert
5194 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5196 * Returns: a MonoString.
5199 mono_string_from_utf16 (gunichar2 *data)
5201 MonoDomain *domain = mono_domain_get ();
5207 while (data [len]) len++;
5209 return mono_string_new_utf16 (domain, data, len);
5214 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5220 r = mono_string_to_utf8_checked (s, error);
5221 if (!mono_error_ok (error))
5227 len = strlen (r) + 1;
5229 mp_s = mono_mempool_alloc (mp, len);
5231 mp_s = mono_image_alloc (image, len);
5233 memcpy (mp_s, r, len);
5241 * mono_string_to_utf8_image:
5242 * @s: a System.String
5244 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5247 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5249 return mono_string_to_utf8_internal (NULL, image, s, error);
5253 * mono_string_to_utf8_mp:
5254 * @s: a System.String
5256 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5259 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5261 return mono_string_to_utf8_internal (mp, NULL, s, error);
5265 default_ex_handler (MonoException *ex)
5267 MonoObject *o = (MonoObject*)ex;
5268 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5272 static MonoExceptionFunc ex_handler = default_ex_handler;
5275 * mono_install_handler:
5276 * @func: exception handler
5278 * This is an internal JIT routine used to install the handler for exceptions
5282 mono_install_handler (MonoExceptionFunc func)
5284 ex_handler = func? func: default_ex_handler;
5288 * mono_raise_exception:
5289 * @ex: exception object
5291 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5294 mono_raise_exception (MonoException *ex)
5297 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5298 * that will cause gcc to omit the function epilog, causing problems when
5299 * the JIT tries to walk the stack, since the return address on the stack
5300 * will point into the next function in the executable, not this one.
5303 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5304 MonoInternalThread *thread = mono_thread_internal_current ();
5305 g_assert (ex->object.vtable->domain == mono_domain_get ());
5306 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5313 * mono_wait_handle_new:
5314 * @domain: Domain where the object will be created
5315 * @handle: Handle for the wait handle
5317 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5320 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5322 MonoWaitHandle *res;
5323 gpointer params [1];
5324 static MonoMethod *handle_set;
5326 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5328 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5330 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5332 params [0] = &handle;
5333 mono_runtime_invoke (handle_set, res, params, NULL);
5339 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5341 static MonoClassField *f_os_handle;
5342 static MonoClassField *f_safe_handle;
5344 if (!f_os_handle && !f_safe_handle) {
5345 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5346 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5351 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5355 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5362 mono_runtime_capture_context (MonoDomain *domain)
5364 RuntimeInvokeFunction runtime_invoke;
5366 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5367 MonoMethod *method = mono_get_context_capture_method ();
5368 MonoMethod *wrapper;
5371 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5372 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5373 domain->capture_context_method = mono_compile_method (method);
5376 runtime_invoke = domain->capture_context_runtime_invoke;
5378 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5381 * mono_async_result_new:
5382 * @domain:domain where the object will be created.
5383 * @handle: wait handle.
5384 * @state: state to pass to AsyncResult
5385 * @data: C closure data.
5387 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5388 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5392 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5394 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5395 MonoObject *context = mono_runtime_capture_context (domain);
5396 /* we must capture the execution context from the original thread */
5398 MONO_OBJECT_SETREF (res, execution_context, context);
5399 /* note: result may be null if the flow is suppressed */
5403 MONO_OBJECT_SETREF (res, object_data, object_data);
5404 MONO_OBJECT_SETREF (res, async_state, state);
5406 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5408 res->sync_completed = FALSE;
5409 res->completed = FALSE;
5415 mono_message_init (MonoDomain *domain,
5416 MonoMethodMessage *this,
5417 MonoReflectionMethod *method,
5418 MonoArray *out_args)
5420 static MonoClass *object_array_klass;
5421 static MonoClass *byte_array_klass;
5422 static MonoClass *string_array_klass;
5423 MonoMethodSignature *sig = mono_method_signature (method->method);
5429 if (!object_array_klass) {
5432 klass = mono_array_class_get (mono_defaults.object_class, 1);
5435 mono_memory_barrier ();
5436 object_array_klass = klass;
5438 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5441 mono_memory_barrier ();
5442 byte_array_klass = klass;
5444 klass = mono_array_class_get (mono_defaults.string_class, 1);
5447 mono_memory_barrier ();
5448 string_array_klass = klass;
5451 MONO_OBJECT_SETREF (this, method, method);
5453 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5454 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5455 this->async_result = NULL;
5456 this->call_type = CallType_Sync;
5458 names = g_new (char *, sig->param_count);
5459 mono_method_get_param_names (method->method, (const char **) names);
5460 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5462 for (i = 0; i < sig->param_count; i++) {
5463 name = mono_string_new (domain, names [i]);
5464 mono_array_setref (this->names, i, name);
5468 for (i = 0, j = 0; i < sig->param_count; i++) {
5469 if (sig->params [i]->byref) {
5471 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5472 mono_array_setref (this->args, i, arg);
5476 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5480 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5483 mono_array_set (this->arg_types, guint8, i, arg_type);
5488 * mono_remoting_invoke:
5489 * @real_proxy: pointer to a RealProxy object
5490 * @msg: The MonoMethodMessage to execute
5491 * @exc: used to store exceptions
5492 * @out_args: used to store output arguments
5494 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5495 * IMessage interface and it is not trivial to extract results from there. So
5496 * we call an helper method PrivateInvoke instead of calling
5497 * RealProxy::Invoke() directly.
5499 * Returns: the result object.
5502 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5503 MonoObject **exc, MonoArray **out_args)
5505 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5508 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5511 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5513 real_proxy->vtable->domain->private_invoke_method = im;
5516 pa [0] = real_proxy;
5521 return mono_runtime_invoke (im, NULL, pa, exc);
5525 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5526 MonoObject **exc, MonoArray **out_args)
5528 static MonoClass *object_array_klass;
5531 MonoMethodSignature *sig;
5533 int i, j, outarg_count = 0;
5535 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5537 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5538 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5539 target = tp->rp->unwrapped_server;
5541 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5545 domain = mono_domain_get ();
5546 method = msg->method->method;
5547 sig = mono_method_signature (method);
5549 for (i = 0; i < sig->param_count; i++) {
5550 if (sig->params [i]->byref)
5554 if (!object_array_klass) {
5557 klass = mono_array_class_get (mono_defaults.object_class, 1);
5560 mono_memory_barrier ();
5561 object_array_klass = klass;
5564 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5565 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5568 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5570 for (i = 0, j = 0; i < sig->param_count; i++) {
5571 if (sig->params [i]->byref) {
5573 arg = mono_array_get (msg->args, gpointer, i);
5574 mono_array_setref (*out_args, j, arg);
5583 * mono_print_unhandled_exception:
5584 * @exc: The exception
5586 * Prints the unhandled exception.
5589 mono_print_unhandled_exception (MonoObject *exc)
5592 char *message = (char *) "";
5596 gboolean free_message = FALSE;
5598 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5599 klass = exc->vtable->klass;
5601 while (klass && method == NULL) {
5602 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5604 klass = klass->parent;
5609 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5611 message = mono_string_to_utf8_checked (str, &error);
5612 if (!mono_error_ok (&error)) {
5613 mono_error_cleanup (&error);
5614 message = (char *)"";
5616 free_message = TRUE;
5622 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5623 * exc->vtable->klass->name, message);
5625 g_printerr ("\nUnhandled Exception: %s\n", message);
5632 * mono_delegate_ctor:
5633 * @this: pointer to an uninitialized delegate object
5634 * @target: target object
5635 * @addr: pointer to native code
5638 * Initialize a delegate and sets a specific method, not the one
5639 * associated with addr. This is useful when sharing generic code.
5640 * In that case addr will most probably not be associated with the
5641 * correct instantiation of the method.
5644 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5646 MonoDelegate *delegate = (MonoDelegate *)this;
5653 delegate->method = method;
5655 class = this->vtable->klass;
5656 mono_stats.delegate_creations++;
5658 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5660 method = mono_marshal_get_remoting_invoke (method);
5661 delegate->method_ptr = mono_compile_method (method);
5662 MONO_OBJECT_SETREF (delegate, target, target);
5663 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5664 method = mono_marshal_get_unbox_wrapper (method);
5665 delegate->method_ptr = mono_compile_method (method);
5666 MONO_OBJECT_SETREF (delegate, target, target);
5668 delegate->method_ptr = addr;
5669 MONO_OBJECT_SETREF (delegate, target, target);
5672 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5676 * mono_delegate_ctor:
5677 * @this: pointer to an uninitialized delegate object
5678 * @target: target object
5679 * @addr: pointer to native code
5681 * This is used to initialize a delegate.
5684 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5686 MonoDomain *domain = mono_domain_get ();
5688 MonoMethod *method = NULL;
5692 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5693 method = ji->method;
5694 g_assert (!method->klass->generic_container);
5697 mono_delegate_ctor_with_method (this, target, addr, method);
5701 * mono_method_call_message_new:
5702 * @method: method to encapsulate
5703 * @params: parameters to the method
5704 * @invoke: optional, delegate invoke.
5705 * @cb: async callback delegate.
5706 * @state: state passed to the async callback.
5708 * Translates arguments pointers into a MonoMethodMessage.
5711 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5712 MonoDelegate **cb, MonoObject **state)
5714 MonoDomain *domain = mono_domain_get ();
5715 MonoMethodSignature *sig = mono_method_signature (method);
5716 MonoMethodMessage *msg;
5719 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5722 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5723 count = sig->param_count - 2;
5725 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5726 count = sig->param_count;
5729 for (i = 0; i < count; i++) {
5734 if (sig->params [i]->byref)
5735 vpos = *((gpointer *)params [i]);
5739 type = sig->params [i]->type;
5740 class = mono_class_from_mono_type (sig->params [i]);
5742 if (class->valuetype)
5743 arg = mono_value_box (domain, class, vpos);
5745 arg = *((MonoObject **)vpos);
5747 mono_array_setref (msg->args, i, arg);
5750 if (cb != NULL && state != NULL) {
5751 *cb = *((MonoDelegate **)params [i]);
5753 *state = *((MonoObject **)params [i]);
5760 * mono_method_return_message_restore:
5762 * Restore results from message based processing back to arguments pointers
5765 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5767 MonoMethodSignature *sig = mono_method_signature (method);
5768 int i, j, type, size, out_len;
5770 if (out_args == NULL)
5772 out_len = mono_array_length (out_args);
5776 for (i = 0, j = 0; i < sig->param_count; i++) {
5777 MonoType *pt = sig->params [i];
5782 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5784 arg = mono_array_get (out_args, gpointer, j);
5787 g_assert (type != MONO_TYPE_VOID);
5789 if (MONO_TYPE_IS_REFERENCE (pt)) {
5790 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5793 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5794 size = mono_class_value_size (class, NULL);
5795 if (class->has_references)
5796 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5798 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5800 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5801 memset (*((gpointer *)params [i]), 0, size);
5811 * mono_load_remote_field:
5812 * @this: pointer to an object
5813 * @klass: klass of the object containing @field
5814 * @field: the field to load
5815 * @res: a storage to store the result
5817 * This method is called by the runtime on attempts to load fields of
5818 * transparent proxy objects. @this points to such TP, @klass is the class of
5819 * the object containing @field. @res is a storage location which can be
5820 * used to store the result.
5822 * Returns: an address pointing to the value of field.
5825 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5827 static MonoMethod *getter = NULL;
5828 MonoDomain *domain = mono_domain_get ();
5829 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5830 MonoClass *field_class;
5831 MonoMethodMessage *msg;
5832 MonoArray *out_args;
5836 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5837 g_assert (res != NULL);
5839 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5840 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5845 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5849 field_class = mono_class_from_mono_type (field->type);
5851 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5852 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5853 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5855 full_name = mono_type_get_full_name (klass);
5856 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5857 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5860 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5862 if (exc) mono_raise_exception ((MonoException *)exc);
5864 if (mono_array_length (out_args) == 0)
5867 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5869 if (field_class->valuetype) {
5870 return ((char *)*res) + sizeof (MonoObject);
5876 * mono_load_remote_field_new:
5881 * Missing documentation.
5884 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5886 static MonoMethod *getter = NULL;
5887 MonoDomain *domain = mono_domain_get ();
5888 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5889 MonoClass *field_class;
5890 MonoMethodMessage *msg;
5891 MonoArray *out_args;
5892 MonoObject *exc, *res;
5895 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5897 field_class = mono_class_from_mono_type (field->type);
5899 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5901 if (field_class->valuetype) {
5902 res = mono_object_new (domain, field_class);
5903 val = ((gchar *) res) + sizeof (MonoObject);
5907 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5912 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5916 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5917 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5919 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5921 full_name = mono_type_get_full_name (klass);
5922 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5923 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5926 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5928 if (exc) mono_raise_exception ((MonoException *)exc);
5930 if (mono_array_length (out_args) == 0)
5933 res = mono_array_get (out_args, MonoObject *, 0);
5939 * mono_store_remote_field:
5940 * @this: pointer to an object
5941 * @klass: klass of the object containing @field
5942 * @field: the field to load
5943 * @val: the value/object to store
5945 * This method is called by the runtime on attempts to store fields of
5946 * transparent proxy objects. @this points to such TP, @klass is the class of
5947 * the object containing @field. @val is the new value to store in @field.
5950 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5952 static MonoMethod *setter = NULL;
5953 MonoDomain *domain = mono_domain_get ();
5954 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5955 MonoClass *field_class;
5956 MonoMethodMessage *msg;
5957 MonoArray *out_args;
5962 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5964 field_class = mono_class_from_mono_type (field->type);
5966 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5967 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5968 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5973 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5977 if (field_class->valuetype)
5978 arg = mono_value_box (domain, field_class, val);
5980 arg = *((MonoObject **)val);
5983 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5984 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5986 full_name = mono_type_get_full_name (klass);
5987 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5988 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5989 mono_array_setref (msg->args, 2, arg);
5992 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5994 if (exc) mono_raise_exception ((MonoException *)exc);
5998 * mono_store_remote_field_new:
6004 * Missing documentation
6007 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6009 static MonoMethod *setter = NULL;
6010 MonoDomain *domain = mono_domain_get ();
6011 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6012 MonoClass *field_class;
6013 MonoMethodMessage *msg;
6014 MonoArray *out_args;
6018 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6020 field_class = mono_class_from_mono_type (field->type);
6022 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6023 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6024 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6029 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6033 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6034 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6036 full_name = mono_type_get_full_name (klass);
6037 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6038 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6039 mono_array_setref (msg->args, 2, arg);
6042 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6044 if (exc) mono_raise_exception ((MonoException *)exc);
6048 * mono_create_ftnptr:
6050 * Given a function address, create a function descriptor for it.
6051 * This is only needed on some platforms.
6054 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6056 return callbacks.create_ftnptr (domain, addr);
6060 * mono_get_addr_from_ftnptr:
6062 * Given a pointer to a function descriptor, return the function address.
6063 * This is only needed on some platforms.
6066 mono_get_addr_from_ftnptr (gpointer descr)
6068 return callbacks.get_addr_from_ftnptr (descr);
6073 * mono_string_chars:
6076 * Returns a pointer to the UCS16 characters stored in the MonoString
6079 mono_string_chars(MonoString *s)
6081 /* This method is here only for documentation extraction, this is a macro */
6085 * mono_string_length:
6088 * Returns the lenght in characters of the string
6091 mono_string_length (MonoString *s)
6093 /* This method is here only for documentation extraction, this is a macro */