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/utils/strenc.h>
42 #include <mono/utils/mono-counters.h>
43 #include <mono/utils/mono-error-internals.h>
44 #include "cominterop.h"
47 #define NEED_TO_ZERO_PTRFREE 1
48 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
49 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
50 #ifdef HAVE_GC_GCJ_MALLOC
51 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
52 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
54 #define GC_NO_DESCRIPTOR (NULL)
55 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
59 #define GC_NO_DESCRIPTOR (NULL)
60 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
61 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
62 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
64 #define NEED_TO_ZERO_PTRFREE 1
65 #define GC_NO_DESCRIPTOR (NULL)
66 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
67 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
68 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
72 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
73 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
76 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
79 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
81 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
82 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
83 static CRITICAL_SECTION ldstr_section;
85 static gboolean profile_allocs = TRUE;
88 mono_runtime_object_init (MonoObject *this)
90 MonoMethod *method = NULL;
91 MonoClass *klass = this->vtable->klass;
93 method = mono_class_get_method_from_name (klass, ".ctor", 0);
96 if (method->klass->valuetype)
97 this = mono_object_unbox (this);
98 mono_runtime_invoke (method, this, NULL, NULL);
101 /* The pseudo algorithm for type initialization from the spec
102 Note it doesn't say anything about domains - only threads.
104 2. If the type is initialized you are done.
105 2.1. If the type is not yet initialized, try to take an
107 2.2. If successful, record this thread as responsible for
108 initializing the type and proceed to step 2.3.
109 2.2.1. If not, see whether this thread or any thread
110 waiting for this thread to complete already holds the lock.
111 2.2.2. If so, return since blocking would create a deadlock. This thread
112 will now see an incompletely initialized state for the type,
113 but no deadlock will arise.
114 2.2.3 If not, block until the type is initialized then return.
115 2.3 Initialize the parent type and then all interfaces implemented
117 2.4 Execute the type initialization code for this type.
118 2.5 Mark the type as initialized, release the initialization lock,
119 awaken any threads waiting for this type to be initialized,
126 guint32 initializing_tid;
127 guint32 waiting_count;
129 CRITICAL_SECTION initialization_section;
130 } TypeInitializationLock;
132 /* for locking access to type_initialization_hash and blocked_thread_hash */
133 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
134 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
135 static CRITICAL_SECTION type_initialization_section;
137 /* from vtable to lock */
138 static GHashTable *type_initialization_hash;
140 /* from thread id to thread id being waited on */
141 static GHashTable *blocked_thread_hash;
144 static MonoThread *main_thread;
146 /* Functions supplied by the runtime */
147 static MonoRuntimeCallbacks callbacks;
150 * mono_thread_set_main:
151 * @thread: thread to set as the main thread
153 * This function can be used to instruct the runtime to treat @thread
154 * as the main thread, ie, the thread that would normally execute the Main()
155 * method. This basically means that at the end of @thread, the runtime will
156 * wait for the existing foreground threads to quit and other such details.
159 mono_thread_set_main (MonoThread *thread)
161 main_thread = thread;
165 mono_thread_get_main (void)
171 mono_type_initialization_init (void)
173 InitializeCriticalSection (&type_initialization_section);
174 type_initialization_hash = g_hash_table_new (NULL, NULL);
175 blocked_thread_hash = g_hash_table_new (NULL, NULL);
176 InitializeCriticalSection (&ldstr_section);
180 mono_type_initialization_cleanup (void)
183 /* This is causing race conditions with
184 * mono_release_type_locks
186 DeleteCriticalSection (&type_initialization_section);
188 DeleteCriticalSection (&ldstr_section);
192 * get_type_init_exception_for_vtable:
194 * Return the stored type initialization exception for VTABLE.
196 static MonoException*
197 get_type_init_exception_for_vtable (MonoVTable *vtable)
199 MonoDomain *domain = vtable->domain;
200 MonoClass *klass = vtable->klass;
204 g_assert (vtable->init_failed);
207 * If the initializing thread was rudely aborted, the exception is not stored
211 mono_domain_lock (domain);
212 if (domain->type_init_exception_hash)
213 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
214 mono_domain_unlock (domain);
217 if (klass->name_space && *klass->name_space)
218 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
220 full_name = g_strdup (klass->name);
221 ex = mono_get_exception_type_initialization (full_name, NULL);
228 * mono_runtime_class_init:
229 * @vtable: vtable that needs to be initialized
231 * This routine calls the class constructor for @vtable.
234 mono_runtime_class_init (MonoVTable *vtable)
236 mono_runtime_class_init_full (vtable, TRUE);
240 * mono_runtime_class_init_full:
241 * @vtable that neeeds to be initialized
242 * @raise_exception is TRUE, exceptions are raised intead of returned
246 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
249 MonoException *exc_to_throw;
250 MonoMethod *method = NULL;
256 if (vtable->initialized)
260 klass = vtable->klass;
262 if (!klass->image->checked_module_cctor) {
263 mono_image_check_for_module_cctor (klass->image);
264 if (klass->image->has_module_cctor) {
265 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
266 MonoVTable *module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
269 mono_runtime_class_init (module_vtable);
272 method = mono_class_get_cctor (klass);
275 MonoDomain *domain = vtable->domain;
276 TypeInitializationLock *lock;
277 guint32 tid = GetCurrentThreadId();
278 int do_initialization = 0;
279 MonoDomain *last_domain = NULL;
281 mono_type_initialization_lock ();
282 /* double check... */
283 if (vtable->initialized) {
284 mono_type_initialization_unlock ();
287 if (vtable->init_failed) {
288 mono_type_initialization_unlock ();
290 /* The type initialization already failed once, rethrow the same exception */
292 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
293 return get_type_init_exception_for_vtable (vtable);
295 lock = g_hash_table_lookup (type_initialization_hash, vtable);
297 /* This thread will get to do the initialization */
298 if (mono_domain_get () != domain) {
299 /* Transfer into the target domain */
300 last_domain = mono_domain_get ();
301 if (!mono_domain_set (domain, FALSE)) {
302 vtable->initialized = 1;
303 mono_type_initialization_unlock ();
305 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
306 return mono_get_exception_appdomain_unloaded ();
309 lock = g_malloc (sizeof(TypeInitializationLock));
310 InitializeCriticalSection (&lock->initialization_section);
311 lock->initializing_tid = tid;
312 lock->waiting_count = 1;
314 /* grab the vtable lock while this thread still owns type_initialization_section */
315 EnterCriticalSection (&lock->initialization_section);
316 g_hash_table_insert (type_initialization_hash, vtable, lock);
317 do_initialization = 1;
320 TypeInitializationLock *pending_lock;
322 if (lock->initializing_tid == tid || lock->done) {
323 mono_type_initialization_unlock ();
326 /* see if the thread doing the initialization is already blocked on this thread */
327 blocked = GUINT_TO_POINTER (lock->initializing_tid);
328 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
329 if (pending_lock->initializing_tid == tid) {
330 if (!pending_lock->done) {
331 mono_type_initialization_unlock ();
334 /* the thread doing the initialization is blocked on this thread,
335 but on a lock that has already been freed. It just hasn't got
340 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
342 ++lock->waiting_count;
343 /* record the fact that we are waiting on the initializing thread */
344 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
346 mono_type_initialization_unlock ();
348 if (do_initialization) {
349 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
351 /* If the initialization failed, mark the class as unusable. */
352 /* Avoid infinite loops */
354 (klass->image == mono_defaults.corlib &&
355 !strcmp (klass->name_space, "System") &&
356 !strcmp (klass->name, "TypeInitializationException")))) {
357 vtable->init_failed = 1;
359 if (klass->name_space && *klass->name_space)
360 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
362 full_name = g_strdup (klass->name);
363 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
367 * Store the exception object so it could be thrown on subsequent
370 mono_domain_lock (domain);
371 if (!domain->type_init_exception_hash)
372 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
373 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
374 mono_domain_unlock (domain);
378 mono_domain_set (last_domain, TRUE);
380 LeaveCriticalSection (&lock->initialization_section);
382 /* this just blocks until the initializing thread is done */
383 EnterCriticalSection (&lock->initialization_section);
384 LeaveCriticalSection (&lock->initialization_section);
387 mono_type_initialization_lock ();
388 if (lock->initializing_tid != tid)
389 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
390 --lock->waiting_count;
391 if (lock->waiting_count == 0) {
392 DeleteCriticalSection (&lock->initialization_section);
393 g_hash_table_remove (type_initialization_hash, vtable);
396 if (!vtable->init_failed)
397 vtable->initialized = 1;
398 mono_type_initialization_unlock ();
400 if (vtable->init_failed) {
401 /* Either we were the initializing thread or we waited for the initialization */
403 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
404 return get_type_init_exception_for_vtable (vtable);
407 vtable->initialized = 1;
414 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
416 MonoVTable *vtable = (MonoVTable*)key;
418 TypeInitializationLock *lock = (TypeInitializationLock*) value;
419 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
422 * Have to set this since it cannot be set by the normal code in
423 * mono_runtime_class_init (). In this case, the exception object is not stored,
424 * and get_type_init_exception_for_class () needs to be aware of this.
426 vtable->init_failed = 1;
427 LeaveCriticalSection (&lock->initialization_section);
428 --lock->waiting_count;
429 if (lock->waiting_count == 0) {
430 DeleteCriticalSection (&lock->initialization_section);
439 mono_release_type_locks (MonoInternalThread *thread)
441 mono_type_initialization_lock ();
442 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
443 mono_type_initialization_unlock ();
447 default_trampoline (MonoMethod *method)
453 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
455 g_assert_not_reached ();
461 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
463 g_error ("remoting not installed");
468 default_delegate_trampoline (MonoClass *klass)
470 g_assert_not_reached ();
474 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
475 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
476 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
477 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
478 static MonoImtThunkBuilder imt_thunk_builder = NULL;
479 #define ARCH_USE_IMT (imt_thunk_builder != NULL)
480 #if (MONO_IMT_SIZE > 32)
481 #error "MONO_IMT_SIZE cannot be larger than 32"
485 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
487 memcpy (&callbacks, cbs, sizeof (*cbs));
490 MonoRuntimeCallbacks*
491 mono_get_runtime_callbacks (void)
497 mono_install_trampoline (MonoTrampoline func)
499 arch_create_jit_trampoline = func? func: default_trampoline;
503 mono_install_jump_trampoline (MonoJumpTrampoline func)
505 arch_create_jump_trampoline = func? func: default_jump_trampoline;
509 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
511 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
515 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
517 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
521 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
522 imt_thunk_builder = func;
525 static MonoCompileFunc default_mono_compile_method = NULL;
528 * mono_install_compile_method:
529 * @func: function to install
531 * This is a VM internal routine
534 mono_install_compile_method (MonoCompileFunc func)
536 default_mono_compile_method = func;
540 * mono_compile_method:
541 * @method: The method to compile.
543 * This JIT-compiles the method, and returns the pointer to the native code
547 mono_compile_method (MonoMethod *method)
549 if (!default_mono_compile_method) {
550 g_error ("compile method called on uninitialized runtime");
553 return default_mono_compile_method (method);
557 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
559 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
563 mono_runtime_create_delegate_trampoline (MonoClass *klass)
565 return arch_create_delegate_trampoline (klass);
568 static MonoFreeMethodFunc default_mono_free_method = NULL;
571 * mono_install_free_method:
572 * @func: pointer to the MonoFreeMethodFunc used to release a method
574 * This is an internal VM routine, it is used for the engines to
575 * register a handler to release the resources associated with a method.
577 * Methods are freed when no more references to the delegate that holds
581 mono_install_free_method (MonoFreeMethodFunc func)
583 default_mono_free_method = func;
587 * mono_runtime_free_method:
588 * @domain; domain where the method is hosted
589 * @method: method to release
591 * This routine is invoked to free the resources associated with
592 * a method that has been JIT compiled. This is used to discard
593 * methods that were used only temporarily (for example, used in marshalling)
597 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
599 if (default_mono_free_method != NULL)
600 default_mono_free_method (domain, method);
602 mono_method_clear_object (domain, method);
604 mono_free_method (method);
608 * The vtables in the root appdomain are assumed to be reachable by other
609 * roots, and we don't use typed allocation in the other domains.
612 /* The sync block is no longer a GC pointer */
613 #define GC_HEADER_BITMAP (0)
615 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
618 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
620 MonoClassField *field;
626 max_size = mono_class_data_size (class) / sizeof (gpointer);
628 max_size = class->instance_size / sizeof (gpointer);
629 if (max_size >= size) {
630 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
633 for (p = class; p != NULL; p = p->parent) {
634 gpointer iter = NULL;
635 while ((field = mono_class_get_fields (p, &iter))) {
639 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
641 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
644 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
647 /* FIXME: should not happen, flag as type load error */
648 if (field->type->byref)
651 if (static_fields && field->offset == -1)
655 pos = field->offset / sizeof (gpointer);
658 type = mono_type_get_underlying_type (field->type);
659 switch (type->type) {
662 case MONO_TYPE_FNPTR:
664 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
669 if (class->image != mono_defaults.corlib)
672 case MONO_TYPE_STRING:
673 case MONO_TYPE_SZARRAY:
674 case MONO_TYPE_CLASS:
675 case MONO_TYPE_OBJECT:
676 case MONO_TYPE_ARRAY:
677 g_assert ((field->offset % sizeof(gpointer)) == 0);
679 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
680 *max_set = MAX (*max_set, pos);
682 case MONO_TYPE_GENERICINST:
683 if (!mono_type_generic_inst_is_valuetype (type)) {
684 g_assert ((field->offset % sizeof(gpointer)) == 0);
686 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
687 *max_set = MAX (*max_set, pos);
692 case MONO_TYPE_VALUETYPE: {
693 MonoClass *fclass = mono_class_from_mono_type (field->type);
694 if (fclass->has_references) {
695 /* remove the object header */
696 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
710 case MONO_TYPE_BOOLEAN:
714 g_assert_not_reached ();
726 * similar to the above, but sets the bits in the bitmap for any non-ref field
727 * and ignores static fields
730 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
732 MonoClassField *field;
737 max_size = class->instance_size / sizeof (gpointer);
738 if (max_size >= size) {
739 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
742 for (p = class; p != NULL; p = p->parent) {
743 gpointer iter = NULL;
744 while ((field = mono_class_get_fields (p, &iter))) {
747 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
749 /* FIXME: should not happen, flag as type load error */
750 if (field->type->byref)
753 pos = field->offset / sizeof (gpointer);
756 type = mono_type_get_underlying_type (field->type);
757 switch (type->type) {
758 #if SIZEOF_VOID_P == 8
762 case MONO_TYPE_FNPTR:
767 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
768 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
769 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
772 #if SIZEOF_VOID_P == 4
776 case MONO_TYPE_FNPTR:
781 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
782 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
783 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
789 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
790 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
791 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
794 case MONO_TYPE_BOOLEAN:
797 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
799 case MONO_TYPE_STRING:
800 case MONO_TYPE_SZARRAY:
801 case MONO_TYPE_CLASS:
802 case MONO_TYPE_OBJECT:
803 case MONO_TYPE_ARRAY:
805 case MONO_TYPE_GENERICINST:
806 if (!mono_type_generic_inst_is_valuetype (type)) {
811 case MONO_TYPE_VALUETYPE: {
812 MonoClass *fclass = mono_class_from_mono_type (field->type);
813 /* remove the object header */
814 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
818 g_assert_not_reached ();
827 * mono_class_insecure_overlapping:
828 * check if a class with explicit layout has references and non-references
829 * fields overlapping.
831 * Returns: TRUE if it is insecure to load the type.
834 mono_class_insecure_overlapping (MonoClass *klass)
838 gsize default_bitmap [4] = {0};
840 gsize default_nrbitmap [4] = {0};
841 int i, insecure = FALSE;
844 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
845 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
847 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
848 int idx = i % (sizeof (bitmap [0]) * 8);
849 if (bitmap [idx] & nrbitmap [idx]) {
854 if (bitmap != default_bitmap)
856 if (nrbitmap != default_nrbitmap)
859 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
867 mono_string_alloc (int length)
869 return mono_string_new_size (mono_domain_get (), length);
873 mono_class_compute_gc_descriptor (MonoClass *class)
877 gsize default_bitmap [4] = {0};
878 static gboolean gcj_inited = FALSE;
883 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
884 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
885 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
886 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
888 #ifdef HAVE_GC_GCJ_MALLOC
890 * This is not needed unless the relevant code in mono_get_allocation_ftn () is
894 #ifdef GC_REDIRECT_TO_LOCAL
895 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
896 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
898 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
899 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
904 mono_loader_unlock ();
908 mono_class_init (class);
910 if (class->gc_descr_inited)
913 class->gc_descr_inited = TRUE;
914 class->gc_descr = GC_NO_DESCRIPTOR;
916 bitmap = default_bitmap;
917 if (class == mono_defaults.string_class) {
918 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
919 } else if (class->rank) {
920 mono_class_compute_gc_descriptor (class->element_class);
921 if (!class->element_class->valuetype) {
923 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
924 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
925 class->name_space, class->name);*/
927 /* remove the object header */
928 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
929 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
930 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
931 class->name_space, class->name);*/
932 if (bitmap != default_bitmap)
936 /*static int count = 0;
939 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
940 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
942 if (class->gc_descr == GC_NO_DESCRIPTOR)
943 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
945 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
946 if (bitmap != default_bitmap)
952 * field_is_special_static:
953 * @fklass: The MonoClass to look up.
954 * @field: The MonoClassField describing the field.
956 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
957 * SPECIAL_STATIC_NONE otherwise.
960 field_is_special_static (MonoClass *fklass, MonoClassField *field)
962 MonoCustomAttrInfo *ainfo;
964 ainfo = mono_custom_attrs_from_field (fklass, field);
967 for (i = 0; i < ainfo->num_attrs; ++i) {
968 MonoClass *klass = ainfo->attrs [i].ctor->klass;
969 if (klass->image == mono_defaults.corlib) {
970 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
971 mono_custom_attrs_free (ainfo);
972 return SPECIAL_STATIC_THREAD;
974 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
975 mono_custom_attrs_free (ainfo);
976 return SPECIAL_STATIC_CONTEXT;
980 mono_custom_attrs_free (ainfo);
981 return SPECIAL_STATIC_NONE;
984 static gpointer imt_trampoline = NULL;
987 mono_install_imt_trampoline (gpointer tramp_code)
989 imt_trampoline = tramp_code;
992 static gpointer vtable_trampoline = NULL;
995 mono_install_vtable_trampoline (gpointer tramp_code)
997 vtable_trampoline = tramp_code;
1000 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1001 #define mix(a,b,c) { \
1002 a -= c; a ^= rot(c, 4); c += b; \
1003 b -= a; b ^= rot(a, 6); a += c; \
1004 c -= b; c ^= rot(b, 8); b += a; \
1005 a -= c; a ^= rot(c,16); c += b; \
1006 b -= a; b ^= rot(a,19); a += c; \
1007 c -= b; c ^= rot(b, 4); b += a; \
1009 #define final(a,b,c) { \
1010 c ^= b; c -= rot(b,14); \
1011 a ^= c; a -= rot(c,11); \
1012 b ^= a; b -= rot(a,25); \
1013 c ^= b; c -= rot(b,16); \
1014 a ^= c; a -= rot(c,4); \
1015 b ^= a; b -= rot(a,14); \
1016 c ^= b; c -= rot(b,24); \
1020 mono_method_get_imt_slot (MonoMethod *method)
1022 MonoMethodSignature *sig;
1024 guint32 *hashes_start, *hashes;
1028 /* This can be used to stress tests the collision code */
1032 * We do this to simplify generic sharing. It will hurt
1033 * performance in cases where a class implements two different
1034 * instantiations of the same generic interface.
1035 * The code in build_imt_slots () depends on this.
1037 if (method->is_inflated)
1038 method = ((MonoMethodInflated*)method)->declaring;
1040 sig = mono_method_signature (method);
1041 hashes_count = sig->param_count + 4;
1042 hashes_start = malloc (hashes_count * sizeof (guint32));
1043 hashes = hashes_start;
1045 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1046 printf ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod\n",
1047 method->klass->name_space, method->klass->name, method->name);
1048 g_assert_not_reached ();
1051 /* Initialize hashes */
1052 hashes [0] = g_str_hash (method->klass->name);
1053 hashes [1] = g_str_hash (method->klass->name_space);
1054 hashes [2] = g_str_hash (method->name);
1055 hashes [3] = mono_metadata_type_hash (sig->ret);
1056 for (i = 0; i < sig->param_count; i++) {
1057 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1060 /* Setup internal state */
1061 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1063 /* Handle most of the hashes */
1064 while (hashes_count > 3) {
1073 /* Handle the last 3 hashes (all the case statements fall through) */
1074 switch (hashes_count) {
1075 case 3 : c += hashes [2];
1076 case 2 : b += hashes [1];
1077 case 1 : a += hashes [0];
1079 case 0: /* nothing left to add */
1083 free (hashes_start);
1084 /* Report the result */
1085 return c % MONO_IMT_SIZE;
1094 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1095 guint32 imt_slot = mono_method_get_imt_slot (method);
1096 MonoImtBuilderEntry *entry;
1098 if (slot_num >= 0 && imt_slot != slot_num) {
1099 /* we build just a single imt slot and this is not it */
1103 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1104 entry->key = method;
1105 entry->value.vtable_slot = vtable_slot;
1106 entry->next = imt_builder [imt_slot];
1107 if (imt_builder [imt_slot] != NULL) {
1108 entry->children = imt_builder [imt_slot]->children + 1;
1109 if (entry->children == 1) {
1110 mono_stats.imt_slots_with_collisions++;
1111 *imt_collisions_bitmap |= (1 << imt_slot);
1114 entry->children = 0;
1115 mono_stats.imt_used_slots++;
1117 imt_builder [imt_slot] = entry;
1119 printf ("Added IMT slot for method (%p) %s.%s.%s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1120 method, method->klass->name_space, method->klass->name,
1121 method->name, imt_slot, vtable_slot, entry->children);
1127 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1129 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1133 e->method->klass->name_space,
1134 e->method->klass->name,
1137 printf (" * %s: NULL\n", message);
1143 compare_imt_builder_entries (const void *p1, const void *p2) {
1144 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1145 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1147 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1151 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1153 int count = end - start;
1154 int chunk_start = out_array->len;
1157 for (i = start; i < end; ++i) {
1158 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1159 item->key = sorted_array [i]->key;
1160 item->value = sorted_array [i]->value;
1161 item->has_target_code = sorted_array [i]->has_target_code;
1162 item->is_equals = TRUE;
1164 item->check_target_idx = out_array->len + 1;
1166 item->check_target_idx = 0;
1167 g_ptr_array_add (out_array, item);
1170 int middle = start + count / 2;
1171 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1173 item->key = sorted_array [middle]->key;
1174 item->is_equals = FALSE;
1175 g_ptr_array_add (out_array, item);
1176 imt_emit_ir (sorted_array, start, middle, out_array);
1177 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1183 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1184 int number_of_entries = entries->children + 1;
1185 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1186 GPtrArray *result = g_ptr_array_new ();
1187 MonoImtBuilderEntry *current_entry;
1190 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1191 sorted_array [i] = current_entry;
1193 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1195 /*for (i = 0; i < number_of_entries; i++) {
1196 print_imt_entry (" sorted array:", sorted_array [i], i);
1199 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1201 free (sorted_array);
1206 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1208 if (imt_builder_entry != NULL) {
1209 if (imt_builder_entry->children == 0 && !fail_tramp) {
1210 /* No collision, return the vtable slot contents */
1211 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1213 /* Collision, build the thunk */
1214 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1217 result = imt_thunk_builder (vtable, domain,
1218 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1219 for (i = 0; i < imt_ir->len; ++i)
1220 g_free (g_ptr_array_index (imt_ir, i));
1221 g_ptr_array_free (imt_ir, TRUE);
1233 static MonoImtBuilderEntry*
1234 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1237 * LOCKING: requires the loader and domain locks.
1241 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1245 guint32 imt_collisions_bitmap = 0;
1246 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1247 int method_count = 0;
1248 gboolean record_method_count_for_max_collisions = FALSE;
1249 gboolean has_generic_virtual = FALSE;
1252 printf ("Building IMT for class %s.%s\n", klass->name_space, klass->name);
1254 for (i = 0; i < klass->interface_offsets_count; ++i) {
1255 MonoClass *iface = klass->interfaces_packed [i];
1256 int interface_offset = klass->interface_offsets_packed [i];
1257 int method_slot_in_interface;
1258 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1261 if (slot_num >= 0 && iface->is_inflated) {
1263 * The imt slot of the method is the same as for its declaring method,
1264 * see the comment in mono_method_get_imt_slot (), so we can
1265 * avoid inflating methods which will be discarded by
1266 * add_imt_builder_entry anyway.
1268 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1269 if (mono_method_get_imt_slot (method) != slot_num)
1272 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1273 if (method->is_generic) {
1274 has_generic_virtual = TRUE;
1277 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1280 if (extra_interfaces) {
1281 int interface_offset = klass->vtable_size;
1283 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1284 MonoClass* iface = list_item->data;
1285 int method_slot_in_interface;
1286 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1287 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1288 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1290 interface_offset += iface->method.count;
1293 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1294 /* overwrite the imt slot only if we're building all the entries or if
1295 * we're building this specific one
1297 if (slot_num < 0 || i == slot_num) {
1298 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1301 if (imt_builder [i]) {
1302 MonoImtBuilderEntry *entry;
1304 /* Link entries with imt_builder [i] */
1305 for (entry = entries; entry->next; entry = entry->next)
1307 entry->next = imt_builder [i];
1308 entries->children += imt_builder [i]->children + 1;
1310 imt_builder [i] = entries;
1313 if (has_generic_virtual) {
1315 * There might be collisions later when the the thunk is expanded.
1317 imt_collisions_bitmap |= (1 << i);
1320 * The IMT thunk might be called with an instance of one of the
1321 * generic virtual methods, so has to fallback to the IMT trampoline.
1323 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], imt_trampoline);
1325 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1329 printf ("initialize_imt_slot[%d]: %p\n", i, imt [i]);
1331 if (imt_builder [i] != NULL) {
1332 int methods_in_slot = imt_builder [i]->children + 1;
1333 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1334 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1335 record_method_count_for_max_collisions = TRUE;
1337 method_count += methods_in_slot;
1341 mono_stats.imt_number_of_methods += method_count;
1342 if (record_method_count_for_max_collisions) {
1343 mono_stats.imt_method_count_when_max_collisions = method_count;
1346 for (i = 0; i < MONO_IMT_SIZE; i++) {
1347 MonoImtBuilderEntry* entry = imt_builder [i];
1348 while (entry != NULL) {
1349 MonoImtBuilderEntry* next = entry->next;
1355 /* we OR the bitmap since we may build just a single imt slot at a time */
1356 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1360 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1361 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1365 * mono_vtable_build_imt_slot:
1366 * @vtable: virtual object table struct
1367 * @imt_slot: slot in the IMT table
1369 * Fill the given @imt_slot in the IMT table of @vtable with
1370 * a trampoline or a thunk for the case of collisions.
1371 * This is part of the internal mono API.
1373 * LOCKING: Take the domain lock.
1376 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1378 gpointer *imt = (gpointer*)vtable;
1379 imt -= MONO_IMT_SIZE;
1380 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1382 /* no support for extra interfaces: the proxy objects will need
1383 * to build the complete IMT
1384 * Update and heck needs to ahppen inside the proper domain lock, as all
1385 * the changes made to a MonoVTable.
1387 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1388 mono_domain_lock (vtable->domain);
1389 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1390 if (imt [imt_slot] == imt_trampoline)
1391 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1392 mono_domain_unlock (vtable->domain);
1393 mono_loader_unlock ();
1398 * The first two free list entries both belong to the wait list: The
1399 * first entry is the pointer to the head of the list and the second
1400 * entry points to the last element. That way appending and removing
1401 * the first element are both O(1) operations.
1403 #define NUM_FREE_LISTS 12
1404 #define FIRST_FREE_LIST_SIZE 64
1405 #define MAX_WAIT_LENGTH 50
1406 #define THUNK_THRESHOLD 10
1409 * LOCKING: The domain lock must be held.
1412 init_thunk_free_lists (MonoDomain *domain)
1414 if (domain->thunk_free_lists)
1416 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1420 list_index_for_size (int item_size)
1423 int size = FIRST_FREE_LIST_SIZE;
1425 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1434 * mono_method_alloc_generic_virtual_thunk:
1436 * @size: size in bytes
1438 * Allocs size bytes to be used for the code of a generic virtual
1439 * thunk. It's either allocated from the domain's code manager or
1440 * reused from a previously invalidated piece.
1442 * LOCKING: The domain lock must be held.
1445 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1447 static gboolean inited = FALSE;
1448 static int generic_virtual_thunks_size = 0;
1452 MonoThunkFreeList **l;
1454 init_thunk_free_lists (domain);
1456 size += sizeof (guint32);
1457 if (size < sizeof (MonoThunkFreeList))
1458 size = sizeof (MonoThunkFreeList);
1460 i = list_index_for_size (size);
1461 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1462 if ((*l)->size >= size) {
1463 MonoThunkFreeList *item = *l;
1465 return ((guint32*)item) + 1;
1469 /* no suitable item found - search lists of larger sizes */
1470 while (++i < NUM_FREE_LISTS) {
1471 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1474 g_assert (item->size > size);
1475 domain->thunk_free_lists [i] = item->next;
1476 return ((guint32*)item) + 1;
1479 /* still nothing found - allocate it */
1481 mono_counters_register ("Generic virtual thunk bytes",
1482 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1485 generic_virtual_thunks_size += size;
1487 p = mono_domain_code_reserve (domain, size);
1494 * LOCKING: The domain lock must be held.
1497 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1500 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1502 init_thunk_free_lists (domain);
1504 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1505 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1506 int length = item->length;
1509 /* unlink the first item from the wait list */
1510 domain->thunk_free_lists [0] = item->next;
1511 domain->thunk_free_lists [0]->length = length - 1;
1513 i = list_index_for_size (item->size);
1515 /* put it in the free list */
1516 item->next = domain->thunk_free_lists [i];
1517 domain->thunk_free_lists [i] = item;
1521 if (domain->thunk_free_lists [1]) {
1522 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1523 domain->thunk_free_lists [0]->length++;
1525 g_assert (!domain->thunk_free_lists [0]);
1527 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1528 domain->thunk_free_lists [0]->length = 1;
1532 typedef struct _GenericVirtualCase {
1536 struct _GenericVirtualCase *next;
1537 } GenericVirtualCase;
1540 * get_generic_virtual_entries:
1542 * Return IMT entries for the generic virtual method instances for vtable slot
1545 static MonoImtBuilderEntry*
1546 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1548 GenericVirtualCase *list;
1549 MonoImtBuilderEntry *entries;
1551 mono_domain_lock (domain);
1552 if (!domain->generic_virtual_cases)
1553 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1555 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1558 for (; list; list = list->next) {
1559 MonoImtBuilderEntry *entry;
1561 if (list->count < THUNK_THRESHOLD)
1564 entry = g_new0 (MonoImtBuilderEntry, 1);
1565 entry->key = list->method;
1566 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1567 entry->has_target_code = 1;
1569 entry->children = entries->children + 1;
1570 entry->next = entries;
1574 mono_domain_unlock (domain);
1576 /* FIXME: Leaking memory ? */
1581 * mono_method_add_generic_virtual_invocation:
1583 * @vtable_slot: pointer to the vtable slot
1584 * @method: the inflated generic virtual method
1585 * @code: the method's code
1587 * Registers a call via unmanaged code to a generic virtual method
1588 * instantiation. If the number of calls reaches a threshold
1589 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1590 * virtual method thunk.
1593 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1594 gpointer *vtable_slot,
1595 MonoMethod *method, gpointer code)
1597 static gboolean inited = FALSE;
1598 static int num_added = 0;
1600 GenericVirtualCase *gvc, *list;
1601 MonoImtBuilderEntry *entries;
1605 mono_domain_lock (domain);
1606 if (!domain->generic_virtual_cases)
1607 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1609 /* Check whether the case was already added */
1610 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1613 if (gvc->method == method)
1618 /* If not found, make a new one */
1620 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1621 gvc->method = method;
1624 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1626 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1629 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1635 if (++gvc->count == THUNK_THRESHOLD) {
1636 gpointer *old_thunk = *vtable_slot;
1638 if ((gpointer)vtable_slot < (gpointer)vtable)
1639 /* Force the rebuild of the thunk at the next call */
1640 *vtable_slot = imt_trampoline;
1642 entries = get_generic_virtual_entries (domain, vtable_slot);
1644 sorted = imt_sort_slot_entries (entries);
1646 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1650 MonoImtBuilderEntry *next = entries->next;
1655 for (i = 0; i < sorted->len; ++i)
1656 g_free (g_ptr_array_index (sorted, i));
1657 g_ptr_array_free (sorted, TRUE);
1660 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1661 invalidate_generic_virtual_thunk (domain, old_thunk);
1664 mono_domain_unlock (domain);
1667 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1670 * mono_class_vtable:
1671 * @domain: the application domain
1672 * @class: the class to initialize
1674 * VTables are domain specific because we create domain specific code, and
1675 * they contain the domain specific static class data.
1676 * On failure, NULL is returned, and class->exception_type is set.
1679 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1681 return mono_class_vtable_full (domain, class, FALSE);
1685 * mono_class_vtable_full:
1686 * @domain: the application domain
1687 * @class: the class to initialize
1688 * @raise_on_error if an exception should be raised on failure or not
1690 * VTables are domain specific because we create domain specific code, and
1691 * they contain the domain specific static class data.
1694 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1696 MonoClassRuntimeInfo *runtime_info;
1700 if (class->exception_type) {
1702 mono_raise_exception (mono_class_get_exception_for_failure (class));
1706 /* this check can be inlined in jitted code, too */
1707 runtime_info = class->runtime_info;
1708 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1709 return runtime_info->domain_vtables [domain->domain_id];
1710 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1714 * mono_class_try_get_vtable:
1715 * @domain: the application domain
1716 * @class: the class to initialize
1718 * This function tries to get the associated vtable from @class if
1719 * it was already created.
1722 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1724 MonoClassRuntimeInfo *runtime_info;
1728 runtime_info = class->runtime_info;
1729 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1730 return runtime_info->domain_vtables [domain->domain_id];
1735 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1738 MonoClassRuntimeInfo *runtime_info, *old_info;
1739 MonoClassField *field;
1742 int imt_table_bytes = 0;
1743 guint32 vtable_size, class_size;
1746 gpointer *interface_offsets;
1748 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1749 mono_domain_lock (domain);
1750 runtime_info = class->runtime_info;
1751 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1752 mono_domain_unlock (domain);
1753 mono_loader_unlock ();
1754 return runtime_info->domain_vtables [domain->domain_id];
1756 if (!class->inited || class->exception_type) {
1757 if (!mono_class_init (class) || class->exception_type) {
1758 mono_domain_unlock (domain);
1759 mono_loader_unlock ();
1761 mono_raise_exception (mono_class_get_exception_for_failure (class));
1766 /* Array types require that their element type be valid*/
1767 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1768 MonoClass *element_class = class->element_class;
1769 if (!element_class->inited)
1770 mono_class_init (element_class);
1772 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1773 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1774 mono_class_setup_vtable (element_class);
1776 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1777 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1778 if (class->exception_type == MONO_EXCEPTION_NONE)
1779 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1780 mono_domain_unlock (domain);
1781 mono_loader_unlock ();
1783 mono_raise_exception (mono_class_get_exception_for_failure (class));
1789 * For some classes, mono_class_init () already computed class->vtable_size, and
1790 * that is all that is needed because of the vtable trampolines.
1792 if (!class->vtable_size)
1793 mono_class_setup_vtable (class);
1795 if (class->exception_type) {
1796 mono_domain_unlock (domain);
1797 mono_loader_unlock ();
1799 mono_raise_exception (mono_class_get_exception_for_failure (class));
1804 vtable_size = MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1805 if (class->interface_offsets_count) {
1806 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1807 vtable_size += sizeof (gpointer) * (MONO_IMT_SIZE);
1808 mono_stats.imt_number_of_tables++;
1809 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
1812 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
1813 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
1816 mono_stats.used_class_count++;
1817 mono_stats.class_vtable_size += vtable_size;
1818 interface_offsets = mono_domain_alloc0 (domain, vtable_size);
1821 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1823 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
1825 vt->rank = class->rank;
1826 vt->domain = domain;
1828 mono_class_compute_gc_descriptor (class);
1830 * We can't use typed allocation in the non-root domains, since the
1831 * collector needs the GC descriptor stored in the vtable even after
1832 * the mempool containing the vtable is destroyed when the domain is
1833 * unloaded. An alternative might be to allocate vtables in the GC
1834 * heap, but this does not seem to work (it leads to crashes inside
1835 * libgc). If that approach is tried, two gc descriptors need to be
1836 * allocated for each class: one for the root domain, and one for all
1837 * other domains. The second descriptor should contain a bit for the
1838 * vtable field in MonoObject, since we can no longer assume the
1839 * vtable is reachable by other roots after the appdomain is unloaded.
1841 #ifdef HAVE_BOEHM_GC
1842 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1843 vt->gc_descr = GC_NO_DESCRIPTOR;
1846 vt->gc_descr = class->gc_descr;
1848 if ((class_size = mono_class_data_size (class))) {
1849 if (class->has_static_refs) {
1850 gpointer statics_gc_descr;
1852 gsize default_bitmap [4] = {0};
1855 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1856 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1857 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1858 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1859 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1860 if (bitmap != default_bitmap)
1863 vt->data = mono_domain_alloc0 (domain, class_size);
1865 mono_stats.class_static_data_size += class_size;
1870 while ((field = mono_class_get_fields (class, &iter))) {
1871 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1873 if (mono_field_is_deleted (field))
1875 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1876 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1877 if (special_static != SPECIAL_STATIC_NONE) {
1878 guint32 size, offset;
1880 size = mono_type_size (field->type, &align);
1881 offset = mono_alloc_special_static_data (special_static, size, align);
1882 if (!domain->special_static_fields)
1883 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1884 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1886 * This marks the field as special static to speed up the
1887 * checks in mono_field_static_get/set_value ().
1893 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1894 MonoClass *fklass = mono_class_from_mono_type (field->type);
1895 const char *data = mono_field_get_data (field);
1897 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1898 t = (char*)vt->data + field->offset;
1899 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
1902 if (fklass->valuetype) {
1903 memcpy (t, data, mono_class_value_size (fklass, NULL));
1905 /* it's a pointer type: add check */
1906 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1913 vt->max_interface_id = class->max_interface_id;
1914 vt->interface_bitmap = class->interface_bitmap;
1916 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
1917 // class->name, class->interface_offsets_count);
1919 if (! ARCH_USE_IMT) {
1920 /* initialize interface offsets */
1921 for (i = 0; i < class->interface_offsets_count; ++i) {
1922 int interface_id = class->interfaces_packed [i]->interface_id;
1923 int slot = class->interface_offsets_packed [i];
1924 interface_offsets [class->max_interface_id - interface_id] = &(vt->vtable [slot]);
1928 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1929 * as we change the code in appdomain.c to invalidate vtables by
1930 * looking at the possible MonoClasses created for the domain.
1932 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1933 /* class->runtime_info is protected by the loader lock, both when
1934 * it it enlarged and when it is stored info.
1937 old_info = class->runtime_info;
1938 if (old_info && old_info->max_domain >= domain->domain_id) {
1939 /* someone already created a large enough runtime info */
1940 mono_memory_barrier ();
1941 old_info->domain_vtables [domain->domain_id] = vt;
1943 int new_size = domain->domain_id;
1945 new_size = MAX (new_size, old_info->max_domain);
1947 /* make the new size a power of two */
1949 while (new_size > i)
1952 /* this is a bounded memory retention issue: may want to
1953 * handle it differently when we'll have a rcu-like system.
1955 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
1956 runtime_info->max_domain = new_size - 1;
1957 /* copy the stuff from the older info */
1959 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1961 runtime_info->domain_vtables [domain->domain_id] = vt;
1963 mono_memory_barrier ();
1964 class->runtime_info = runtime_info;
1967 /* Initialize vtable */
1968 if (vtable_trampoline) {
1969 // This also covers the AOT case
1970 for (i = 0; i < class->vtable_size; ++i) {
1971 vt->vtable [i] = vtable_trampoline;
1974 mono_class_setup_vtable (class);
1976 for (i = 0; i < class->vtable_size; ++i) {
1979 if ((cm = class->vtable [i]))
1980 vt->vtable [i] = vtable_trampoline? vtable_trampoline: arch_create_jit_trampoline (cm);
1984 if (ARCH_USE_IMT && imt_table_bytes) {
1985 /* Now that the vtable is full, we can actually fill up the IMT */
1986 if (imt_trampoline) {
1987 /* lazy construction of the IMT entries enabled */
1988 for (i = 0; i < MONO_IMT_SIZE; ++i)
1989 interface_offsets [i] = imt_trampoline;
1991 build_imt (class, vt, domain, interface_offsets, NULL);
1995 mono_domain_unlock (domain);
1996 mono_loader_unlock ();
1998 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1999 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND) && raise_on_error)
2000 mono_raise_exception (mono_class_get_exception_for_failure (class));
2002 /* make sure the parent is initialized */
2003 /*FIXME shouldn't this fail the current type?*/
2005 mono_class_vtable_full (domain, class->parent, raise_on_error);
2007 /*FIXME check for OOM*/
2008 vt->type = mono_type_get_object (domain, &class->byval_arg);
2009 if (class->contextbound)
2018 * mono_class_proxy_vtable:
2019 * @domain: the application domain
2020 * @remove_class: the remote class
2022 * Creates a vtable for transparent proxies. It is basically
2023 * a copy of the real vtable of the class wrapped in @remote_class,
2024 * but all function pointers invoke the remoting functions, and
2025 * vtable->klass points to the transparent proxy class, and not to @class.
2028 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2030 MonoVTable *vt, *pvt;
2031 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2033 GSList *extra_interfaces = NULL;
2034 MonoClass *class = remote_class->proxy_class;
2035 gpointer *interface_offsets;
2037 vt = mono_class_vtable (domain, class);
2038 g_assert (vt); /*FIXME property handle failure*/
2039 max_interface_id = vt->max_interface_id;
2041 /* Calculate vtable space for extra interfaces */
2042 for (j = 0; j < remote_class->interface_count; j++) {
2043 MonoClass* iclass = remote_class->interfaces[j];
2047 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2048 continue; /* interface implemented by the class */
2049 if (g_slist_find (extra_interfaces, iclass))
2052 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2054 method_count = mono_class_num_methods (iclass);
2056 ifaces = mono_class_get_implemented_interfaces (iclass);
2058 for (i = 0; i < ifaces->len; ++i) {
2059 MonoClass *ic = g_ptr_array_index (ifaces, i);
2060 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2061 continue; /* interface implemented by the class */
2062 if (g_slist_find (extra_interfaces, ic))
2064 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2065 method_count += mono_class_num_methods (ic);
2067 g_ptr_array_free (ifaces, TRUE);
2070 extra_interface_vtsize += method_count * sizeof (gpointer);
2071 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2075 mono_stats.imt_number_of_tables++;
2076 mono_stats.imt_tables_size += (sizeof (gpointer) * MONO_IMT_SIZE);
2077 vtsize = sizeof (gpointer) * (MONO_IMT_SIZE) +
2078 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2080 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
2081 MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2084 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2086 interface_offsets = mono_domain_alloc0 (domain, vtsize + extra_interface_vtsize);
2088 pvt = (MonoVTable*) (interface_offsets + MONO_IMT_SIZE);
2090 pvt = (MonoVTable*) (interface_offsets + max_interface_id + 1);
2091 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2093 pvt->klass = mono_defaults.transparent_proxy_class;
2094 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2095 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2097 /* initialize vtable */
2098 mono_class_setup_vtable (class);
2099 for (i = 0; i < class->vtable_size; ++i) {
2102 if ((cm = class->vtable [i]))
2103 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2105 pvt->vtable [i] = NULL;
2108 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2109 /* create trampolines for abstract methods */
2110 for (k = class; k; k = k->parent) {
2112 gpointer iter = NULL;
2113 while ((m = mono_class_get_methods (k, &iter)))
2114 if (!pvt->vtable [m->slot])
2115 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2119 pvt->max_interface_id = max_interface_id;
2120 pvt->interface_bitmap = mono_domain_alloc0 (domain, sizeof (guint8) * (max_interface_id/8 + 1 ));
2122 if (! ARCH_USE_IMT) {
2123 /* initialize interface offsets */
2124 for (i = 0; i < class->interface_offsets_count; ++i) {
2125 int interface_id = class->interfaces_packed [i]->interface_id;
2126 int slot = class->interface_offsets_packed [i];
2127 interface_offsets [class->max_interface_id - interface_id] = &(pvt->vtable [slot]);
2130 for (i = 0; i < class->interface_offsets_count; ++i) {
2131 int interface_id = class->interfaces_packed [i]->interface_id;
2132 pvt->interface_bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2135 if (extra_interfaces) {
2136 int slot = class->vtable_size;
2142 /* Create trampolines for the methods of the interfaces */
2143 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2144 interf = list_item->data;
2146 if (! ARCH_USE_IMT) {
2147 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
2149 pvt->interface_bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2153 while ((cm = mono_class_get_methods (interf, &iter)))
2154 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2156 slot += mono_class_num_methods (interf);
2158 if (! ARCH_USE_IMT) {
2159 g_slist_free (extra_interfaces);
2164 /* Now that the vtable is full, we can actually fill up the IMT */
2165 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2166 if (extra_interfaces) {
2167 g_slist_free (extra_interfaces);
2175 * mono_class_field_is_special_static:
2177 * Returns whether @field is a thread/context static field.
2180 mono_class_field_is_special_static (MonoClassField *field)
2182 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2184 if (mono_field_is_deleted (field))
2186 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2187 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2194 * mono_class_has_special_static_fields:
2196 * Returns whenever @klass has any thread/context static fields.
2199 mono_class_has_special_static_fields (MonoClass *klass)
2201 MonoClassField *field;
2205 while ((field = mono_class_get_fields (klass, &iter))) {
2206 g_assert (field->parent == klass);
2207 if (mono_class_field_is_special_static (field))
2215 * create_remote_class_key:
2216 * Creates an array of pointers that can be used as a hash key for a remote class.
2217 * The first element of the array is the number of pointers.
2220 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2225 if (remote_class == NULL) {
2226 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2227 key = g_malloc (sizeof(gpointer) * 3);
2228 key [0] = GINT_TO_POINTER (2);
2229 key [1] = mono_defaults.marshalbyrefobject_class;
2230 key [2] = extra_class;
2232 key = g_malloc (sizeof(gpointer) * 2);
2233 key [0] = GINT_TO_POINTER (1);
2234 key [1] = extra_class;
2237 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2238 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2239 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2240 key [1] = remote_class->proxy_class;
2242 // Keep the list of interfaces sorted
2243 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2244 if (extra_class && remote_class->interfaces [i] > extra_class) {
2245 key [j++] = extra_class;
2248 key [j] = remote_class->interfaces [i];
2251 key [j] = extra_class;
2253 // Replace the old class. The interface list is the same
2254 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2255 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2256 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2257 for (i = 0; i < remote_class->interface_count; i++)
2258 key [2 + i] = remote_class->interfaces [i];
2266 * copy_remote_class_key:
2268 * Make a copy of KEY in the domain and return the copy.
2271 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2273 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2274 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2276 memcpy (mp_key, key, key_size);
2282 * mono_remote_class:
2283 * @domain: the application domain
2284 * @class_name: name of the remote class
2286 * Creates and initializes a MonoRemoteClass object for a remote type.
2288 * Can raise an exception on failure.
2291 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2294 MonoRemoteClass *rc;
2295 gpointer* key, *mp_key;
2298 key = create_remote_class_key (NULL, proxy_class);
2300 mono_domain_lock (domain);
2301 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2305 mono_domain_unlock (domain);
2309 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2310 if (!mono_error_ok (&error)) {
2312 mono_domain_unlock (domain);
2313 mono_error_raise_exception (&error);
2316 mp_key = copy_remote_class_key (domain, key);
2320 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2321 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2322 rc->interface_count = 1;
2323 rc->interfaces [0] = proxy_class;
2324 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2326 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2327 rc->interface_count = 0;
2328 rc->proxy_class = proxy_class;
2331 rc->default_vtable = NULL;
2332 rc->xdomain_vtable = NULL;
2333 rc->proxy_class_name = name;
2334 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2336 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2338 mono_domain_unlock (domain);
2343 * clone_remote_class:
2344 * Creates a copy of the remote_class, adding the provided class or interface
2346 static MonoRemoteClass*
2347 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2349 MonoRemoteClass *rc;
2350 gpointer* key, *mp_key;
2352 key = create_remote_class_key (remote_class, extra_class);
2353 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2359 mp_key = copy_remote_class_key (domain, key);
2363 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2365 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2366 rc->proxy_class = remote_class->proxy_class;
2367 rc->interface_count = remote_class->interface_count + 1;
2369 // Keep the list of interfaces sorted, since the hash key of
2370 // the remote class depends on this
2371 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2372 if (remote_class->interfaces [i] > extra_class && i == j)
2373 rc->interfaces [j++] = extra_class;
2374 rc->interfaces [j] = remote_class->interfaces [i];
2377 rc->interfaces [j] = extra_class;
2379 // Replace the old class. The interface array is the same
2380 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2381 rc->proxy_class = extra_class;
2382 rc->interface_count = remote_class->interface_count;
2383 if (rc->interface_count > 0)
2384 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2387 rc->default_vtable = NULL;
2388 rc->xdomain_vtable = NULL;
2389 rc->proxy_class_name = remote_class->proxy_class_name;
2391 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2397 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2399 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2400 mono_domain_lock (domain);
2401 if (rp->target_domain_id != -1) {
2402 if (remote_class->xdomain_vtable == NULL)
2403 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2404 mono_domain_unlock (domain);
2405 mono_loader_unlock ();
2406 return remote_class->xdomain_vtable;
2408 if (remote_class->default_vtable == NULL) {
2411 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2412 klass = mono_class_from_mono_type (type);
2413 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2414 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2416 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2419 mono_domain_unlock (domain);
2420 mono_loader_unlock ();
2421 return remote_class->default_vtable;
2425 * mono_upgrade_remote_class:
2426 * @domain: the application domain
2427 * @tproxy: the proxy whose remote class has to be upgraded.
2428 * @klass: class to which the remote class can be casted.
2430 * Updates the vtable of the remote class by adding the necessary method slots
2431 * and interface offsets so it can be safely casted to klass. klass can be a
2432 * class or an interface.
2435 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2437 MonoTransparentProxy *tproxy;
2438 MonoRemoteClass *remote_class;
2439 gboolean redo_vtable;
2441 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2442 mono_domain_lock (domain);
2444 tproxy = (MonoTransparentProxy*) proxy_object;
2445 remote_class = tproxy->remote_class;
2447 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2450 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2451 if (remote_class->interfaces [i] == klass)
2452 redo_vtable = FALSE;
2455 redo_vtable = (remote_class->proxy_class != klass);
2459 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2460 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2463 mono_domain_unlock (domain);
2464 mono_loader_unlock ();
2469 * mono_object_get_virtual_method:
2470 * @obj: object to operate on.
2473 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2474 * the instance of a callvirt of method.
2477 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2480 MonoMethod **vtable;
2482 MonoMethod *res = NULL;
2484 klass = mono_object_class (obj);
2485 if (klass == mono_defaults.transparent_proxy_class) {
2486 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2492 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2495 mono_class_setup_vtable (klass);
2496 vtable = klass->vtable;
2498 if (method->slot == -1) {
2499 /* method->slot might not be set for instances of generic methods */
2500 if (method->is_inflated) {
2501 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2502 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2505 g_assert_not_reached ();
2509 /* check method->slot is a valid index: perform isinstance? */
2510 if (method->slot != -1) {
2511 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2513 res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2515 res = vtable [method->slot];
2520 /* It may be an interface, abstract class method or generic method */
2521 if (!res || mono_method_signature (res)->generic_param_count)
2524 /* generic methods demand invoke_with_check */
2525 if (mono_method_signature (res)->generic_param_count)
2526 res = mono_marshal_get_remoting_invoke_with_check (res);
2529 if (klass == mono_defaults.com_object_class || klass->is_com_object)
2530 res = mono_cominterop_get_invoke (res);
2533 res = mono_marshal_get_remoting_invoke (res);
2536 if (method->is_inflated) {
2537 /* Have to inflate the result */
2538 res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2548 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2550 g_error ("runtime invoke called on uninitialized runtime");
2554 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2557 * mono_runtime_invoke:
2558 * @method: method to invoke
2559 * @obJ: object instance
2560 * @params: arguments to the method
2561 * @exc: exception information.
2563 * Invokes the method represented by @method on the object @obj.
2565 * obj is the 'this' pointer, it should be NULL for static
2566 * methods, a MonoObject* for object instances and a pointer to
2567 * the value type for value types.
2569 * The params array contains the arguments to the method with the
2570 * same convention: MonoObject* pointers for object instances and
2571 * pointers to the value type otherwise.
2573 * From unmanaged code you'll usually use the
2574 * mono_runtime_invoke() variant.
2576 * Note that this function doesn't handle virtual methods for
2577 * you, it will exec the exact method you pass: we still need to
2578 * expose a function to lookup the derived class implementation
2579 * of a virtual method (there are examples of this in the code,
2582 * You can pass NULL as the exc argument if you don't want to
2583 * catch exceptions, otherwise, *exc will be set to the exception
2584 * thrown, if any. if an exception is thrown, you can't use the
2585 * MonoObject* result from the function.
2587 * If the method returns a value type, it is boxed in an object
2591 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2595 if (mono_runtime_get_no_exec ())
2596 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2598 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2599 mono_profiler_method_start_invoke (method);
2601 result = default_mono_runtime_invoke (method, obj, params, exc);
2603 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2604 mono_profiler_method_end_invoke (method);
2610 * mono_method_get_unmanaged_thunk:
2611 * @method: method to generate a thunk for.
2613 * Returns an unmanaged->managed thunk that can be used to call
2614 * a managed method directly from C.
2616 * The thunk's C signature closely matches the managed signature:
2618 * C#: public bool Equals (object obj);
2619 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2620 * MonoObject*, MonoException**);
2622 * The 1st ("this") parameter must not be used with static methods:
2624 * C#: public static bool ReferenceEquals (object a, object b);
2625 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2628 * The last argument must be a non-null pointer of a MonoException* pointer.
2629 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2630 * exception has been thrown in managed code. Otherwise it will point
2631 * to the MonoException* caught by the thunk. In this case, the result of
2632 * the thunk is undefined:
2634 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2635 * MonoException *ex = NULL;
2636 * Equals func = mono_method_get_unmanaged_thunk (method);
2637 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2639 * // handle exception
2642 * The calling convention of the thunk matches the platform's default
2643 * convention. This means that under Windows, C declarations must
2644 * contain the __stdcall attribute:
2646 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2647 * MonoObject*, MonoException**);
2651 * Value type arguments and return values are treated as they were objects:
2653 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2654 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2656 * Arguments must be properly boxed upon trunk's invocation, while return
2657 * values must be unboxed.
2660 mono_method_get_unmanaged_thunk (MonoMethod *method)
2662 method = mono_marshal_get_thunk_invoke_wrapper (method);
2663 return mono_compile_method (method);
2667 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2671 /* object fields cannot be byref, so we don't need a
2673 gpointer *p = (gpointer*)dest;
2680 case MONO_TYPE_BOOLEAN:
2682 case MONO_TYPE_U1: {
2683 guint8 *p = (guint8*)dest;
2684 *p = value ? *(guint8*)value : 0;
2689 case MONO_TYPE_CHAR: {
2690 guint16 *p = (guint16*)dest;
2691 *p = value ? *(guint16*)value : 0;
2694 #if SIZEOF_VOID_P == 4
2699 case MONO_TYPE_U4: {
2700 gint32 *p = (gint32*)dest;
2701 *p = value ? *(gint32*)value : 0;
2704 #if SIZEOF_VOID_P == 8
2709 case MONO_TYPE_U8: {
2710 gint64 *p = (gint64*)dest;
2711 *p = value ? *(gint64*)value : 0;
2714 case MONO_TYPE_R4: {
2715 float *p = (float*)dest;
2716 *p = value ? *(float*)value : 0;
2719 case MONO_TYPE_R8: {
2720 double *p = (double*)dest;
2721 *p = value ? *(double*)value : 0;
2724 case MONO_TYPE_STRING:
2725 case MONO_TYPE_SZARRAY:
2726 case MONO_TYPE_CLASS:
2727 case MONO_TYPE_OBJECT:
2728 case MONO_TYPE_ARRAY:
2729 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2731 case MONO_TYPE_FNPTR:
2732 case MONO_TYPE_PTR: {
2733 gpointer *p = (gpointer*)dest;
2734 *p = deref_pointer? *(gpointer*)value: value;
2737 case MONO_TYPE_VALUETYPE:
2738 /* note that 't' and 'type->type' can be different */
2739 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2740 t = mono_class_enum_basetype (type->data.klass)->type;
2743 MonoClass *class = mono_class_from_mono_type (type);
2744 int size = mono_class_value_size (class, NULL);
2746 memset (dest, 0, size);
2748 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2751 case MONO_TYPE_GENERICINST:
2752 t = type->data.generic_class->container_class->byval_arg.type;
2755 g_warning ("got type %x", type->type);
2756 g_assert_not_reached ();
2761 * mono_field_set_value:
2762 * @obj: Instance object
2763 * @field: MonoClassField describing the field to set
2764 * @value: The value to be set
2766 * Sets the value of the field described by @field in the object instance @obj
2767 * to the value passed in @value. This method should only be used for instance
2768 * fields. For static fields, use mono_field_static_set_value.
2770 * The value must be on the native format of the field type.
2773 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2777 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2779 dest = (char*)obj + field->offset;
2780 set_value (field->type, dest, value, FALSE);
2784 * mono_field_static_set_value:
2785 * @field: MonoClassField describing the field to set
2786 * @value: The value to be set
2788 * Sets the value of the static field described by @field
2789 * to the value passed in @value.
2791 * The value must be on the native format of the field type.
2794 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2798 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2799 /* you cant set a constant! */
2800 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2802 if (field->offset == -1) {
2803 /* Special static */
2804 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
2805 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
2807 dest = (char*)vt->data + field->offset;
2809 set_value (field->type, dest, value, FALSE);
2812 /* Used by the debugger */
2814 mono_vtable_get_static_field_data (MonoVTable *vt)
2820 * mono_field_get_value:
2821 * @obj: Object instance
2822 * @field: MonoClassField describing the field to fetch information from
2823 * @value: pointer to the location where the value will be stored
2825 * Use this routine to get the value of the field @field in the object
2828 * The pointer provided by value must be of the field type, for reference
2829 * types this is a MonoObject*, for value types its the actual pointer to
2834 * mono_field_get_value (obj, int_field, &i);
2837 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2841 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2843 src = (char*)obj + field->offset;
2844 set_value (field->type, value, src, TRUE);
2848 * mono_field_get_value_object:
2849 * @domain: domain where the object will be created (if boxing)
2850 * @field: MonoClassField describing the field to fetch information from
2851 * @obj: The object instance for the field.
2853 * Returns: a new MonoObject with the value from the given field. If the
2854 * field represents a value type, the value is boxed.
2858 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2862 MonoVTable *vtable = NULL;
2864 gboolean is_static = FALSE;
2865 gboolean is_ref = FALSE;
2867 switch (field->type->type) {
2868 case MONO_TYPE_STRING:
2869 case MONO_TYPE_OBJECT:
2870 case MONO_TYPE_CLASS:
2871 case MONO_TYPE_ARRAY:
2872 case MONO_TYPE_SZARRAY:
2877 case MONO_TYPE_BOOLEAN:
2880 case MONO_TYPE_CHAR:
2889 case MONO_TYPE_VALUETYPE:
2890 is_ref = field->type->byref;
2892 case MONO_TYPE_GENERICINST:
2893 is_ref = !field->type->data.generic_class->container_class->valuetype;
2896 g_error ("type 0x%x not handled in "
2897 "mono_field_get_value_object", field->type->type);
2901 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2903 vtable = mono_class_vtable (domain, field->parent);
2905 char *name = mono_type_get_full_name (field->parent);
2906 g_warning ("Could not retrieve the vtable for type %s in mono_field_get_value_object", name);
2910 if (!vtable->initialized)
2911 mono_runtime_class_init (vtable);
2916 mono_field_static_get_value (vtable, field, &o);
2918 mono_field_get_value (obj, field, &o);
2923 /* boxed value type */
2924 klass = mono_class_from_mono_type (field->type);
2925 o = mono_object_new (domain, klass);
2926 v = ((gchar *) o) + sizeof (MonoObject);
2928 mono_field_static_get_value (vtable, field, v);
2930 mono_field_get_value (obj, field, v);
2937 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2940 const char *p = blob;
2941 mono_metadata_decode_blob_size (p, &p);
2944 case MONO_TYPE_BOOLEAN:
2947 *(guint8 *) value = *p;
2949 case MONO_TYPE_CHAR:
2952 *(guint16*) value = read16 (p);
2956 *(guint32*) value = read32 (p);
2960 *(guint64*) value = read64 (p);
2963 readr4 (p, (float*) value);
2966 readr8 (p, (double*) value);
2968 case MONO_TYPE_STRING:
2969 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
2971 case MONO_TYPE_CLASS:
2972 *(gpointer*) value = NULL;
2976 g_warning ("type 0x%02x should not be in constant table", type);
2982 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2984 MonoTypeEnum def_type;
2987 data = mono_class_get_field_default_value (field, &def_type);
2988 mono_get_constant_value_from_blob (domain, def_type, data, value);
2992 * mono_field_static_get_value:
2993 * @vt: vtable to the object
2994 * @field: MonoClassField describing the field to fetch information from
2995 * @value: where the value is returned
2997 * Use this routine to get the value of the static field @field value.
2999 * The pointer provided by value must be of the field type, for reference
3000 * types this is a MonoObject*, for value types its the actual pointer to
3005 * mono_field_static_get_value (vt, int_field, &i);
3008 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3012 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3014 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3015 get_default_field_value (vt->domain, field, value);
3019 if (field->offset == -1) {
3020 /* Special static */
3021 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3022 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3024 src = (char*)vt->data + field->offset;
3026 set_value (field->type, value, src, TRUE);
3030 * mono_property_set_value:
3031 * @prop: MonoProperty to set
3032 * @obj: instance object on which to act
3033 * @params: parameters to pass to the propery
3034 * @exc: optional exception
3036 * Invokes the property's set method with the given arguments on the
3037 * object instance obj (or NULL for static properties).
3039 * You can pass NULL as the exc argument if you don't want to
3040 * catch exceptions, otherwise, *exc will be set to the exception
3041 * thrown, if any. if an exception is thrown, you can't use the
3042 * MonoObject* result from the function.
3045 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3047 default_mono_runtime_invoke (prop->set, obj, params, exc);
3051 * mono_property_get_value:
3052 * @prop: MonoProperty to fetch
3053 * @obj: instance object on which to act
3054 * @params: parameters to pass to the propery
3055 * @exc: optional exception
3057 * Invokes the property's get method with the given arguments on the
3058 * object instance obj (or NULL for static properties).
3060 * You can pass NULL as the exc argument if you don't want to
3061 * catch exceptions, otherwise, *exc will be set to the exception
3062 * thrown, if any. if an exception is thrown, you can't use the
3063 * MonoObject* result from the function.
3065 * Returns: the value from invoking the get method on the property.
3068 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3070 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3074 * mono_nullable_init:
3075 * @buf: The nullable structure to initialize.
3076 * @value: the value to initialize from
3077 * @klass: the type for the object
3079 * Initialize the nullable structure pointed to by @buf from @value which
3080 * should be a boxed value type. The size of @buf should be able to hold
3081 * as much data as the @klass->instance_size (which is the number of bytes
3082 * that will be copies).
3084 * Since Nullables have variable structure, we can not define a C
3085 * structure for them.
3088 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3090 MonoClass *param_class = klass->cast_class;
3092 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3093 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3095 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3097 if (param_class->has_references)
3098 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3100 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3102 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
3107 * mono_nullable_box:
3108 * @buf: The buffer representing the data to be boxed
3109 * @klass: the type to box it as.
3111 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3115 mono_nullable_box (guint8 *buf, MonoClass *klass)
3117 MonoClass *param_class = klass->cast_class;
3119 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3120 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3122 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3123 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3124 if (param_class->has_references)
3125 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3127 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3135 * mono_get_delegate_invoke:
3136 * @klass: The delegate class
3138 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
3141 mono_get_delegate_invoke (MonoClass *klass)
3145 /* This is called at runtime, so avoid the slower search in metadata */
3146 mono_class_setup_methods (klass);
3148 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3155 * mono_runtime_delegate_invoke:
3156 * @delegate: pointer to a delegate object.
3157 * @params: parameters for the delegate.
3158 * @exc: Pointer to the exception result.
3160 * Invokes the delegate method @delegate with the parameters provided.
3162 * You can pass NULL as the exc argument if you don't want to
3163 * catch exceptions, otherwise, *exc will be set to the exception
3164 * thrown, if any. if an exception is thrown, you can't use the
3165 * MonoObject* result from the function.
3168 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3172 im = mono_get_delegate_invoke (delegate->vtable->klass);
3175 return mono_runtime_invoke (im, delegate, params, exc);
3178 static char **main_args = NULL;
3179 static int num_main_args;
3182 * mono_runtime_get_main_args:
3184 * Returns: a MonoArray with the arguments passed to the main program
3187 mono_runtime_get_main_args (void)
3191 MonoDomain *domain = mono_domain_get ();
3196 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3198 for (i = 0; i < num_main_args; ++i)
3199 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3205 fire_process_exit_event (void)
3207 MonoClassField *field;
3208 MonoDomain *domain = mono_domain_get ();
3210 MonoObject *delegate, *exc;
3212 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
3215 if (domain != mono_get_root_domain ())
3218 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
3219 if (delegate == NULL)
3224 mono_runtime_delegate_invoke (delegate, pa, &exc);
3228 * mono_runtime_run_main:
3229 * @method: the method to start the application with (usually Main)
3230 * @argc: number of arguments from the command line
3231 * @argv: array of strings from the command line
3232 * @exc: excetption results
3234 * Execute a standard Main() method (argc/argv contains the
3235 * executable name). This method also sets the command line argument value
3236 * needed by System.Environment.
3241 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3245 MonoArray *args = NULL;
3246 MonoDomain *domain = mono_domain_get ();
3247 gchar *utf8_fullpath;
3250 g_assert (method != NULL);
3252 mono_thread_set_main (mono_thread_current ());
3254 main_args = g_new0 (char*, argc);
3255 num_main_args = argc;
3257 if (!g_path_is_absolute (argv [0])) {
3258 gchar *basename = g_path_get_basename (argv [0]);
3259 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3263 utf8_fullpath = mono_utf8_from_external (fullpath);
3264 if(utf8_fullpath == NULL) {
3265 /* Printing the arg text will cause glib to
3266 * whinge about "Invalid UTF-8", but at least
3267 * its relevant, and shows the problem text
3270 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3271 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3278 utf8_fullpath = mono_utf8_from_external (argv[0]);
3279 if(utf8_fullpath == NULL) {
3280 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3281 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3286 main_args [0] = utf8_fullpath;
3288 for (i = 1; i < argc; ++i) {
3291 utf8_arg=mono_utf8_from_external (argv[i]);
3292 if(utf8_arg==NULL) {
3293 /* Ditto the comment about Invalid UTF-8 here */
3294 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3295 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3299 main_args [i] = utf8_arg;
3303 if (mono_method_signature (method)->param_count) {
3304 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3305 for (i = 0; i < argc; ++i) {
3306 /* The encodings should all work, given that
3307 * we've checked all these args for the
3310 gchar *str = mono_utf8_from_external (argv [i]);
3311 MonoString *arg = mono_string_new (domain, str);
3312 mono_array_setref (args, i, arg);
3316 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3319 mono_assembly_set_main (method->klass->image->assembly);
3321 result = mono_runtime_exec_main (method, args, exc);
3322 fire_process_exit_event ();
3327 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3329 static MonoMethod *serialize_method;
3334 if (!serialize_method) {
3335 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3336 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3339 if (!serialize_method) {
3344 g_assert (!mono_object_class (obj)->marshalbyref);
3348 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3356 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3358 static MonoMethod *deserialize_method;
3363 if (!deserialize_method) {
3364 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3365 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3367 if (!deserialize_method) {
3374 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3382 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3384 static MonoMethod *get_proxy_method;
3386 MonoDomain *domain = mono_domain_get ();
3387 MonoRealProxy *real_proxy;
3388 MonoReflectionType *reflection_type;
3389 MonoTransparentProxy *transparent_proxy;
3391 if (!get_proxy_method)
3392 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3394 g_assert (obj->vtable->klass->marshalbyref);
3396 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3397 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3399 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3400 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3403 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3407 return (MonoObject*) transparent_proxy;
3411 * mono_object_xdomain_representation
3413 * @target_domain: a domain
3414 * @exc: pointer to a MonoObject*
3416 * Creates a representation of obj in the domain target_domain. This
3417 * is either a copy of obj arrived through via serialization and
3418 * deserialization or a proxy, depending on whether the object is
3419 * serializable or marshal by ref. obj must not be in target_domain.
3421 * If the object cannot be represented in target_domain, NULL is
3422 * returned and *exc is set to an appropriate exception.
3425 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3427 MonoObject *deserialized = NULL;
3428 gboolean failure = FALSE;
3432 if (mono_object_class (obj)->marshalbyref) {
3433 deserialized = make_transparent_proxy (obj, &failure, exc);
3435 MonoDomain *domain = mono_domain_get ();
3436 MonoObject *serialized;
3438 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3439 serialized = serialize_object (obj, &failure, exc);
3440 mono_domain_set_internal_with_options (target_domain, FALSE);
3442 deserialized = deserialize_object (serialized, &failure, exc);
3443 if (domain != target_domain)
3444 mono_domain_set_internal_with_options (domain, FALSE);
3447 return deserialized;
3450 /* Used in call_unhandled_exception_delegate */
3452 create_unhandled_exception_eventargs (MonoObject *exc)
3456 MonoMethod *method = NULL;
3457 MonoBoolean is_terminating = TRUE;
3460 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3463 mono_class_init (klass);
3465 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3466 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3470 args [1] = &is_terminating;
3472 obj = mono_object_new (mono_domain_get (), klass);
3473 mono_runtime_invoke (method, obj, args, NULL);
3478 /* Used in mono_unhandled_exception */
3480 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3481 MonoObject *e = NULL;
3483 MonoDomain *current_domain = mono_domain_get ();
3485 if (domain != current_domain)
3486 mono_domain_set_internal_with_options (domain, FALSE);
3488 g_assert (domain == mono_object_domain (domain->domain));
3490 if (mono_object_domain (exc) != domain) {
3491 MonoObject *serialization_exc;
3493 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3495 if (serialization_exc) {
3497 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3500 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3501 "System.Runtime.Serialization", "SerializationException",
3502 "Could not serialize unhandled exception.");
3506 g_assert (mono_object_domain (exc) == domain);
3508 pa [0] = domain->domain;
3509 pa [1] = create_unhandled_exception_eventargs (exc);
3510 mono_runtime_delegate_invoke (delegate, pa, &e);
3512 if (domain != current_domain)
3513 mono_domain_set_internal_with_options (current_domain, FALSE);
3517 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3518 if (!mono_error_ok (&error)) {
3519 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3520 mono_error_cleanup (&error);
3522 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3528 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3531 * mono_runtime_unhandled_exception_policy_set:
3532 * @policy: the new policy
3534 * This is a VM internal routine.
3536 * Sets the runtime policy for handling unhandled exceptions.
3539 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3540 runtime_unhandled_exception_policy = policy;
3544 * mono_runtime_unhandled_exception_policy_get:
3546 * This is a VM internal routine.
3548 * Gets the runtime policy for handling unhandled exceptions.
3550 MonoRuntimeUnhandledExceptionPolicy
3551 mono_runtime_unhandled_exception_policy_get (void) {
3552 return runtime_unhandled_exception_policy;
3556 * mono_unhandled_exception:
3557 * @exc: exception thrown
3559 * This is a VM internal routine.
3561 * We call this function when we detect an unhandled exception
3562 * in the default domain.
3564 * It invokes the * UnhandledException event in AppDomain or prints
3565 * a warning to the console
3568 mono_unhandled_exception (MonoObject *exc)
3570 MonoDomain *current_domain = mono_domain_get ();
3571 MonoDomain *root_domain = mono_get_root_domain ();
3572 MonoClassField *field;
3573 MonoObject *current_appdomain_delegate;
3574 MonoObject *root_appdomain_delegate;
3576 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3577 "UnhandledException");
3580 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3581 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3582 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3583 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3584 if (current_domain != root_domain && (mono_framework_version () >= 2)) {
3585 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3587 current_appdomain_delegate = NULL;
3590 /* set exitcode only if we will abort the process */
3592 mono_environment_exitcode_set (1);
3593 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3594 mono_print_unhandled_exception (exc);
3596 if (root_appdomain_delegate) {
3597 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3599 if (current_appdomain_delegate) {
3600 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3607 * Launch a new thread to execute a function
3609 * main_func is called back from the thread with main_args as the
3610 * parameter. The callback function is expected to start Main()
3611 * eventually. This function then waits for all managed threads to
3613 * It is not necesseray anymore to execute managed code in a subthread,
3614 * so this function should not be used anymore by default: just
3615 * execute the code and then call mono_thread_manage ().
3618 mono_runtime_exec_managed_code (MonoDomain *domain,
3619 MonoMainThreadFunc main_func,
3622 mono_thread_create (domain, main_func, main_args);
3624 mono_thread_manage ();
3628 * Execute a standard Main() method (args doesn't contain the
3632 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3637 MonoCustomAttrInfo* cinfo;
3638 gboolean has_stathread_attribute;
3639 MonoInternalThread* thread = mono_thread_internal_current ();
3645 domain = mono_object_domain (args);
3646 if (!domain->entry_assembly) {
3648 MonoAssembly *assembly;
3650 assembly = method->klass->image->assembly;
3651 domain->entry_assembly = assembly;
3652 /* Domains created from another domain already have application_base and configuration_file set */
3653 if (domain->setup->application_base == NULL) {
3654 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3657 if (domain->setup->configuration_file == NULL) {
3658 str = g_strconcat (assembly->image->name, ".config", NULL);
3659 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3661 mono_set_private_bin_path_from_config (domain);
3665 cinfo = mono_custom_attrs_from_method (method);
3667 static MonoClass *stathread_attribute = NULL;
3668 if (!stathread_attribute)
3669 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3670 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3672 mono_custom_attrs_free (cinfo);
3674 has_stathread_attribute = FALSE;
3676 if (has_stathread_attribute) {
3677 thread->apartment_state = ThreadApartmentState_STA;
3678 } else if (mono_framework_version () == 1) {
3679 thread->apartment_state = ThreadApartmentState_Unknown;
3681 thread->apartment_state = ThreadApartmentState_MTA;
3683 mono_thread_init_apartment_state ();
3685 mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3687 /* FIXME: check signature of method */
3688 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3690 res = mono_runtime_invoke (method, NULL, pa, exc);
3692 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3696 mono_environment_exitcode_set (rval);
3698 mono_runtime_invoke (method, NULL, pa, exc);
3702 /* If the return type of Main is void, only
3703 * set the exitcode if an exception was thrown
3704 * (we don't want to blow away an
3705 * explicitly-set exit code)
3708 mono_environment_exitcode_set (rval);
3712 mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3718 * mono_install_runtime_invoke:
3719 * @func: Function to install
3721 * This is a VM internal routine
3724 mono_install_runtime_invoke (MonoInvokeFunc func)
3726 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3731 * mono_runtime_invoke_array:
3732 * @method: method to invoke
3733 * @obJ: object instance
3734 * @params: arguments to the method
3735 * @exc: exception information.
3737 * Invokes the method represented by @method on the object @obj.
3739 * obj is the 'this' pointer, it should be NULL for static
3740 * methods, a MonoObject* for object instances and a pointer to
3741 * the value type for value types.
3743 * The params array contains the arguments to the method with the
3744 * same convention: MonoObject* pointers for object instances and
3745 * pointers to the value type otherwise. The _invoke_array
3746 * variant takes a C# object[] as the params argument (MonoArray
3747 * *params): in this case the value types are boxed inside the
3748 * respective reference representation.
3750 * From unmanaged code you'll usually use the
3751 * mono_runtime_invoke() variant.
3753 * Note that this function doesn't handle virtual methods for
3754 * you, it will exec the exact method you pass: we still need to
3755 * expose a function to lookup the derived class implementation
3756 * of a virtual method (there are examples of this in the code,
3759 * You can pass NULL as the exc argument if you don't want to
3760 * catch exceptions, otherwise, *exc will be set to the exception
3761 * thrown, if any. if an exception is thrown, you can't use the
3762 * MonoObject* result from the function.
3764 * If the method returns a value type, it is boxed in an object
3768 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3771 MonoMethodSignature *sig = mono_method_signature (method);
3772 gpointer *pa = NULL;
3775 gboolean has_byref_nullables = FALSE;
3777 if (NULL != params) {
3778 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3779 for (i = 0; i < mono_array_length (params); i++) {
3780 MonoType *t = sig->params [i];
3786 case MONO_TYPE_BOOLEAN:
3789 case MONO_TYPE_CHAR:
3798 case MONO_TYPE_VALUETYPE:
3799 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3800 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
3801 pa [i] = mono_array_get (params, MonoObject*, i);
3803 has_byref_nullables = TRUE;
3805 /* MS seems to create the objects if a null is passed in */
3806 if (!mono_array_get (params, MonoObject*, i))
3807 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
3811 * We can't pass the unboxed vtype byref to the callee, since
3812 * that would mean the callee would be able to modify boxed
3813 * primitive types. So we (and MS) make a copy of the boxed
3814 * object, pass that to the callee, and replace the original
3815 * boxed object in the arg array with the copy.
3817 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3818 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3819 mono_array_setref (params, i, copy);
3822 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3825 case MONO_TYPE_STRING:
3826 case MONO_TYPE_OBJECT:
3827 case MONO_TYPE_CLASS:
3828 case MONO_TYPE_ARRAY:
3829 case MONO_TYPE_SZARRAY:
3831 pa [i] = mono_array_addr (params, MonoObject*, i);
3832 // FIXME: I need to check this code path
3834 pa [i] = mono_array_get (params, MonoObject*, i);
3836 case MONO_TYPE_GENERICINST:
3838 t = &t->data.generic_class->container_class->this_arg;
3840 t = &t->data.generic_class->container_class->byval_arg;
3842 case MONO_TYPE_PTR: {
3845 /* The argument should be an IntPtr */
3846 arg = mono_array_get (params, MonoObject*, i);
3850 g_assert (arg->vtable->klass == mono_defaults.int_class);
3851 pa [i] = ((MonoIntPtr*)arg)->m_value;
3856 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
3861 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3864 if (mono_class_is_nullable (method->klass)) {
3865 /* Need to create a boxed vtype instead */
3871 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3875 obj = mono_object_new (mono_domain_get (), method->klass);
3876 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3877 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3879 if (method->klass->valuetype)
3880 o = mono_object_unbox (obj);
3883 } else if (method->klass->valuetype) {
3884 obj = mono_value_box (mono_domain_get (), method->klass, obj);
3887 mono_runtime_invoke (method, o, pa, exc);
3890 if (mono_class_is_nullable (method->klass)) {
3891 MonoObject *nullable;
3893 /* Convert the unboxed vtype into a Nullable structure */
3894 nullable = mono_object_new (mono_domain_get (), method->klass);
3896 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3897 obj = mono_object_unbox (nullable);
3900 /* obj must be already unboxed if needed */
3901 res = mono_runtime_invoke (method, obj, pa, exc);
3903 if (sig->ret->type == MONO_TYPE_PTR) {
3904 MonoClass *pointer_class;
3905 static MonoMethod *box_method;
3907 MonoObject *box_exc;
3910 * The runtime-invoke wrapper returns a boxed IntPtr, need to
3911 * convert it to a Pointer object.
3913 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3915 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
3917 g_assert (res->vtable->klass == mono_defaults.int_class);
3918 box_args [0] = ((MonoIntPtr*)res)->m_value;
3919 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
3920 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
3921 g_assert (!box_exc);
3924 if (has_byref_nullables) {
3926 * The runtime invoke wrapper already converted byref nullables back,
3927 * and stored them in pa, we just need to copy them back to the
3930 for (i = 0; i < mono_array_length (params); i++) {
3931 MonoType *t = sig->params [i];
3933 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3934 mono_array_setref (params, i, pa [i]);
3943 arith_overflow (void)
3945 mono_raise_exception (mono_get_exception_overflow ());
3949 * mono_object_allocate:
3950 * @size: number of bytes to allocate
3952 * This is a very simplistic routine until we have our GC-aware
3955 * Returns: an allocated object of size @size, or NULL on failure.
3957 static inline void *
3958 mono_object_allocate (size_t size, MonoVTable *vtable)
3961 mono_stats.new_object_count++;
3962 ALLOC_OBJECT (o, vtable, size);
3968 * mono_object_allocate_ptrfree:
3969 * @size: number of bytes to allocate
3971 * Note that the memory allocated is not zeroed.
3972 * Returns: an allocated object of size @size, or NULL on failure.
3974 static inline void *
3975 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3978 mono_stats.new_object_count++;
3979 ALLOC_PTRFREE (o, vtable, size);
3983 static inline void *
3984 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3987 ALLOC_TYPED (o, size, vtable);
3988 mono_stats.new_object_count++;
3995 * @klass: the class of the object that we want to create
3997 * Returns: a newly created object whose definition is
3998 * looked up using @klass. This will not invoke any constructors,
3999 * so the consumer of this routine has to invoke any constructors on
4000 * its own to initialize the object.
4002 * It returns NULL on failure.
4005 mono_object_new (MonoDomain *domain, MonoClass *klass)
4009 MONO_ARCH_SAVE_REGS;
4010 vtable = mono_class_vtable (domain, klass);
4013 return mono_object_new_specific (vtable);
4017 * mono_object_new_specific:
4018 * @vtable: the vtable of the object that we want to create
4020 * Returns: A newly created object with class and domain specified
4024 mono_object_new_specific (MonoVTable *vtable)
4028 MONO_ARCH_SAVE_REGS;
4030 /* check for is_com_object for COM Interop */
4031 if (vtable->remote || vtable->klass->is_com_object)
4034 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4037 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4040 mono_class_init (klass);
4042 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4044 vtable->domain->create_proxy_for_type_method = im;
4047 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4049 o = mono_runtime_invoke (im, NULL, pa, NULL);
4050 if (o != NULL) return o;
4053 return mono_object_new_alloc_specific (vtable);
4057 mono_object_new_alloc_specific (MonoVTable *vtable)
4061 if (!vtable->klass->has_references) {
4062 o = mono_object_new_ptrfree (vtable);
4063 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4064 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4066 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4067 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4069 if (G_UNLIKELY (vtable->klass->has_finalize))
4070 mono_object_register_finalizer (o);
4072 if (G_UNLIKELY (profile_allocs))
4073 mono_profiler_allocation (o, vtable->klass);
4078 mono_object_new_fast (MonoVTable *vtable)
4081 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4086 mono_object_new_ptrfree (MonoVTable *vtable)
4089 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4090 #if NEED_TO_ZERO_PTRFREE
4091 /* an inline memset is much faster for the common vcase of small objects
4092 * note we assume the allocated size is a multiple of sizeof (void*).
4094 if (vtable->klass->instance_size < 128) {
4096 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4097 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4103 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4110 mono_object_new_ptrfree_box (MonoVTable *vtable)
4113 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4114 /* the object will be boxed right away, no need to memzero it */
4119 * mono_class_get_allocation_ftn:
4121 * @for_box: the object will be used for boxing
4122 * @pass_size_in_words:
4124 * Return the allocation function appropriate for the given class.
4128 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4130 *pass_size_in_words = FALSE;
4132 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4133 profile_allocs = FALSE;
4135 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4136 return mono_object_new_specific;
4138 if (!vtable->klass->has_references) {
4139 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4141 return mono_object_new_ptrfree_box;
4142 return mono_object_new_ptrfree;
4145 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4147 return mono_object_new_fast;
4150 * FIXME: This is actually slower than mono_object_new_fast, because
4151 * of the overhead of parameter passing.
4154 *pass_size_in_words = TRUE;
4155 #ifdef GC_REDIRECT_TO_LOCAL
4156 return GC_local_gcj_fast_malloc;
4158 return GC_gcj_fast_malloc;
4163 return mono_object_new_specific;
4167 * mono_object_new_from_token:
4168 * @image: Context where the type_token is hosted
4169 * @token: a token of the type that we want to create
4171 * Returns: A newly created object whose definition is
4172 * looked up using @token in the @image image
4175 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4179 class = mono_class_get (image, token);
4181 return mono_object_new (domain, class);
4186 * mono_object_clone:
4187 * @obj: the object to clone
4189 * Returns: A newly created object who is a shallow copy of @obj
4192 mono_object_clone (MonoObject *obj)
4195 int size = obj->vtable->klass->instance_size;
4197 o = mono_object_allocate (size, obj->vtable);
4199 if (obj->vtable->klass->has_references) {
4200 mono_gc_wbarrier_object_copy (o, obj);
4202 int size = obj->vtable->klass->instance_size;
4203 /* do not copy the sync state */
4204 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
4206 if (G_UNLIKELY (profile_allocs))
4207 mono_profiler_allocation (o, obj->vtable->klass);
4209 if (obj->vtable->klass->has_finalize)
4210 mono_object_register_finalizer (o);
4215 * mono_array_full_copy:
4216 * @src: source array to copy
4217 * @dest: destination array
4219 * Copies the content of one array to another with exactly the same type and size.
4222 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4224 mono_array_size_t size;
4225 MonoClass *klass = src->obj.vtable->klass;
4227 MONO_ARCH_SAVE_REGS;
4229 g_assert (klass == dest->obj.vtable->klass);
4231 size = mono_array_length (src);
4232 g_assert (size == mono_array_length (dest));
4233 size *= mono_array_element_size (klass);
4235 if (klass->element_class->valuetype) {
4236 if (klass->element_class->has_references)
4237 mono_value_copy_array (dest, 0, mono_array_addr_with_size (src, 0, 0), mono_array_length (src));
4239 memcpy (&dest->vector, &src->vector, size);
4241 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4244 memcpy (&dest->vector, &src->vector, size);
4249 * mono_array_clone_in_domain:
4250 * @domain: the domain in which the array will be cloned into
4251 * @array: the array to clone
4253 * This routine returns a copy of the array that is hosted on the
4254 * specified MonoDomain.
4257 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4260 mono_array_size_t size, i;
4261 mono_array_size_t *sizes;
4262 MonoClass *klass = array->obj.vtable->klass;
4264 MONO_ARCH_SAVE_REGS;
4266 if (array->bounds == NULL) {
4267 size = mono_array_length (array);
4268 o = mono_array_new_full (domain, klass, &size, NULL);
4270 size *= mono_array_element_size (klass);
4272 if (klass->element_class->valuetype) {
4273 if (klass->element_class->has_references)
4274 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4276 memcpy (&o->vector, &array->vector, size);
4278 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4281 memcpy (&o->vector, &array->vector, size);
4286 sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
4287 size = mono_array_element_size (klass);
4288 for (i = 0; i < klass->rank; ++i) {
4289 sizes [i] = array->bounds [i].length;
4290 size *= array->bounds [i].length;
4291 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4293 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
4295 if (klass->element_class->valuetype) {
4296 if (klass->element_class->has_references)
4297 mono_value_copy_array (o, 0, mono_array_addr_with_size (array, 0, 0), mono_array_length (array));
4299 memcpy (&o->vector, &array->vector, size);
4301 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4304 memcpy (&o->vector, &array->vector, size);
4312 * @array: the array to clone
4314 * Returns: A newly created array who is a shallow copy of @array
4317 mono_array_clone (MonoArray *array)
4319 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4322 /* helper macros to check for overflow when calculating the size of arrays */
4323 #ifdef MONO_BIG_ARRAYS
4324 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4325 #define MYGUINT_MAX MYGUINT64_MAX
4326 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4327 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4328 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4329 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4330 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4332 #define MYGUINT32_MAX 4294967295U
4333 #define MYGUINT_MAX MYGUINT32_MAX
4334 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4335 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4336 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4337 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4338 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4342 mono_array_calc_byte_len (MonoClass *class, mono_array_size_t len, mono_array_size_t *res)
4344 mono_array_size_t byte_len;
4346 byte_len = mono_array_element_size (class);
4347 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4350 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4352 byte_len += sizeof (MonoArray);
4360 * mono_array_new_full:
4361 * @domain: domain where the object is created
4362 * @array_class: array class
4363 * @lengths: lengths for each dimension in the array
4364 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4366 * This routine creates a new array objects with the given dimensions,
4367 * lower bounds and type.
4370 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
4372 mono_array_size_t byte_len, len, bounds_size;
4375 MonoArrayBounds *bounds;
4379 if (!array_class->inited)
4380 mono_class_init (array_class);
4384 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4385 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4387 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4391 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4393 for (i = 0; i < array_class->rank; ++i) {
4394 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4396 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4397 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4402 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4403 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4407 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4408 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4409 byte_len = (byte_len + 3) & ~3;
4410 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4411 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4412 byte_len += bounds_size;
4415 * Following three lines almost taken from mono_object_new ():
4416 * they need to be kept in sync.
4418 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4419 #ifndef HAVE_SGEN_GC
4420 if (!array_class->has_references) {
4421 o = mono_object_allocate_ptrfree (byte_len, vtable);
4422 #if NEED_TO_ZERO_PTRFREE
4423 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4425 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4426 o = mono_object_allocate_spec (byte_len, vtable);
4428 o = mono_object_allocate (byte_len, vtable);
4431 array = (MonoArray*)o;
4432 array->max_length = len;
4435 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4436 array->bounds = bounds;
4440 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4442 o = mono_gc_alloc_vector (vtable, byte_len, len);
4443 array = (MonoArray*)o;
4444 mono_stats.new_object_count++;
4446 bounds = array->bounds;
4450 for (i = 0; i < array_class->rank; ++i) {
4451 bounds [i].length = lengths [i];
4453 bounds [i].lower_bound = lower_bounds [i];
4457 if (G_UNLIKELY (profile_allocs))
4458 mono_profiler_allocation (o, array_class);
4465 * @domain: domain where the object is created
4466 * @eclass: element class
4467 * @n: number of array elements
4469 * This routine creates a new szarray with @n elements of type @eclass.
4472 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
4476 MONO_ARCH_SAVE_REGS;
4478 ac = mono_array_class_get (eclass, 1);
4481 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4485 * mono_array_new_specific:
4486 * @vtable: a vtable in the appropriate domain for an initialized class
4487 * @n: number of array elements
4489 * This routine is a fast alternative to mono_array_new() for code which
4490 * can be sure about the domain it operates in.
4493 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
4499 MONO_ARCH_SAVE_REGS;
4501 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4506 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4507 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4510 #ifndef HAVE_SGEN_GC
4511 if (!vtable->klass->has_references) {
4512 o = mono_object_allocate_ptrfree (byte_len, vtable);
4513 #if NEED_TO_ZERO_PTRFREE
4514 ((MonoArray*)o)->bounds = NULL;
4515 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4517 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4518 o = mono_object_allocate_spec (byte_len, vtable);
4520 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4521 o = mono_object_allocate (byte_len, vtable);
4524 ao = (MonoArray *)o;
4527 o = mono_gc_alloc_vector (vtable, byte_len, n);
4529 mono_stats.new_object_count++;
4532 if (G_UNLIKELY (profile_allocs))
4533 mono_profiler_allocation (o, vtable->klass);
4539 * mono_string_new_utf16:
4540 * @text: a pointer to an utf16 string
4541 * @len: the length of the string
4543 * Returns: A newly created string object which contains @text.
4546 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4550 s = mono_string_new_size (domain, len);
4551 g_assert (s != NULL);
4553 memcpy (mono_string_chars (s), text, len * 2);
4559 * mono_string_new_size:
4560 * @text: a pointer to an utf16 string
4561 * @len: the length of the string
4563 * Returns: A newly created string object of @len
4566 mono_string_new_size (MonoDomain *domain, gint32 len)
4570 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
4572 /* overflow ? can't fit it, can't allocate it! */
4574 mono_gc_out_of_memory (-1);
4576 vtable = mono_class_vtable (domain, mono_defaults.string_class);
4579 s = mono_object_allocate_ptrfree (size, vtable);
4582 #if NEED_TO_ZERO_PTRFREE
4585 if (G_UNLIKELY (profile_allocs))
4586 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
4592 * mono_string_new_len:
4593 * @text: a pointer to an utf8 string
4594 * @length: number of bytes in @text to consider
4596 * Returns: A newly created string object which contains @text.
4599 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
4601 GError *error = NULL;
4602 MonoString *o = NULL;
4604 glong items_written;
4606 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
4609 o = mono_string_new_utf16 (domain, ut, items_written);
4611 g_error_free (error);
4620 * @text: a pointer to an utf8 string
4622 * Returns: A newly created string object which contains @text.
4625 mono_string_new (MonoDomain *domain, const char *text)
4627 GError *error = NULL;
4628 MonoString *o = NULL;
4630 glong items_written;
4635 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
4638 o = mono_string_new_utf16 (domain, ut, items_written);
4640 g_error_free (error);
4643 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
4648 MonoString *o = NULL;
4650 if (!g_utf8_validate (text, -1, &end))
4653 len = g_utf8_strlen (text, -1);
4654 o = mono_string_new_size (domain, len);
4655 str = mono_string_chars (o);
4657 while (text < end) {
4658 *str++ = g_utf8_get_char (text);
4659 text = g_utf8_next_char (text);
4666 * mono_string_new_wrapper:
4667 * @text: pointer to utf8 characters.
4669 * Helper function to create a string object from @text in the current domain.
4672 mono_string_new_wrapper (const char *text)
4674 MonoDomain *domain = mono_domain_get ();
4676 MONO_ARCH_SAVE_REGS;
4679 return mono_string_new (domain, text);
4686 * @class: the class of the value
4687 * @value: a pointer to the unboxed data
4689 * Returns: A newly created object which contains @value.
4692 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
4698 g_assert (class->valuetype);
4699 if (mono_class_is_nullable (class))
4700 return mono_nullable_box (value, class);
4702 vtable = mono_class_vtable (domain, class);
4705 size = mono_class_instance_size (class);
4706 res = mono_object_new_alloc_specific (vtable);
4707 if (G_UNLIKELY (profile_allocs))
4708 mono_profiler_allocation (res, class);
4710 size = size - sizeof (MonoObject);
4713 g_assert (size == mono_class_value_size (class, NULL));
4714 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
4716 #if NO_UNALIGNED_ACCESS
4717 memcpy ((char *)res + sizeof (MonoObject), value, size);
4721 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
4724 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4727 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4730 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4733 memcpy ((char *)res + sizeof (MonoObject), value, size);
4737 if (class->has_finalize)
4738 mono_object_register_finalizer (res);
4744 * @dest: destination pointer
4745 * @src: source pointer
4746 * @klass: a valuetype class
4748 * Copy a valuetype from @src to @dest. This function must be used
4749 * when @klass contains references fields.
4752 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4754 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4758 * mono_value_copy_array:
4759 * @dest: destination array
4760 * @dest_idx: index in the @dest array
4761 * @src: source pointer
4762 * @count: number of items
4764 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
4765 * This function must be used when @klass contains references fields.
4766 * Overlap is handled.
4769 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4771 int size = mono_array_element_size (dest->obj.vtable->klass);
4772 char *d = mono_array_addr_with_size (dest, size, dest_idx);
4773 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
4774 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4778 * mono_object_get_domain:
4779 * @obj: object to query
4781 * Returns: the MonoDomain where the object is hosted
4784 mono_object_get_domain (MonoObject *obj)
4786 return mono_object_domain (obj);
4790 * mono_object_get_class:
4791 * @obj: object to query
4793 * Returns: the MonOClass of the object.
4796 mono_object_get_class (MonoObject *obj)
4798 return mono_object_class (obj);
4801 * mono_object_get_size:
4802 * @o: object to query
4804 * Returns: the size, in bytes, of @o
4807 mono_object_get_size (MonoObject* o)
4809 MonoClass* klass = mono_object_class (o);
4810 if (klass == mono_defaults.string_class) {
4811 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4812 } else if (o->vtable->rank) {
4813 MonoArray *array = (MonoArray*)o;
4814 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4815 if (array->bounds) {
4818 size += sizeof (MonoArrayBounds) * o->vtable->rank;
4822 return mono_class_instance_size (klass);
4827 * mono_object_unbox:
4828 * @obj: object to unbox
4830 * Returns: a pointer to the start of the valuetype boxed in this
4833 * This method will assert if the object passed is not a valuetype.
4836 mono_object_unbox (MonoObject *obj)
4838 /* add assert for valuetypes? */
4839 g_assert (obj->vtable->klass->valuetype);
4840 return ((char*)obj) + sizeof (MonoObject);
4844 * mono_object_isinst:
4846 * @klass: a pointer to a class
4848 * Returns: @obj if @obj is derived from @klass
4851 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4854 mono_class_init (klass);
4856 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
4857 return mono_object_isinst_mbyref (obj, klass);
4862 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4866 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4875 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4876 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4880 MonoClass *oklass = vt->klass;
4881 if ((oklass == mono_defaults.transparent_proxy_class))
4882 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4884 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4888 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
4890 MonoDomain *domain = mono_domain_get ();
4892 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4893 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4894 MonoMethod *im = NULL;
4897 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4898 im = mono_object_get_virtual_method (rp, im);
4901 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4904 res = mono_runtime_invoke (im, rp, pa, NULL);
4906 if (*(MonoBoolean *) mono_object_unbox(res)) {
4907 /* Update the vtable of the remote type, so it can safely cast to this new type */
4908 mono_upgrade_remote_class (domain, obj, klass);
4917 * mono_object_castclass_mbyref:
4919 * @klass: a pointer to a class
4921 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4924 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4926 if (!obj) return NULL;
4927 if (mono_object_isinst_mbyref (obj, klass)) return obj;
4929 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4931 "InvalidCastException"));
4936 MonoDomain *orig_domain;
4942 str_lookup (MonoDomain *domain, gpointer user_data)
4944 LDStrInfo *info = user_data;
4945 if (info->res || domain == info->orig_domain)
4947 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4953 mono_string_get_pinned (MonoString *str)
4957 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4958 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4959 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4960 news->length = mono_string_length (str);
4965 #define mono_string_get_pinned(str) (str)
4969 mono_string_is_interned_lookup (MonoString *str, int insert)
4971 MonoGHashTable *ldstr_table;
4975 domain = ((MonoObject *)str)->vtable->domain;
4976 ldstr_table = domain->ldstr_table;
4978 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4983 str = mono_string_get_pinned (str);
4984 mono_g_hash_table_insert (ldstr_table, str, str);
4988 LDStrInfo ldstr_info;
4989 ldstr_info.orig_domain = domain;
4990 ldstr_info.ins = str;
4991 ldstr_info.res = NULL;
4993 mono_domain_foreach (str_lookup, &ldstr_info);
4994 if (ldstr_info.res) {
4996 * the string was already interned in some other domain:
4997 * intern it in the current one as well.
4999 mono_g_hash_table_insert (ldstr_table, str, str);
5009 * mono_string_is_interned:
5010 * @o: String to probe
5012 * Returns whether the string has been interned.
5015 mono_string_is_interned (MonoString *o)
5017 return mono_string_is_interned_lookup (o, FALSE);
5021 * mono_string_intern:
5022 * @o: String to intern
5024 * Interns the string passed.
5025 * Returns: The interned string.
5028 mono_string_intern (MonoString *str)
5030 return mono_string_is_interned_lookup (str, TRUE);
5035 * @domain: the domain where the string will be used.
5036 * @image: a metadata context
5037 * @idx: index into the user string table.
5039 * Implementation for the ldstr opcode.
5040 * Returns: a loaded string from the @image/@idx combination.
5043 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5045 MONO_ARCH_SAVE_REGS;
5048 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5050 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5054 * mono_ldstr_metadata_sig
5055 * @domain: the domain for the string
5056 * @sig: the signature of a metadata string
5058 * Returns: a MonoString for a string stored in the metadata
5061 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5063 const char *str = sig;
5064 MonoString *o, *interned;
5067 len2 = mono_metadata_decode_blob_size (str, &str);
5070 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5071 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5074 guint16 *p2 = (guint16*)mono_string_chars (o);
5075 for (i = 0; i < len2; ++i) {
5076 *p2 = GUINT16_FROM_LE (*p2);
5082 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
5084 /* o will get garbage collected */
5088 o = mono_string_get_pinned (o);
5089 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5096 * mono_string_to_utf8:
5097 * @s: a System.String
5099 * Return the UTF8 representation for @s.
5100 * the resulting buffer nedds to be freed with g_free().
5102 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5105 mono_string_to_utf8 (MonoString *s)
5108 char *result = mono_string_to_utf8_checked (s, &error);
5110 if (!mono_error_ok (&error))
5111 mono_error_raise_exception (&error);
5116 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5120 GError *gerror = NULL;
5122 mono_error_init (error);
5128 return g_strdup ("");
5130 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5132 mono_error_set_argument (error, "string", "%s", gerror->message);
5133 g_error_free (gerror);
5136 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5137 if (s->length > written) {
5138 /* allocate the total length and copy the part of the string that has been converted */
5139 char *as2 = g_malloc0 (s->length);
5140 memcpy (as2, as, written);
5149 * mono_string_to_utf16:
5152 * Return an null-terminated array of the utf-16 chars
5153 * contained in @s. The result must be freed with g_free().
5154 * This is a temporary helper until our string implementation
5155 * is reworked to always include the null terminating char.
5158 mono_string_to_utf16 (MonoString *s)
5165 as = g_malloc ((s->length * 2) + 2);
5166 as [(s->length * 2)] = '\0';
5167 as [(s->length * 2) + 1] = '\0';
5170 return (gunichar2 *)(as);
5173 memcpy (as, mono_string_chars(s), s->length * 2);
5174 return (gunichar2 *)(as);
5178 * mono_string_from_utf16:
5179 * @data: the UTF16 string (LPWSTR) to convert
5181 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5183 * Returns: a MonoString.
5186 mono_string_from_utf16 (gunichar2 *data)
5188 MonoDomain *domain = mono_domain_get ();
5194 while (data [len]) len++;
5196 return mono_string_new_utf16 (domain, data, len);
5201 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, MonoError *error)
5207 r = mono_string_to_utf8_checked (s, error);
5208 if (!mono_error_ok (error))
5214 len = strlen (r) + 1;
5216 mp_s = mono_mempool_alloc (mp, len);
5218 mp_s = mono_image_alloc (image, len);
5220 memcpy (mp_s, r, len);
5228 * mono_string_to_utf8_image:
5229 * @s: a System.String
5231 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5234 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5236 return mono_string_to_utf8_internal (NULL, image, s, error);
5240 * mono_string_to_utf8_mp:
5241 * @s: a System.String
5243 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5246 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5248 return mono_string_to_utf8_internal (mp, NULL, s, error);
5252 default_ex_handler (MonoException *ex)
5254 MonoObject *o = (MonoObject*)ex;
5255 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
5259 static MonoExceptionFunc ex_handler = default_ex_handler;
5262 * mono_install_handler:
5263 * @func: exception handler
5265 * This is an internal JIT routine used to install the handler for exceptions
5269 mono_install_handler (MonoExceptionFunc func)
5271 ex_handler = func? func: default_ex_handler;
5275 * mono_raise_exception:
5276 * @ex: exception object
5278 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5281 mono_raise_exception (MonoException *ex)
5284 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5285 * that will cause gcc to omit the function epilog, causing problems when
5286 * the JIT tries to walk the stack, since the return address on the stack
5287 * will point into the next function in the executable, not this one.
5290 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class) {
5291 MonoInternalThread *thread = mono_thread_internal_current ();
5292 g_assert (ex->object.vtable->domain == mono_domain_get ());
5293 MONO_OBJECT_SETREF (thread, abort_exc, ex);
5300 * mono_wait_handle_new:
5301 * @domain: Domain where the object will be created
5302 * @handle: Handle for the wait handle
5304 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5307 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5309 MonoWaitHandle *res;
5310 gpointer params [1];
5311 static MonoMethod *handle_set;
5313 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5315 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5317 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5319 params [0] = &handle;
5320 mono_runtime_invoke (handle_set, res, params, NULL);
5326 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5328 static MonoClassField *f_os_handle;
5329 static MonoClassField *f_safe_handle;
5331 if (!f_os_handle && !f_safe_handle) {
5332 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5333 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5338 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5342 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5349 mono_runtime_capture_context (MonoDomain *domain)
5351 RuntimeInvokeFunction runtime_invoke;
5353 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5354 MonoMethod *method = mono_get_context_capture_method ();
5355 MonoMethod *wrapper;
5358 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5359 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5360 domain->capture_context_method = mono_compile_method (method);
5363 runtime_invoke = domain->capture_context_runtime_invoke;
5365 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5368 * mono_async_result_new:
5369 * @domain:domain where the object will be created.
5370 * @handle: wait handle.
5371 * @state: state to pass to AsyncResult
5372 * @data: C closure data.
5374 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5375 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5379 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5381 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5382 MonoObject *context = mono_runtime_capture_context (domain);
5383 /* we must capture the execution context from the original thread */
5385 MONO_OBJECT_SETREF (res, execution_context, context);
5386 /* note: result may be null if the flow is suppressed */
5390 MONO_OBJECT_SETREF (res, object_data, object_data);
5391 MONO_OBJECT_SETREF (res, async_state, state);
5393 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5395 res->sync_completed = FALSE;
5396 res->completed = FALSE;
5402 mono_message_init (MonoDomain *domain,
5403 MonoMethodMessage *this,
5404 MonoReflectionMethod *method,
5405 MonoArray *out_args)
5407 static MonoClass *object_array_klass;
5408 static MonoClass *byte_array_klass;
5409 static MonoClass *string_array_klass;
5410 MonoMethodSignature *sig = mono_method_signature (method->method);
5416 if (!object_array_klass) {
5419 klass = mono_array_class_get (mono_defaults.object_class, 1);
5422 mono_memory_barrier ();
5423 object_array_klass = klass;
5425 klass = mono_array_class_get (mono_defaults.byte_class, 1);
5428 mono_memory_barrier ();
5429 byte_array_klass = klass;
5431 klass = mono_array_class_get (mono_defaults.string_class, 1);
5434 mono_memory_barrier ();
5435 string_array_klass = klass;
5438 MONO_OBJECT_SETREF (this, method, method);
5440 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
5441 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
5442 this->async_result = NULL;
5443 this->call_type = CallType_Sync;
5445 names = g_new (char *, sig->param_count);
5446 mono_method_get_param_names (method->method, (const char **) names);
5447 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
5449 for (i = 0; i < sig->param_count; i++) {
5450 name = mono_string_new (domain, names [i]);
5451 mono_array_setref (this->names, i, name);
5455 for (i = 0, j = 0; i < sig->param_count; i++) {
5456 if (sig->params [i]->byref) {
5458 MonoObject* arg = mono_array_get (out_args, gpointer, j);
5459 mono_array_setref (this->args, i, arg);
5463 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
5467 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
5470 mono_array_set (this->arg_types, guint8, i, arg_type);
5475 * mono_remoting_invoke:
5476 * @real_proxy: pointer to a RealProxy object
5477 * @msg: The MonoMethodMessage to execute
5478 * @exc: used to store exceptions
5479 * @out_args: used to store output arguments
5481 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
5482 * IMessage interface and it is not trivial to extract results from there. So
5483 * we call an helper method PrivateInvoke instead of calling
5484 * RealProxy::Invoke() directly.
5486 * Returns: the result object.
5489 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
5490 MonoObject **exc, MonoArray **out_args)
5492 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
5495 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
5498 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
5500 real_proxy->vtable->domain->private_invoke_method = im;
5503 pa [0] = real_proxy;
5508 return mono_runtime_invoke (im, NULL, pa, exc);
5512 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
5513 MonoObject **exc, MonoArray **out_args)
5515 static MonoClass *object_array_klass;
5518 MonoMethodSignature *sig;
5520 int i, j, outarg_count = 0;
5522 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5524 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
5525 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5526 target = tp->rp->unwrapped_server;
5528 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
5532 domain = mono_domain_get ();
5533 method = msg->method->method;
5534 sig = mono_method_signature (method);
5536 for (i = 0; i < sig->param_count; i++) {
5537 if (sig->params [i]->byref)
5541 if (!object_array_klass) {
5544 klass = mono_array_class_get (mono_defaults.object_class, 1);
5547 mono_memory_barrier ();
5548 object_array_klass = klass;
5551 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
5552 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
5555 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
5557 for (i = 0, j = 0; i < sig->param_count; i++) {
5558 if (sig->params [i]->byref) {
5560 arg = mono_array_get (msg->args, gpointer, i);
5561 mono_array_setref (*out_args, j, arg);
5570 * mono_print_unhandled_exception:
5571 * @exc: The exception
5573 * Prints the unhandled exception.
5576 mono_print_unhandled_exception (MonoObject *exc)
5579 char *message = (char *) "";
5583 gboolean free_message = FALSE;
5585 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
5586 klass = exc->vtable->klass;
5588 while (klass && method == NULL) {
5589 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
5591 klass = klass->parent;
5596 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
5598 message = mono_string_to_utf8_checked (str, &error);
5599 if (!mono_error_ok (&error)) {
5600 mono_error_cleanup (&error);
5601 message = (char *)"";
5603 free_message = TRUE;
5609 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
5610 * exc->vtable->klass->name, message);
5612 g_printerr ("\nUnhandled Exception: %s\n", message);
5619 * mono_delegate_ctor:
5620 * @this: pointer to an uninitialized delegate object
5621 * @target: target object
5622 * @addr: pointer to native code
5625 * Initialize a delegate and sets a specific method, not the one
5626 * associated with addr. This is useful when sharing generic code.
5627 * In that case addr will most probably not be associated with the
5628 * correct instantiation of the method.
5631 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
5633 MonoDelegate *delegate = (MonoDelegate *)this;
5640 delegate->method = method;
5642 class = this->vtable->klass;
5643 mono_stats.delegate_creations++;
5645 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
5647 method = mono_marshal_get_remoting_invoke (method);
5648 delegate->method_ptr = mono_compile_method (method);
5649 MONO_OBJECT_SETREF (delegate, target, target);
5650 } else if (method && mono_method_signature (method)->hasthis && method->klass->valuetype) {
5651 method = mono_marshal_get_unbox_wrapper (method);
5652 delegate->method_ptr = mono_compile_method (method);
5653 MONO_OBJECT_SETREF (delegate, target, target);
5655 delegate->method_ptr = addr;
5656 MONO_OBJECT_SETREF (delegate, target, target);
5659 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
5663 * mono_delegate_ctor:
5664 * @this: pointer to an uninitialized delegate object
5665 * @target: target object
5666 * @addr: pointer to native code
5668 * This is used to initialize a delegate.
5671 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
5673 MonoDomain *domain = mono_domain_get ();
5675 MonoMethod *method = NULL;
5679 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
5680 method = ji->method;
5681 g_assert (!method->klass->generic_container);
5684 mono_delegate_ctor_with_method (this, target, addr, method);
5688 * mono_method_call_message_new:
5689 * @method: method to encapsulate
5690 * @params: parameters to the method
5691 * @invoke: optional, delegate invoke.
5692 * @cb: async callback delegate.
5693 * @state: state passed to the async callback.
5695 * Translates arguments pointers into a MonoMethodMessage.
5698 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
5699 MonoDelegate **cb, MonoObject **state)
5701 MonoDomain *domain = mono_domain_get ();
5702 MonoMethodSignature *sig = mono_method_signature (method);
5703 MonoMethodMessage *msg;
5706 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5709 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
5710 count = sig->param_count - 2;
5712 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
5713 count = sig->param_count;
5716 for (i = 0; i < count; i++) {
5721 if (sig->params [i]->byref)
5722 vpos = *((gpointer *)params [i]);
5726 type = sig->params [i]->type;
5727 class = mono_class_from_mono_type (sig->params [i]);
5729 if (class->valuetype)
5730 arg = mono_value_box (domain, class, vpos);
5732 arg = *((MonoObject **)vpos);
5734 mono_array_setref (msg->args, i, arg);
5737 if (cb != NULL && state != NULL) {
5738 *cb = *((MonoDelegate **)params [i]);
5740 *state = *((MonoObject **)params [i]);
5747 * mono_method_return_message_restore:
5749 * Restore results from message based processing back to arguments pointers
5752 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
5754 MonoMethodSignature *sig = mono_method_signature (method);
5755 int i, j, type, size, out_len;
5757 if (out_args == NULL)
5759 out_len = mono_array_length (out_args);
5763 for (i = 0, j = 0; i < sig->param_count; i++) {
5764 MonoType *pt = sig->params [i];
5769 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
5771 arg = mono_array_get (out_args, gpointer, j);
5774 g_assert (type != MONO_TYPE_VOID);
5776 if (MONO_TYPE_IS_REFERENCE (pt)) {
5777 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
5780 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
5781 size = mono_class_value_size (class, NULL);
5782 if (class->has_references)
5783 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
5785 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
5787 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5788 memset (*((gpointer *)params [i]), 0, size);
5798 * mono_load_remote_field:
5799 * @this: pointer to an object
5800 * @klass: klass of the object containing @field
5801 * @field: the field to load
5802 * @res: a storage to store the result
5804 * This method is called by the runtime on attempts to load fields of
5805 * transparent proxy objects. @this points to such TP, @klass is the class of
5806 * the object containing @field. @res is a storage location which can be
5807 * used to store the result.
5809 * Returns: an address pointing to the value of field.
5812 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5814 static MonoMethod *getter = NULL;
5815 MonoDomain *domain = mono_domain_get ();
5816 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5817 MonoClass *field_class;
5818 MonoMethodMessage *msg;
5819 MonoArray *out_args;
5823 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5824 g_assert (res != NULL);
5826 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5827 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5832 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5836 field_class = mono_class_from_mono_type (field->type);
5838 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5839 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5840 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5842 full_name = mono_type_get_full_name (klass);
5843 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5844 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5847 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5849 if (exc) mono_raise_exception ((MonoException *)exc);
5851 if (mono_array_length (out_args) == 0)
5854 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5856 if (field_class->valuetype) {
5857 return ((char *)*res) + sizeof (MonoObject);
5863 * mono_load_remote_field_new:
5868 * Missing documentation.
5871 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5873 static MonoMethod *getter = NULL;
5874 MonoDomain *domain = mono_domain_get ();
5875 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5876 MonoClass *field_class;
5877 MonoMethodMessage *msg;
5878 MonoArray *out_args;
5879 MonoObject *exc, *res;
5882 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5884 field_class = mono_class_from_mono_type (field->type);
5886 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5888 if (field_class->valuetype) {
5889 res = mono_object_new (domain, field_class);
5890 val = ((gchar *) res) + sizeof (MonoObject);
5894 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5899 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5903 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5904 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5906 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5908 full_name = mono_type_get_full_name (klass);
5909 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5910 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5913 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5915 if (exc) mono_raise_exception ((MonoException *)exc);
5917 if (mono_array_length (out_args) == 0)
5920 res = mono_array_get (out_args, MonoObject *, 0);
5926 * mono_store_remote_field:
5927 * @this: pointer to an object
5928 * @klass: klass of the object containing @field
5929 * @field: the field to load
5930 * @val: the value/object to store
5932 * This method is called by the runtime on attempts to store fields of
5933 * transparent proxy objects. @this points to such TP, @klass is the class of
5934 * the object containing @field. @val is the new value to store in @field.
5937 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5939 static MonoMethod *setter = NULL;
5940 MonoDomain *domain = mono_domain_get ();
5941 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5942 MonoClass *field_class;
5943 MonoMethodMessage *msg;
5944 MonoArray *out_args;
5949 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5951 field_class = mono_class_from_mono_type (field->type);
5953 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5954 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5955 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5960 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5964 if (field_class->valuetype)
5965 arg = mono_value_box (domain, field_class, val);
5967 arg = *((MonoObject **)val);
5970 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5971 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5973 full_name = mono_type_get_full_name (klass);
5974 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5975 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
5976 mono_array_setref (msg->args, 2, arg);
5979 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5981 if (exc) mono_raise_exception ((MonoException *)exc);
5985 * mono_store_remote_field_new:
5991 * Missing documentation
5994 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5996 static MonoMethod *setter = NULL;
5997 MonoDomain *domain = mono_domain_get ();
5998 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5999 MonoClass *field_class;
6000 MonoMethodMessage *msg;
6001 MonoArray *out_args;
6005 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
6007 field_class = mono_class_from_mono_type (field->type);
6009 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
6010 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6011 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6016 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6020 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6021 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6023 full_name = mono_type_get_full_name (klass);
6024 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6025 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6026 mono_array_setref (msg->args, 2, arg);
6029 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6031 if (exc) mono_raise_exception ((MonoException *)exc);
6035 * mono_create_ftnptr:
6037 * Given a function address, create a function descriptor for it.
6038 * This is only needed on some platforms.
6041 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6043 return callbacks.create_ftnptr (domain, addr);
6047 * mono_get_addr_from_ftnptr:
6049 * Given a pointer to a function descriptor, return the function address.
6050 * This is only needed on some platforms.
6053 mono_get_addr_from_ftnptr (gpointer descr)
6055 return callbacks.get_addr_from_ftnptr (descr);
6060 * mono_string_chars:
6063 * Returns a pointer to the UCS16 characters stored in the MonoString
6066 mono_string_chars(MonoString *s)
6068 /* This method is here only for documentation extraction, this is a macro */
6072 * mono_string_length:
6075 * Returns the lenght in characters of the string
6078 mono_string_length (MonoString *s)
6080 /* This method is here only for documentation extraction, this is a macro */