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-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/threadpool.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internal.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include "cominterop.h"
48 #if defined(HAVE_BOEHM_GC)
49 #define NEED_TO_ZERO_PTRFREE 1
50 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
51 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
52 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
53 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
54 #elif defined(HAVE_SGEN_GC)
55 #define GC_NO_DESCRIPTOR (NULL)
56 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
57 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
58 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
60 #define NEED_TO_ZERO_PTRFREE 1
61 #define GC_NO_DESCRIPTOR (NULL)
62 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
63 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
64 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
67 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
68 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
71 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
74 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
77 free_main_args (void);
80 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
83 #define ldstr_lock() mono_mutex_lock (&ldstr_section)
84 #define ldstr_unlock() mono_mutex_unlock (&ldstr_section)
85 static mono_mutex_t ldstr_section;
87 static gboolean profile_allocs = TRUE;
90 mono_runtime_object_init (MonoObject *this)
92 MonoMethod *method = NULL;
93 MonoClass *klass = this->vtable->klass;
95 method = mono_class_get_method_from_name (klass, ".ctor", 0);
97 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
99 if (method->klass->valuetype)
100 this = mono_object_unbox (this);
101 mono_runtime_invoke (method, this, NULL, NULL);
104 /* The pseudo algorithm for type initialization from the spec
105 Note it doesn't say anything about domains - only threads.
107 2. If the type is initialized you are done.
108 2.1. If the type is not yet initialized, try to take an
110 2.2. If successful, record this thread as responsible for
111 initializing the type and proceed to step 2.3.
112 2.2.1. If not, see whether this thread or any thread
113 waiting for this thread to complete already holds the lock.
114 2.2.2. If so, return since blocking would create a deadlock. This thread
115 will now see an incompletely initialized state for the type,
116 but no deadlock will arise.
117 2.2.3 If not, block until the type is initialized then return.
118 2.3 Initialize the parent type and then all interfaces implemented
120 2.4 Execute the type initialization code for this type.
121 2.5 Mark the type as initialized, release the initialization lock,
122 awaken any threads waiting for this type to be initialized,
129 guint32 initializing_tid;
130 guint32 waiting_count;
132 mono_mutex_t initialization_section;
133 } TypeInitializationLock;
135 /* for locking access to type_initialization_hash and blocked_thread_hash */
136 #define mono_type_initialization_lock() mono_mutex_lock (&type_initialization_section)
137 #define mono_type_initialization_unlock() mono_mutex_unlock (&type_initialization_section)
138 static mono_mutex_t type_initialization_section;
142 mono_type_init_lock (TypeInitializationLock *lock)
145 mono_mutex_lock (&lock->initialization_section);
146 MONO_FINISH_TRY_BLOCKING
150 mono_type_init_unlock (TypeInitializationLock *lock)
152 mono_mutex_unlock (&lock->initialization_section);
155 /* from vtable to lock */
156 static GHashTable *type_initialization_hash;
158 /* from thread id to thread id being waited on */
159 static GHashTable *blocked_thread_hash;
162 static MonoThread *main_thread;
164 /* Functions supplied by the runtime */
165 static MonoRuntimeCallbacks callbacks;
168 * mono_thread_set_main:
169 * @thread: thread to set as the main thread
171 * This function can be used to instruct the runtime to treat @thread
172 * as the main thread, ie, the thread that would normally execute the Main()
173 * method. This basically means that at the end of @thread, the runtime will
174 * wait for the existing foreground threads to quit and other such details.
177 mono_thread_set_main (MonoThread *thread)
179 static gboolean registered = FALSE;
182 MONO_GC_REGISTER_ROOT_SINGLE (main_thread);
186 main_thread = thread;
190 mono_thread_get_main (void)
196 mono_type_initialization_init (void)
198 mono_mutex_init_recursive (&type_initialization_section);
199 type_initialization_hash = g_hash_table_new (NULL, NULL);
200 blocked_thread_hash = g_hash_table_new (NULL, NULL);
201 mono_mutex_init_recursive (&ldstr_section);
205 mono_type_initialization_cleanup (void)
208 /* This is causing race conditions with
209 * mono_release_type_locks
211 mono_mutex_destroy (&type_initialization_section);
212 g_hash_table_destroy (type_initialization_hash);
213 type_initialization_hash = NULL;
215 mono_mutex_destroy (&ldstr_section);
216 g_hash_table_destroy (blocked_thread_hash);
217 blocked_thread_hash = NULL;
223 * get_type_init_exception_for_vtable:
225 * Return the stored type initialization exception for VTABLE.
227 static MonoException*
228 get_type_init_exception_for_vtable (MonoVTable *vtable)
230 MonoDomain *domain = vtable->domain;
231 MonoClass *klass = vtable->klass;
235 if (!vtable->init_failed)
236 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
239 * If the initializing thread was rudely aborted, the exception is not stored
243 mono_domain_lock (domain);
244 if (domain->type_init_exception_hash)
245 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
246 mono_domain_unlock (domain);
249 if (klass->name_space && *klass->name_space)
250 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
252 full_name = g_strdup (klass->name);
253 ex = mono_get_exception_type_initialization (full_name, NULL);
260 * mono_runtime_class_init:
261 * @vtable: vtable that needs to be initialized
263 * This routine calls the class constructor for @vtable.
266 mono_runtime_class_init (MonoVTable *vtable)
268 mono_runtime_class_init_full (vtable, TRUE);
272 * mono_runtime_class_init_full:
273 * @vtable that neeeds to be initialized
274 * @raise_exception is TRUE, exceptions are raised intead of returned
278 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
281 MonoException *exc_to_throw;
282 MonoMethod *method = NULL;
286 if (vtable->initialized)
290 klass = vtable->klass;
292 if (!klass->image->checked_module_cctor) {
293 mono_image_check_for_module_cctor (klass->image);
294 if (klass->image->has_module_cctor) {
296 MonoClass *module_klass;
297 MonoVTable *module_vtable;
299 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
301 exc = mono_error_convert_to_exception (&error);
303 mono_raise_exception (exc);
307 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
310 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
315 method = mono_class_get_cctor (klass);
318 MonoDomain *domain = vtable->domain;
319 TypeInitializationLock *lock;
320 guint32 tid = GetCurrentThreadId();
321 int do_initialization = 0;
322 MonoDomain *last_domain = NULL;
324 mono_type_initialization_lock ();
325 /* double check... */
326 if (vtable->initialized) {
327 mono_type_initialization_unlock ();
330 if (vtable->init_failed) {
331 mono_type_initialization_unlock ();
333 /* The type initialization already failed once, rethrow the same exception */
335 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
336 return get_type_init_exception_for_vtable (vtable);
338 lock = g_hash_table_lookup (type_initialization_hash, vtable);
340 /* This thread will get to do the initialization */
341 if (mono_domain_get () != domain) {
342 /* Transfer into the target domain */
343 last_domain = mono_domain_get ();
344 if (!mono_domain_set (domain, FALSE)) {
345 vtable->initialized = 1;
346 mono_type_initialization_unlock ();
348 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
349 return mono_get_exception_appdomain_unloaded ();
352 lock = g_malloc (sizeof(TypeInitializationLock));
353 mono_mutex_init_recursive (&lock->initialization_section);
354 lock->initializing_tid = tid;
355 lock->waiting_count = 1;
357 /* grab the vtable lock while this thread still owns type_initialization_section */
358 mono_type_init_lock (lock);
359 g_hash_table_insert (type_initialization_hash, vtable, lock);
360 do_initialization = 1;
363 TypeInitializationLock *pending_lock;
365 if (lock->initializing_tid == tid || lock->done) {
366 mono_type_initialization_unlock ();
369 /* see if the thread doing the initialization is already blocked on this thread */
370 blocked = GUINT_TO_POINTER (lock->initializing_tid);
371 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
372 if (pending_lock->initializing_tid == tid) {
373 if (!pending_lock->done) {
374 mono_type_initialization_unlock ();
377 /* the thread doing the initialization is blocked on this thread,
378 but on a lock that has already been freed. It just hasn't got
383 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
385 ++lock->waiting_count;
386 /* record the fact that we are waiting on the initializing thread */
387 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
389 mono_type_initialization_unlock ();
391 if (do_initialization) {
392 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
394 /* If the initialization failed, mark the class as unusable. */
395 /* Avoid infinite loops */
397 (klass->image == mono_defaults.corlib &&
398 !strcmp (klass->name_space, "System") &&
399 !strcmp (klass->name, "TypeInitializationException")))) {
400 vtable->init_failed = 1;
402 if (klass->name_space && *klass->name_space)
403 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
405 full_name = g_strdup (klass->name);
406 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
410 * Store the exception object so it could be thrown on subsequent
413 mono_domain_lock (domain);
414 if (!domain->type_init_exception_hash)
415 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
416 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
417 mono_domain_unlock (domain);
421 mono_domain_set (last_domain, TRUE);
423 mono_type_init_unlock (lock);
425 /* this just blocks until the initializing thread is done */
426 mono_type_init_lock (lock);
427 mono_type_init_unlock (lock);
430 mono_type_initialization_lock ();
431 if (lock->initializing_tid != tid)
432 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
433 --lock->waiting_count;
434 if (lock->waiting_count == 0) {
435 mono_mutex_destroy (&lock->initialization_section);
436 g_hash_table_remove (type_initialization_hash, vtable);
439 mono_memory_barrier ();
440 if (!vtable->init_failed)
441 vtable->initialized = 1;
442 mono_type_initialization_unlock ();
444 if (vtable->init_failed) {
445 /* Either we were the initializing thread or we waited for the initialization */
447 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
448 return get_type_init_exception_for_vtable (vtable);
451 vtable->initialized = 1;
458 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
460 MonoVTable *vtable = (MonoVTable*)key;
462 TypeInitializationLock *lock = (TypeInitializationLock*) value;
463 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
466 * Have to set this since it cannot be set by the normal code in
467 * mono_runtime_class_init (). In this case, the exception object is not stored,
468 * and get_type_init_exception_for_class () needs to be aware of this.
470 vtable->init_failed = 1;
471 mono_type_init_unlock (lock);
472 --lock->waiting_count;
473 if (lock->waiting_count == 0) {
474 mono_mutex_destroy (&lock->initialization_section);
483 mono_release_type_locks (MonoInternalThread *thread)
485 mono_type_initialization_lock ();
486 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
487 mono_type_initialization_unlock ();
491 default_trampoline (MonoMethod *method)
497 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
499 g_assert_not_reached ();
504 #ifndef DISABLE_REMOTING
507 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
509 g_error ("remoting not installed");
513 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
517 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
519 g_assert_not_reached ();
523 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
524 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
525 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
526 static MonoImtThunkBuilder imt_thunk_builder;
527 #if (MONO_IMT_SIZE > 32)
528 #error "MONO_IMT_SIZE cannot be larger than 32"
532 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
534 memcpy (&callbacks, cbs, sizeof (*cbs));
537 MonoRuntimeCallbacks*
538 mono_get_runtime_callbacks (void)
544 mono_install_trampoline (MonoTrampoline func)
546 arch_create_jit_trampoline = func? func: default_trampoline;
550 mono_install_jump_trampoline (MonoJumpTrampoline func)
552 arch_create_jump_trampoline = func? func: default_jump_trampoline;
555 #ifndef DISABLE_REMOTING
557 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
559 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
564 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
566 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
570 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
571 imt_thunk_builder = func;
574 static MonoCompileFunc default_mono_compile_method = NULL;
577 * mono_install_compile_method:
578 * @func: function to install
580 * This is a VM internal routine
583 mono_install_compile_method (MonoCompileFunc func)
585 default_mono_compile_method = func;
589 * mono_compile_method:
590 * @method: The method to compile.
592 * This JIT-compiles the method, and returns the pointer to the native code
596 mono_compile_method (MonoMethod *method)
598 if (!default_mono_compile_method) {
599 g_error ("compile method called on uninitialized runtime");
602 return default_mono_compile_method (method);
606 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
608 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
612 mono_runtime_create_delegate_trampoline (MonoClass *klass)
614 return arch_create_delegate_trampoline (mono_domain_get (), klass);
617 static MonoFreeMethodFunc default_mono_free_method = NULL;
620 * mono_install_free_method:
621 * @func: pointer to the MonoFreeMethodFunc used to release a method
623 * This is an internal VM routine, it is used for the engines to
624 * register a handler to release the resources associated with a method.
626 * Methods are freed when no more references to the delegate that holds
630 mono_install_free_method (MonoFreeMethodFunc func)
632 default_mono_free_method = func;
636 * mono_runtime_free_method:
637 * @domain; domain where the method is hosted
638 * @method: method to release
640 * This routine is invoked to free the resources associated with
641 * a method that has been JIT compiled. This is used to discard
642 * methods that were used only temporarily (for example, used in marshalling)
646 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
648 if (default_mono_free_method != NULL)
649 default_mono_free_method (domain, method);
651 mono_method_clear_object (domain, method);
653 mono_free_method (method);
657 * The vtables in the root appdomain are assumed to be reachable by other
658 * roots, and we don't use typed allocation in the other domains.
661 /* The sync block is no longer a GC pointer */
662 #define GC_HEADER_BITMAP (0)
664 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
667 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
669 MonoClassField *field;
675 max_size = mono_class_data_size (class) / sizeof (gpointer);
677 max_size = class->instance_size / sizeof (gpointer);
678 if (max_size > size) {
679 g_assert (offset <= 0);
680 bitmap = g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
685 /*An Ephemeron cannot be marked by sgen*/
686 if (!static_fields && class->image == mono_defaults.corlib && !strcmp ("Ephemeron", class->name)) {
688 memset (bitmap, 0, size / 8);
693 for (p = class; p != NULL; p = p->parent) {
694 gpointer iter = NULL;
695 while ((field = mono_class_get_fields (p, &iter))) {
699 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
701 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
704 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
707 /* FIXME: should not happen, flag as type load error */
708 if (field->type->byref)
711 if (static_fields && field->offset == -1)
715 pos = field->offset / sizeof (gpointer);
718 type = mono_type_get_underlying_type (field->type);
719 switch (type->type) {
722 case MONO_TYPE_FNPTR:
724 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
729 if (class->image != mono_defaults.corlib)
732 case MONO_TYPE_STRING:
733 case MONO_TYPE_SZARRAY:
734 case MONO_TYPE_CLASS:
735 case MONO_TYPE_OBJECT:
736 case MONO_TYPE_ARRAY:
737 g_assert ((field->offset % sizeof(gpointer)) == 0);
739 g_assert (pos < size || pos <= max_size);
740 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
741 *max_set = MAX (*max_set, pos);
743 case MONO_TYPE_GENERICINST:
744 if (!mono_type_generic_inst_is_valuetype (type)) {
745 g_assert ((field->offset % sizeof(gpointer)) == 0);
747 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
748 *max_set = MAX (*max_set, pos);
753 case MONO_TYPE_VALUETYPE: {
754 MonoClass *fclass = mono_class_from_mono_type (field->type);
755 if (fclass->has_references) {
756 /* remove the object header */
757 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
771 case MONO_TYPE_BOOLEAN:
775 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
786 * mono_class_compute_bitmap:
788 * Mono internal function to compute a bitmap of reference fields in a class.
791 mono_class_compute_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
793 return compute_class_bitmap (class, bitmap, size, offset, max_set, static_fields);
798 * similar to the above, but sets the bits in the bitmap for any non-ref field
799 * and ignores static fields
802 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
804 MonoClassField *field;
809 max_size = class->instance_size / sizeof (gpointer);
810 if (max_size >= size) {
811 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
814 for (p = class; p != NULL; p = p->parent) {
815 gpointer iter = NULL;
816 while ((field = mono_class_get_fields (p, &iter))) {
819 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
821 /* FIXME: should not happen, flag as type load error */
822 if (field->type->byref)
825 pos = field->offset / sizeof (gpointer);
828 type = mono_type_get_underlying_type (field->type);
829 switch (type->type) {
830 #if SIZEOF_VOID_P == 8
834 case MONO_TYPE_FNPTR:
839 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
840 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
841 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
844 #if SIZEOF_VOID_P == 4
848 case MONO_TYPE_FNPTR:
853 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
854 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
855 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
861 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
862 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
863 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
866 case MONO_TYPE_BOOLEAN:
869 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
871 case MONO_TYPE_STRING:
872 case MONO_TYPE_SZARRAY:
873 case MONO_TYPE_CLASS:
874 case MONO_TYPE_OBJECT:
875 case MONO_TYPE_ARRAY:
877 case MONO_TYPE_GENERICINST:
878 if (!mono_type_generic_inst_is_valuetype (type)) {
883 case MONO_TYPE_VALUETYPE: {
884 MonoClass *fclass = mono_class_from_mono_type (field->type);
885 /* remove the object header */
886 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
890 g_assert_not_reached ();
899 * mono_class_insecure_overlapping:
900 * check if a class with explicit layout has references and non-references
901 * fields overlapping.
903 * Returns: TRUE if it is insecure to load the type.
906 mono_class_insecure_overlapping (MonoClass *klass)
910 gsize default_bitmap [4] = {0};
912 gsize default_nrbitmap [4] = {0};
913 int i, insecure = FALSE;
916 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
917 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
919 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
920 int idx = i % (sizeof (bitmap [0]) * 8);
921 if (bitmap [idx] & nrbitmap [idx]) {
926 if (bitmap != default_bitmap)
928 if (nrbitmap != default_nrbitmap)
931 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
939 mono_string_alloc (int length)
941 return mono_string_new_size (mono_domain_get (), length);
945 mono_class_compute_gc_descriptor (MonoClass *class)
949 gsize default_bitmap [4] = {0};
950 static gboolean gcj_inited = FALSE;
955 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
956 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
957 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
958 mono_register_jit_icall (mono_string_alloc, "mono_string_alloc", mono_create_icall_signature ("object int"), FALSE);
961 mono_loader_unlock ();
965 mono_class_init (class);
967 if (class->gc_descr_inited)
970 class->gc_descr_inited = TRUE;
971 class->gc_descr = GC_NO_DESCRIPTOR;
973 bitmap = default_bitmap;
974 if (class == mono_defaults.string_class) {
975 class->gc_descr = (gpointer)mono_gc_make_descr_for_string (bitmap, 2);
976 } else if (class->rank) {
977 mono_class_compute_gc_descriptor (class->element_class);
978 if (MONO_TYPE_IS_REFERENCE (&class->element_class->byval_arg)) {
980 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
981 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
982 class->name_space, class->name);*/
984 /* remove the object header */
985 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
986 class->gc_descr = mono_gc_make_descr_for_array (class->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
987 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
988 class->name_space, class->name);*/
989 if (bitmap != default_bitmap)
993 /*static int count = 0;
996 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
997 class->gc_descr = (gpointer)mono_gc_make_descr_for_object (bitmap, max_set + 1, class->instance_size);
999 if (class->gc_descr == GC_NO_DESCRIPTOR)
1000 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1002 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1003 if (bitmap != default_bitmap)
1009 * field_is_special_static:
1010 * @fklass: The MonoClass to look up.
1011 * @field: The MonoClassField describing the field.
1013 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1014 * SPECIAL_STATIC_NONE otherwise.
1017 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1019 MonoCustomAttrInfo *ainfo;
1021 ainfo = mono_custom_attrs_from_field (fklass, field);
1024 for (i = 0; i < ainfo->num_attrs; ++i) {
1025 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1026 if (klass->image == mono_defaults.corlib) {
1027 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1028 mono_custom_attrs_free (ainfo);
1029 return SPECIAL_STATIC_THREAD;
1031 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1032 mono_custom_attrs_free (ainfo);
1033 return SPECIAL_STATIC_CONTEXT;
1037 mono_custom_attrs_free (ainfo);
1038 return SPECIAL_STATIC_NONE;
1041 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1042 #define mix(a,b,c) { \
1043 a -= c; a ^= rot(c, 4); c += b; \
1044 b -= a; b ^= rot(a, 6); a += c; \
1045 c -= b; c ^= rot(b, 8); b += a; \
1046 a -= c; a ^= rot(c,16); c += b; \
1047 b -= a; b ^= rot(a,19); a += c; \
1048 c -= b; c ^= rot(b, 4); b += a; \
1050 #define final(a,b,c) { \
1051 c ^= b; c -= rot(b,14); \
1052 a ^= c; a -= rot(c,11); \
1053 b ^= a; b -= rot(a,25); \
1054 c ^= b; c -= rot(b,16); \
1055 a ^= c; a -= rot(c,4); \
1056 b ^= a; b -= rot(a,14); \
1057 c ^= b; c -= rot(b,24); \
1061 * mono_method_get_imt_slot:
1063 * The IMT slot is embedded into AOTed code, so this must return the same value
1064 * for the same method across all executions. This means:
1065 * - pointers shouldn't be used as hash values.
1066 * - mono_metadata_str_hash () should be used for hashing strings.
1069 mono_method_get_imt_slot (MonoMethod *method)
1071 MonoMethodSignature *sig;
1073 guint32 *hashes_start, *hashes;
1077 /* This can be used to stress tests the collision code */
1081 * We do this to simplify generic sharing. It will hurt
1082 * performance in cases where a class implements two different
1083 * instantiations of the same generic interface.
1084 * The code in build_imt_slots () depends on this.
1086 if (method->is_inflated)
1087 method = ((MonoMethodInflated*)method)->declaring;
1089 sig = mono_method_signature (method);
1090 hashes_count = sig->param_count + 4;
1091 hashes_start = malloc (hashes_count * sizeof (guint32));
1092 hashes = hashes_start;
1094 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1095 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1096 method->klass->name_space, method->klass->name, method->name);
1099 /* Initialize hashes */
1100 hashes [0] = mono_metadata_str_hash (method->klass->name);
1101 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1102 hashes [2] = mono_metadata_str_hash (method->name);
1103 hashes [3] = mono_metadata_type_hash (sig->ret);
1104 for (i = 0; i < sig->param_count; i++) {
1105 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1108 /* Setup internal state */
1109 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1111 /* Handle most of the hashes */
1112 while (hashes_count > 3) {
1121 /* Handle the last 3 hashes (all the case statements fall through) */
1122 switch (hashes_count) {
1123 case 3 : c += hashes [2];
1124 case 2 : b += hashes [1];
1125 case 1 : a += hashes [0];
1127 case 0: /* nothing left to add */
1131 free (hashes_start);
1132 /* Report the result */
1133 return c % MONO_IMT_SIZE;
1142 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1143 guint32 imt_slot = mono_method_get_imt_slot (method);
1144 MonoImtBuilderEntry *entry;
1146 if (slot_num >= 0 && imt_slot != slot_num) {
1147 /* we build just a single imt slot and this is not it */
1151 entry = g_malloc0 (sizeof (MonoImtBuilderEntry));
1152 entry->key = method;
1153 entry->value.vtable_slot = vtable_slot;
1154 entry->next = imt_builder [imt_slot];
1155 if (imt_builder [imt_slot] != NULL) {
1156 entry->children = imt_builder [imt_slot]->children + 1;
1157 if (entry->children == 1) {
1158 mono_stats.imt_slots_with_collisions++;
1159 *imt_collisions_bitmap |= (1 << imt_slot);
1162 entry->children = 0;
1163 mono_stats.imt_used_slots++;
1165 imt_builder [imt_slot] = entry;
1168 char *method_name = mono_method_full_name (method, TRUE);
1169 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1170 method, method_name, imt_slot, vtable_slot, entry->children);
1171 g_free (method_name);
1178 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1180 MonoMethod *method = e->key;
1181 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1185 method->klass->name_space,
1186 method->klass->name,
1189 printf (" * %s: NULL\n", message);
1195 compare_imt_builder_entries (const void *p1, const void *p2) {
1196 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1197 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1199 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1203 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1205 int count = end - start;
1206 int chunk_start = out_array->len;
1209 for (i = start; i < end; ++i) {
1210 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1211 item->key = sorted_array [i]->key;
1212 item->value = sorted_array [i]->value;
1213 item->has_target_code = sorted_array [i]->has_target_code;
1214 item->is_equals = TRUE;
1216 item->check_target_idx = out_array->len + 1;
1218 item->check_target_idx = 0;
1219 g_ptr_array_add (out_array, item);
1222 int middle = start + count / 2;
1223 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1225 item->key = sorted_array [middle]->key;
1226 item->is_equals = FALSE;
1227 g_ptr_array_add (out_array, item);
1228 imt_emit_ir (sorted_array, start, middle, out_array);
1229 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1235 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1236 int number_of_entries = entries->children + 1;
1237 MonoImtBuilderEntry **sorted_array = malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1238 GPtrArray *result = g_ptr_array_new ();
1239 MonoImtBuilderEntry *current_entry;
1242 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1243 sorted_array [i] = current_entry;
1245 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1247 /*for (i = 0; i < number_of_entries; i++) {
1248 print_imt_entry (" sorted array:", sorted_array [i], i);
1251 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1253 free (sorted_array);
1258 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1260 if (imt_builder_entry != NULL) {
1261 if (imt_builder_entry->children == 0 && !fail_tramp) {
1262 /* No collision, return the vtable slot contents */
1263 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1265 /* Collision, build the thunk */
1266 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1269 result = imt_thunk_builder (vtable, domain,
1270 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1271 for (i = 0; i < imt_ir->len; ++i)
1272 g_free (g_ptr_array_index (imt_ir, i));
1273 g_ptr_array_free (imt_ir, TRUE);
1285 static MonoImtBuilderEntry*
1286 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1289 * LOCKING: requires the loader and domain locks.
1293 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1297 guint32 imt_collisions_bitmap = 0;
1298 MonoImtBuilderEntry **imt_builder = calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1299 int method_count = 0;
1300 gboolean record_method_count_for_max_collisions = FALSE;
1301 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1304 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1306 for (i = 0; i < klass->interface_offsets_count; ++i) {
1307 MonoClass *iface = klass->interfaces_packed [i];
1308 int interface_offset = klass->interface_offsets_packed [i];
1309 int method_slot_in_interface, vt_slot;
1311 if (mono_class_has_variant_generic_params (iface))
1312 has_variant_iface = TRUE;
1314 mono_class_setup_methods (iface);
1315 vt_slot = interface_offset;
1316 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1319 if (slot_num >= 0 && iface->is_inflated) {
1321 * The imt slot of the method is the same as for its declaring method,
1322 * see the comment in mono_method_get_imt_slot (), so we can
1323 * avoid inflating methods which will be discarded by
1324 * add_imt_builder_entry anyway.
1326 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1327 if (mono_method_get_imt_slot (method) != slot_num) {
1332 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1333 if (method->is_generic) {
1334 has_generic_virtual = TRUE;
1339 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1340 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1345 if (extra_interfaces) {
1346 int interface_offset = klass->vtable_size;
1348 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1349 MonoClass* iface = list_item->data;
1350 int method_slot_in_interface;
1351 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1352 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1354 if (method->is_generic)
1355 has_generic_virtual = TRUE;
1356 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1358 interface_offset += iface->method.count;
1361 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1362 /* overwrite the imt slot only if we're building all the entries or if
1363 * we're building this specific one
1365 if (slot_num < 0 || i == slot_num) {
1366 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1369 if (imt_builder [i]) {
1370 MonoImtBuilderEntry *entry;
1372 /* Link entries with imt_builder [i] */
1373 for (entry = entries; entry->next; entry = entry->next) {
1375 MonoMethod *method = (MonoMethod*)entry->key;
1376 char *method_name = mono_method_full_name (method, TRUE);
1377 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1378 g_free (method_name);
1381 entry->next = imt_builder [i];
1382 entries->children += imt_builder [i]->children + 1;
1384 imt_builder [i] = entries;
1387 if (has_generic_virtual || has_variant_iface) {
1389 * There might be collisions later when the the thunk is expanded.
1391 imt_collisions_bitmap |= (1 << i);
1394 * The IMT thunk might be called with an instance of one of the
1395 * generic virtual methods, so has to fallback to the IMT trampoline.
1397 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (i));
1399 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1402 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1406 if (imt_builder [i] != NULL) {
1407 int methods_in_slot = imt_builder [i]->children + 1;
1408 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1409 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1410 record_method_count_for_max_collisions = TRUE;
1412 method_count += methods_in_slot;
1416 mono_stats.imt_number_of_methods += method_count;
1417 if (record_method_count_for_max_collisions) {
1418 mono_stats.imt_method_count_when_max_collisions = method_count;
1421 for (i = 0; i < MONO_IMT_SIZE; i++) {
1422 MonoImtBuilderEntry* entry = imt_builder [i];
1423 while (entry != NULL) {
1424 MonoImtBuilderEntry* next = entry->next;
1430 /* we OR the bitmap since we may build just a single imt slot at a time */
1431 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1435 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1436 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1440 * mono_vtable_build_imt_slot:
1441 * @vtable: virtual object table struct
1442 * @imt_slot: slot in the IMT table
1444 * Fill the given @imt_slot in the IMT table of @vtable with
1445 * a trampoline or a thunk for the case of collisions.
1446 * This is part of the internal mono API.
1448 * LOCKING: Take the domain lock.
1451 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1453 gpointer *imt = (gpointer*)vtable;
1454 imt -= MONO_IMT_SIZE;
1455 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1457 /* no support for extra interfaces: the proxy objects will need
1458 * to build the complete IMT
1459 * Update and heck needs to ahppen inside the proper domain lock, as all
1460 * the changes made to a MonoVTable.
1462 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1463 mono_domain_lock (vtable->domain);
1464 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1465 if (imt [imt_slot] == callbacks.get_imt_trampoline (imt_slot))
1466 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1467 mono_domain_unlock (vtable->domain);
1468 mono_loader_unlock ();
1473 * The first two free list entries both belong to the wait list: The
1474 * first entry is the pointer to the head of the list and the second
1475 * entry points to the last element. That way appending and removing
1476 * the first element are both O(1) operations.
1478 #ifdef MONO_SMALL_CONFIG
1479 #define NUM_FREE_LISTS 6
1481 #define NUM_FREE_LISTS 12
1483 #define FIRST_FREE_LIST_SIZE 64
1484 #define MAX_WAIT_LENGTH 50
1485 #define THUNK_THRESHOLD 10
1488 * LOCKING: The domain lock must be held.
1491 init_thunk_free_lists (MonoDomain *domain)
1493 if (domain->thunk_free_lists)
1495 domain->thunk_free_lists = mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1499 list_index_for_size (int item_size)
1502 int size = FIRST_FREE_LIST_SIZE;
1504 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1513 * mono_method_alloc_generic_virtual_thunk:
1515 * @size: size in bytes
1517 * Allocs size bytes to be used for the code of a generic virtual
1518 * thunk. It's either allocated from the domain's code manager or
1519 * reused from a previously invalidated piece.
1521 * LOCKING: The domain lock must be held.
1524 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1526 static gboolean inited = FALSE;
1527 static int generic_virtual_thunks_size = 0;
1531 MonoThunkFreeList **l;
1533 init_thunk_free_lists (domain);
1535 size += sizeof (guint32);
1536 if (size < sizeof (MonoThunkFreeList))
1537 size = sizeof (MonoThunkFreeList);
1539 i = list_index_for_size (size);
1540 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1541 if ((*l)->size >= size) {
1542 MonoThunkFreeList *item = *l;
1544 return ((guint32*)item) + 1;
1548 /* no suitable item found - search lists of larger sizes */
1549 while (++i < NUM_FREE_LISTS) {
1550 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1553 g_assert (item->size > size);
1554 domain->thunk_free_lists [i] = item->next;
1555 return ((guint32*)item) + 1;
1558 /* still nothing found - allocate it */
1560 mono_counters_register ("Generic virtual thunk bytes",
1561 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1564 generic_virtual_thunks_size += size;
1566 p = mono_domain_code_reserve (domain, size);
1569 mono_domain_lock (domain);
1570 if (!domain->generic_virtual_thunks)
1571 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1572 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1573 mono_domain_unlock (domain);
1579 * LOCKING: The domain lock must be held.
1582 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1585 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1586 gboolean found = FALSE;
1588 mono_domain_lock (domain);
1589 if (!domain->generic_virtual_thunks)
1590 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1591 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1593 mono_domain_unlock (domain);
1596 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1598 init_thunk_free_lists (domain);
1600 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1601 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1602 int length = item->length;
1605 /* unlink the first item from the wait list */
1606 domain->thunk_free_lists [0] = item->next;
1607 domain->thunk_free_lists [0]->length = length - 1;
1609 i = list_index_for_size (item->size);
1611 /* put it in the free list */
1612 item->next = domain->thunk_free_lists [i];
1613 domain->thunk_free_lists [i] = item;
1617 if (domain->thunk_free_lists [1]) {
1618 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1619 domain->thunk_free_lists [0]->length++;
1621 g_assert (!domain->thunk_free_lists [0]);
1623 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1624 domain->thunk_free_lists [0]->length = 1;
1628 typedef struct _GenericVirtualCase {
1632 struct _GenericVirtualCase *next;
1633 } GenericVirtualCase;
1636 * get_generic_virtual_entries:
1638 * Return IMT entries for the generic virtual method instances and
1639 * variant interface methods for vtable slot
1642 static MonoImtBuilderEntry*
1643 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1645 GenericVirtualCase *list;
1646 MonoImtBuilderEntry *entries;
1648 mono_domain_lock (domain);
1649 if (!domain->generic_virtual_cases)
1650 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1652 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1655 for (; list; list = list->next) {
1656 MonoImtBuilderEntry *entry;
1658 if (list->count < THUNK_THRESHOLD)
1661 entry = g_new0 (MonoImtBuilderEntry, 1);
1662 entry->key = list->method;
1663 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1664 entry->has_target_code = 1;
1666 entry->children = entries->children + 1;
1667 entry->next = entries;
1671 mono_domain_unlock (domain);
1673 /* FIXME: Leaking memory ? */
1678 * mono_method_add_generic_virtual_invocation:
1680 * @vtable_slot: pointer to the vtable slot
1681 * @method: the inflated generic virtual method
1682 * @code: the method's code
1684 * Registers a call via unmanaged code to a generic virtual method
1685 * instantiation or variant interface method. If the number of calls reaches a threshold
1686 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1687 * virtual method thunk.
1690 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1691 gpointer *vtable_slot,
1692 MonoMethod *method, gpointer code)
1694 static gboolean inited = FALSE;
1695 static int num_added = 0;
1697 GenericVirtualCase *gvc, *list;
1698 MonoImtBuilderEntry *entries;
1702 mono_domain_lock (domain);
1703 if (!domain->generic_virtual_cases)
1704 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1706 /* Check whether the case was already added */
1707 list = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 if (gvc->method == method)
1715 /* If not found, make a new one */
1717 gvc = mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1718 gvc->method = method;
1721 gvc->next = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1723 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1726 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1732 if (++gvc->count == THUNK_THRESHOLD) {
1733 gpointer *old_thunk = *vtable_slot;
1734 gpointer vtable_trampoline = NULL;
1735 gpointer imt_trampoline = NULL;
1737 if ((gpointer)vtable_slot < (gpointer)vtable) {
1738 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1739 int imt_slot = MONO_IMT_SIZE + displacement;
1741 /* Force the rebuild of the thunk at the next call */
1742 imt_trampoline = callbacks.get_imt_trampoline (imt_slot);
1743 *vtable_slot = imt_trampoline;
1745 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline ((gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1747 entries = get_generic_virtual_entries (domain, vtable_slot);
1749 sorted = imt_sort_slot_entries (entries);
1751 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1755 MonoImtBuilderEntry *next = entries->next;
1760 for (i = 0; i < sorted->len; ++i)
1761 g_free (g_ptr_array_index (sorted, i));
1762 g_ptr_array_free (sorted, TRUE);
1765 #ifndef __native_client__
1766 /* We don't re-use any thunks as there is a lot of overhead */
1767 /* to deleting and re-using code in Native Client. */
1768 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1769 invalidate_generic_virtual_thunk (domain, old_thunk);
1773 mono_domain_unlock (domain);
1776 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error);
1779 * mono_class_vtable:
1780 * @domain: the application domain
1781 * @class: the class to initialize
1783 * VTables are domain specific because we create domain specific code, and
1784 * they contain the domain specific static class data.
1785 * On failure, NULL is returned, and class->exception_type is set.
1788 mono_class_vtable (MonoDomain *domain, MonoClass *class)
1790 return mono_class_vtable_full (domain, class, FALSE);
1794 * mono_class_vtable_full:
1795 * @domain: the application domain
1796 * @class: the class to initialize
1797 * @raise_on_error if an exception should be raised on failure or not
1799 * VTables are domain specific because we create domain specific code, and
1800 * they contain the domain specific static class data.
1803 mono_class_vtable_full (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1805 MonoClassRuntimeInfo *runtime_info;
1809 if (class->exception_type) {
1811 mono_raise_exception (mono_class_get_exception_for_failure (class));
1815 /* this check can be inlined in jitted code, too */
1816 runtime_info = class->runtime_info;
1817 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1818 return runtime_info->domain_vtables [domain->domain_id];
1819 return mono_class_create_runtime_vtable (domain, class, raise_on_error);
1823 * mono_class_try_get_vtable:
1824 * @domain: the application domain
1825 * @class: the class to initialize
1827 * This function tries to get the associated vtable from @class if
1828 * it was already created.
1831 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *class)
1833 MonoClassRuntimeInfo *runtime_info;
1837 runtime_info = class->runtime_info;
1838 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1839 return runtime_info->domain_vtables [domain->domain_id];
1844 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1846 size_t alloc_offset;
1849 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1850 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1851 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1853 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1854 g_assert ((imt_table_bytes & 7) == 4);
1861 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1865 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class, gboolean raise_on_error)
1868 MonoClassRuntimeInfo *runtime_info, *old_info;
1869 MonoClassField *field;
1871 int i, vtable_slots;
1872 size_t imt_table_bytes;
1874 guint32 vtable_size, class_size;
1876 gpointer *interface_offsets;
1878 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1879 mono_domain_lock (domain);
1880 runtime_info = class->runtime_info;
1881 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1882 mono_domain_unlock (domain);
1883 mono_loader_unlock ();
1884 return runtime_info->domain_vtables [domain->domain_id];
1886 if (!class->inited || class->exception_type) {
1887 if (!mono_class_init (class) || class->exception_type) {
1888 mono_domain_unlock (domain);
1889 mono_loader_unlock ();
1891 mono_raise_exception (mono_class_get_exception_for_failure (class));
1896 /* Array types require that their element type be valid*/
1897 if (class->byval_arg.type == MONO_TYPE_ARRAY || class->byval_arg.type == MONO_TYPE_SZARRAY) {
1898 MonoClass *element_class = class->element_class;
1899 if (!element_class->inited)
1900 mono_class_init (element_class);
1902 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1903 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1904 mono_class_setup_vtable (element_class);
1906 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1907 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1908 if (class->exception_type == MONO_EXCEPTION_NONE)
1909 mono_class_set_failure (class, MONO_EXCEPTION_TYPE_LOAD, NULL);
1910 mono_domain_unlock (domain);
1911 mono_loader_unlock ();
1913 mono_raise_exception (mono_class_get_exception_for_failure (class));
1919 * For some classes, mono_class_init () already computed class->vtable_size, and
1920 * that is all that is needed because of the vtable trampolines.
1922 if (!class->vtable_size)
1923 mono_class_setup_vtable (class);
1925 if (class->generic_class && !class->vtable)
1926 mono_class_check_vtable_constraints (class, NULL);
1928 /* Initialize klass->has_finalize */
1929 mono_class_has_finalizer (class);
1931 if (class->exception_type) {
1932 mono_domain_unlock (domain);
1933 mono_loader_unlock ();
1935 mono_raise_exception (mono_class_get_exception_for_failure (class));
1939 vtable_slots = class->vtable_size;
1940 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1941 class_size = mono_class_data_size (class);
1945 if (class->interface_offsets_count) {
1946 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1947 mono_stats.imt_number_of_tables++;
1948 mono_stats.imt_tables_size += imt_table_bytes;
1950 imt_table_bytes = 0;
1953 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1955 mono_stats.used_class_count++;
1956 mono_stats.class_vtable_size += vtable_size;
1958 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1959 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1960 g_assert (!((gsize)vt & 7));
1963 vt->rank = class->rank;
1964 vt->domain = domain;
1966 mono_class_compute_gc_descriptor (class);
1968 * We can't use typed allocation in the non-root domains, since the
1969 * collector needs the GC descriptor stored in the vtable even after
1970 * the mempool containing the vtable is destroyed when the domain is
1971 * unloaded. An alternative might be to allocate vtables in the GC
1972 * heap, but this does not seem to work (it leads to crashes inside
1973 * libgc). If that approach is tried, two gc descriptors need to be
1974 * allocated for each class: one for the root domain, and one for all
1975 * other domains. The second descriptor should contain a bit for the
1976 * vtable field in MonoObject, since we can no longer assume the
1977 * vtable is reachable by other roots after the appdomain is unloaded.
1979 #ifdef HAVE_BOEHM_GC
1980 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1981 vt->gc_descr = GC_NO_DESCRIPTOR;
1984 vt->gc_descr = class->gc_descr;
1986 gc_bits = mono_gc_get_vtable_bits (class);
1987 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1989 vt->gc_bits = gc_bits;
1992 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1993 if (class->has_static_refs) {
1994 gpointer statics_gc_descr;
1996 gsize default_bitmap [4] = {0};
1999 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2000 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
2001 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2002 vt->vtable [class->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr);
2003 mono_domain_add_class_static_data (domain, class, vt->vtable [class->vtable_size], NULL);
2004 if (bitmap != default_bitmap)
2007 vt->vtable [class->vtable_size] = mono_domain_alloc0 (domain, class_size);
2009 vt->has_static_fields = TRUE;
2010 mono_stats.class_static_data_size += class_size;
2014 while ((field = mono_class_get_fields (class, &iter))) {
2015 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2017 if (mono_field_is_deleted (field))
2019 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2020 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
2021 if (special_static != SPECIAL_STATIC_NONE) {
2022 guint32 size, offset;
2024 gsize default_bitmap [4] = {0};
2029 if (mono_type_is_reference (field->type)) {
2030 default_bitmap [0] = 1;
2032 bitmap = default_bitmap;
2033 } else if (mono_type_is_struct (field->type)) {
2034 fclass = mono_class_from_mono_type (field->type);
2035 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2036 numbits = max_set + 1;
2038 default_bitmap [0] = 0;
2040 bitmap = default_bitmap;
2042 size = mono_type_size (field->type, &align);
2043 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2044 if (!domain->special_static_fields)
2045 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2046 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2047 if (bitmap != default_bitmap)
2050 * This marks the field as special static to speed up the
2051 * checks in mono_field_static_get/set_value ().
2057 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2058 MonoClass *fklass = mono_class_from_mono_type (field->type);
2059 const char *data = mono_field_get_data (field);
2061 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2062 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2063 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2066 if (fklass->valuetype) {
2067 memcpy (t, data, mono_class_value_size (fklass, NULL));
2069 /* it's a pointer type: add check */
2070 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2077 vt->max_interface_id = class->max_interface_id;
2078 vt->interface_bitmap = class->interface_bitmap;
2080 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2081 // class->name, class->interface_offsets_count);
2083 /* Initialize vtable */
2084 if (callbacks.get_vtable_trampoline) {
2085 // This also covers the AOT case
2086 for (i = 0; i < class->vtable_size; ++i) {
2087 vt->vtable [i] = callbacks.get_vtable_trampoline (i);
2090 mono_class_setup_vtable (class);
2092 for (i = 0; i < class->vtable_size; ++i) {
2095 if ((cm = class->vtable [i]))
2096 vt->vtable [i] = arch_create_jit_trampoline (cm);
2100 if (imt_table_bytes) {
2101 /* Now that the vtable is full, we can actually fill up the IMT */
2102 for (i = 0; i < MONO_IMT_SIZE; ++i)
2103 interface_offsets [i] = callbacks.get_imt_trampoline (i);
2107 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2108 * re-acquire them and check if another thread has created the vtable in the meantime.
2110 /* Special case System.MonoType to avoid infinite recursion */
2111 if (class != mono_defaults.monotype_class) {
2112 /*FIXME check for OOM*/
2113 vt->type = mono_type_get_object (domain, &class->byval_arg);
2114 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2115 /* This is unregistered in
2116 unregister_vtable_reflection_type() in
2118 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2121 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (class));
2123 /* class_vtable_array keeps an array of created vtables
2125 g_ptr_array_add (domain->class_vtable_array, vt);
2126 /* class->runtime_info is protected by the loader lock, both when
2127 * it it enlarged and when it is stored info.
2131 * Store the vtable in class->runtime_info.
2132 * class->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2134 mono_memory_barrier ();
2136 old_info = class->runtime_info;
2137 if (old_info && old_info->max_domain >= domain->domain_id) {
2138 /* someone already created a large enough runtime info */
2139 old_info->domain_vtables [domain->domain_id] = vt;
2141 int new_size = domain->domain_id;
2143 new_size = MAX (new_size, old_info->max_domain);
2145 /* make the new size a power of two */
2147 while (new_size > i)
2150 /* this is a bounded memory retention issue: may want to
2151 * handle it differently when we'll have a rcu-like system.
2153 runtime_info = mono_image_alloc0 (class->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2154 runtime_info->max_domain = new_size - 1;
2155 /* copy the stuff from the older info */
2157 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2159 runtime_info->domain_vtables [domain->domain_id] = vt;
2161 mono_memory_barrier ();
2162 class->runtime_info = runtime_info;
2165 if (class == mono_defaults.monotype_class) {
2166 /*FIXME check for OOM*/
2167 vt->type = mono_type_get_object (domain, &class->byval_arg);
2168 if (mono_object_get_class (vt->type) != mono_defaults.monotype_class)
2169 /* This is unregistered in
2170 unregister_vtable_reflection_type() in
2172 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type);
2175 mono_domain_unlock (domain);
2176 mono_loader_unlock ();
2178 /* make sure the parent is initialized */
2179 /*FIXME shouldn't this fail the current type?*/
2181 mono_class_vtable_full (domain, class->parent, raise_on_error);
2186 #ifndef DISABLE_REMOTING
2188 * mono_class_proxy_vtable:
2189 * @domain: the application domain
2190 * @remove_class: the remote class
2192 * Creates a vtable for transparent proxies. It is basically
2193 * a copy of the real vtable of the class wrapped in @remote_class,
2194 * but all function pointers invoke the remoting functions, and
2195 * vtable->klass points to the transparent proxy class, and not to @class.
2198 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2201 MonoVTable *vt, *pvt;
2202 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2204 GSList *extra_interfaces = NULL;
2205 MonoClass *class = remote_class->proxy_class;
2206 gpointer *interface_offsets;
2209 size_t imt_table_bytes;
2211 #ifdef COMPRESSED_INTERFACE_BITMAP
2215 vt = mono_class_vtable (domain, class);
2216 g_assert (vt); /*FIXME property handle failure*/
2217 max_interface_id = vt->max_interface_id;
2219 /* Calculate vtable space for extra interfaces */
2220 for (j = 0; j < remote_class->interface_count; j++) {
2221 MonoClass* iclass = remote_class->interfaces[j];
2225 /*FIXME test for interfaces with variant generic arguments*/
2226 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, iclass->interface_id))
2227 continue; /* interface implemented by the class */
2228 if (g_slist_find (extra_interfaces, iclass))
2231 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2233 method_count = mono_class_num_methods (iclass);
2235 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2236 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2238 for (i = 0; i < ifaces->len; ++i) {
2239 MonoClass *ic = g_ptr_array_index (ifaces, i);
2240 /*FIXME test for interfaces with variant generic arguments*/
2241 if (MONO_CLASS_IMPLEMENTS_INTERFACE (class, ic->interface_id))
2242 continue; /* interface implemented by the class */
2243 if (g_slist_find (extra_interfaces, ic))
2245 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2246 method_count += mono_class_num_methods (ic);
2248 g_ptr_array_free (ifaces, TRUE);
2251 extra_interface_vtsize += method_count * sizeof (gpointer);
2252 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2255 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2256 mono_stats.imt_number_of_tables++;
2257 mono_stats.imt_tables_size += imt_table_bytes;
2259 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer);
2261 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2263 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2264 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2265 g_assert (!((gsize)pvt & 7));
2267 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + class->vtable_size * sizeof (gpointer));
2269 pvt->klass = mono_defaults.transparent_proxy_class;
2270 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2271 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2273 /* initialize vtable */
2274 mono_class_setup_vtable (class);
2275 for (i = 0; i < class->vtable_size; ++i) {
2278 if ((cm = class->vtable [i]))
2279 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2281 pvt->vtable [i] = NULL;
2284 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2285 /* create trampolines for abstract methods */
2286 for (k = class; k; k = k->parent) {
2288 gpointer iter = NULL;
2289 while ((m = mono_class_get_methods (k, &iter)))
2290 if (!pvt->vtable [m->slot])
2291 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2295 pvt->max_interface_id = max_interface_id;
2296 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2297 #ifdef COMPRESSED_INTERFACE_BITMAP
2298 bitmap = g_malloc0 (bsize);
2300 bitmap = mono_domain_alloc0 (domain, bsize);
2303 for (i = 0; i < class->interface_offsets_count; ++i) {
2304 int interface_id = class->interfaces_packed [i]->interface_id;
2305 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2308 if (extra_interfaces) {
2309 int slot = class->vtable_size;
2315 /* Create trampolines for the methods of the interfaces */
2316 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2317 interf = list_item->data;
2319 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2323 while ((cm = mono_class_get_methods (interf, &iter)))
2324 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2326 slot += mono_class_num_methods (interf);
2330 /* Now that the vtable is full, we can actually fill up the IMT */
2331 build_imt (class, pvt, domain, interface_offsets, extra_interfaces);
2332 if (extra_interfaces) {
2333 g_slist_free (extra_interfaces);
2336 #ifdef COMPRESSED_INTERFACE_BITMAP
2337 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2338 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2339 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2342 pvt->interface_bitmap = bitmap;
2347 #endif /* DISABLE_REMOTING */
2350 * mono_class_field_is_special_static:
2352 * Returns whether @field is a thread/context static field.
2355 mono_class_field_is_special_static (MonoClassField *field)
2357 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2359 if (mono_field_is_deleted (field))
2361 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2362 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2369 * mono_class_field_get_special_static_type:
2370 * @field: The MonoClassField describing the field.
2372 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2373 * SPECIAL_STATIC_NONE otherwise.
2376 mono_class_field_get_special_static_type (MonoClassField *field)
2378 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2379 return SPECIAL_STATIC_NONE;
2380 if (mono_field_is_deleted (field))
2381 return SPECIAL_STATIC_NONE;
2382 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2383 return field_is_special_static (field->parent, field);
2384 return SPECIAL_STATIC_NONE;
2388 * mono_class_has_special_static_fields:
2390 * Returns whenever @klass has any thread/context static fields.
2393 mono_class_has_special_static_fields (MonoClass *klass)
2395 MonoClassField *field;
2399 while ((field = mono_class_get_fields (klass, &iter))) {
2400 g_assert (field->parent == klass);
2401 if (mono_class_field_is_special_static (field))
2408 #ifndef DISABLE_REMOTING
2410 * create_remote_class_key:
2411 * Creates an array of pointers that can be used as a hash key for a remote class.
2412 * The first element of the array is the number of pointers.
2415 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2420 if (remote_class == NULL) {
2421 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2422 key = g_malloc (sizeof(gpointer) * 3);
2423 key [0] = GINT_TO_POINTER (2);
2424 key [1] = mono_defaults.marshalbyrefobject_class;
2425 key [2] = extra_class;
2427 key = g_malloc (sizeof(gpointer) * 2);
2428 key [0] = GINT_TO_POINTER (1);
2429 key [1] = extra_class;
2432 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2433 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2434 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2435 key [1] = remote_class->proxy_class;
2437 // Keep the list of interfaces sorted
2438 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2439 if (extra_class && remote_class->interfaces [i] > extra_class) {
2440 key [j++] = extra_class;
2443 key [j] = remote_class->interfaces [i];
2446 key [j] = extra_class;
2448 // Replace the old class. The interface list is the same
2449 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2450 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2451 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2452 for (i = 0; i < remote_class->interface_count; i++)
2453 key [2 + i] = remote_class->interfaces [i];
2461 * copy_remote_class_key:
2463 * Make a copy of KEY in the domain and return the copy.
2466 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2468 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2469 gpointer *mp_key = mono_domain_alloc (domain, key_size);
2471 memcpy (mp_key, key, key_size);
2477 * mono_remote_class:
2478 * @domain: the application domain
2479 * @class_name: name of the remote class
2481 * Creates and initializes a MonoRemoteClass object for a remote type.
2483 * Can raise an exception on failure.
2486 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2489 MonoRemoteClass *rc;
2490 gpointer* key, *mp_key;
2493 key = create_remote_class_key (NULL, proxy_class);
2495 mono_domain_lock (domain);
2496 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2500 mono_domain_unlock (domain);
2504 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2505 if (!mono_error_ok (&error)) {
2507 mono_domain_unlock (domain);
2508 mono_error_raise_exception (&error);
2511 mp_key = copy_remote_class_key (domain, key);
2515 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2516 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2517 rc->interface_count = 1;
2518 rc->interfaces [0] = proxy_class;
2519 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2521 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2522 rc->interface_count = 0;
2523 rc->proxy_class = proxy_class;
2526 rc->default_vtable = NULL;
2527 rc->xdomain_vtable = NULL;
2528 rc->proxy_class_name = name;
2529 #ifndef DISABLE_PERFCOUNTERS
2530 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2533 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2535 mono_domain_unlock (domain);
2540 * clone_remote_class:
2541 * Creates a copy of the remote_class, adding the provided class or interface
2543 static MonoRemoteClass*
2544 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2546 MonoRemoteClass *rc;
2547 gpointer* key, *mp_key;
2549 key = create_remote_class_key (remote_class, extra_class);
2550 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
2556 mp_key = copy_remote_class_key (domain, key);
2560 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2562 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2563 rc->proxy_class = remote_class->proxy_class;
2564 rc->interface_count = remote_class->interface_count + 1;
2566 // Keep the list of interfaces sorted, since the hash key of
2567 // the remote class depends on this
2568 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2569 if (remote_class->interfaces [i] > extra_class && i == j)
2570 rc->interfaces [j++] = extra_class;
2571 rc->interfaces [j] = remote_class->interfaces [i];
2574 rc->interfaces [j] = extra_class;
2576 // Replace the old class. The interface array is the same
2577 rc = mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2578 rc->proxy_class = extra_class;
2579 rc->interface_count = remote_class->interface_count;
2580 if (rc->interface_count > 0)
2581 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2584 rc->default_vtable = NULL;
2585 rc->xdomain_vtable = NULL;
2586 rc->proxy_class_name = remote_class->proxy_class_name;
2588 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2594 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2596 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2597 mono_domain_lock (domain);
2598 if (rp->target_domain_id != -1) {
2599 if (remote_class->xdomain_vtable == NULL)
2600 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2601 mono_domain_unlock (domain);
2602 mono_loader_unlock ();
2603 return remote_class->xdomain_vtable;
2605 if (remote_class->default_vtable == NULL) {
2608 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2609 klass = mono_class_from_mono_type (type);
2611 if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2612 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2615 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2618 mono_domain_unlock (domain);
2619 mono_loader_unlock ();
2620 return remote_class->default_vtable;
2624 * mono_upgrade_remote_class:
2625 * @domain: the application domain
2626 * @tproxy: the proxy whose remote class has to be upgraded.
2627 * @klass: class to which the remote class can be casted.
2629 * Updates the vtable of the remote class by adding the necessary method slots
2630 * and interface offsets so it can be safely casted to klass. klass can be a
2631 * class or an interface.
2634 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2636 MonoTransparentProxy *tproxy;
2637 MonoRemoteClass *remote_class;
2638 gboolean redo_vtable;
2640 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2641 mono_domain_lock (domain);
2643 tproxy = (MonoTransparentProxy*) proxy_object;
2644 remote_class = tproxy->remote_class;
2646 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2649 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2650 if (remote_class->interfaces [i] == klass)
2651 redo_vtable = FALSE;
2654 redo_vtable = (remote_class->proxy_class != klass);
2658 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2659 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2662 mono_domain_unlock (domain);
2663 mono_loader_unlock ();
2665 #endif /* DISABLE_REMOTING */
2669 * mono_object_get_virtual_method:
2670 * @obj: object to operate on.
2673 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2674 * the instance of a callvirt of method.
2677 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2680 MonoMethod **vtable;
2681 gboolean is_proxy = FALSE;
2682 MonoMethod *res = NULL;
2684 klass = mono_object_class (obj);
2685 #ifndef DISABLE_REMOTING
2686 if (klass == mono_defaults.transparent_proxy_class) {
2687 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2692 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2695 mono_class_setup_vtable (klass);
2696 vtable = klass->vtable;
2698 if (method->slot == -1) {
2699 /* method->slot might not be set for instances of generic methods */
2700 if (method->is_inflated) {
2701 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2702 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2705 g_assert_not_reached ();
2709 /* check method->slot is a valid index: perform isinstance? */
2710 if (method->slot != -1) {
2711 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2713 gboolean variance_used = FALSE;
2714 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2715 g_assert (iface_offset > 0);
2716 res = vtable [iface_offset + method->slot];
2719 res = vtable [method->slot];
2723 #ifndef DISABLE_REMOTING
2725 /* It may be an interface, abstract class method or generic method */
2726 if (!res || mono_method_signature (res)->generic_param_count)
2729 /* generic methods demand invoke_with_check */
2730 if (mono_method_signature (res)->generic_param_count)
2731 res = mono_marshal_get_remoting_invoke_with_check (res);
2734 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2735 res = mono_cominterop_get_invoke (res);
2738 res = mono_marshal_get_remoting_invoke (res);
2743 if (method->is_inflated) {
2745 /* Have to inflate the result */
2746 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2747 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2757 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2759 g_error ("runtime invoke called on uninitialized runtime");
2763 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2766 * mono_runtime_invoke:
2767 * @method: method to invoke
2768 * @obJ: object instance
2769 * @params: arguments to the method
2770 * @exc: exception information.
2772 * Invokes the method represented by @method on the object @obj.
2774 * obj is the 'this' pointer, it should be NULL for static
2775 * methods, a MonoObject* for object instances and a pointer to
2776 * the value type for value types.
2778 * The params array contains the arguments to the method with the
2779 * same convention: MonoObject* pointers for object instances and
2780 * pointers to the value type otherwise.
2782 * From unmanaged code you'll usually use the
2783 * mono_runtime_invoke() variant.
2785 * Note that this function doesn't handle virtual methods for
2786 * you, it will exec the exact method you pass: we still need to
2787 * expose a function to lookup the derived class implementation
2788 * of a virtual method (there are examples of this in the code,
2791 * You can pass NULL as the exc argument if you don't want to
2792 * catch exceptions, otherwise, *exc will be set to the exception
2793 * thrown, if any. if an exception is thrown, you can't use the
2794 * MonoObject* result from the function.
2796 * If the method returns a value type, it is boxed in an object
2800 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2804 if (mono_runtime_get_no_exec ())
2805 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2807 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2808 mono_profiler_method_start_invoke (method);
2810 result = default_mono_runtime_invoke (method, obj, params, exc);
2812 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2813 mono_profiler_method_end_invoke (method);
2819 * mono_method_get_unmanaged_thunk:
2820 * @method: method to generate a thunk for.
2822 * Returns an unmanaged->managed thunk that can be used to call
2823 * a managed method directly from C.
2825 * The thunk's C signature closely matches the managed signature:
2827 * C#: public bool Equals (object obj);
2828 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2829 * MonoObject*, MonoException**);
2831 * The 1st ("this") parameter must not be used with static methods:
2833 * C#: public static bool ReferenceEquals (object a, object b);
2834 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2837 * The last argument must be a non-null pointer of a MonoException* pointer.
2838 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2839 * exception has been thrown in managed code. Otherwise it will point
2840 * to the MonoException* caught by the thunk. In this case, the result of
2841 * the thunk is undefined:
2843 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2844 * MonoException *ex = NULL;
2845 * Equals func = mono_method_get_unmanaged_thunk (method);
2846 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2848 * // handle exception
2851 * The calling convention of the thunk matches the platform's default
2852 * convention. This means that under Windows, C declarations must
2853 * contain the __stdcall attribute:
2855 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2856 * MonoObject*, MonoException**);
2860 * Value type arguments and return values are treated as they were objects:
2862 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2863 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2865 * Arguments must be properly boxed upon trunk's invocation, while return
2866 * values must be unboxed.
2869 mono_method_get_unmanaged_thunk (MonoMethod *method)
2871 method = mono_marshal_get_thunk_invoke_wrapper (method);
2872 return mono_compile_method (method);
2876 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2880 /* object fields cannot be byref, so we don't need a
2882 gpointer *p = (gpointer*)dest;
2889 case MONO_TYPE_BOOLEAN:
2891 case MONO_TYPE_U1: {
2892 guint8 *p = (guint8*)dest;
2893 *p = value ? *(guint8*)value : 0;
2898 case MONO_TYPE_CHAR: {
2899 guint16 *p = (guint16*)dest;
2900 *p = value ? *(guint16*)value : 0;
2903 #if SIZEOF_VOID_P == 4
2908 case MONO_TYPE_U4: {
2909 gint32 *p = (gint32*)dest;
2910 *p = value ? *(gint32*)value : 0;
2913 #if SIZEOF_VOID_P == 8
2918 case MONO_TYPE_U8: {
2919 gint64 *p = (gint64*)dest;
2920 *p = value ? *(gint64*)value : 0;
2923 case MONO_TYPE_R4: {
2924 float *p = (float*)dest;
2925 *p = value ? *(float*)value : 0;
2928 case MONO_TYPE_R8: {
2929 double *p = (double*)dest;
2930 *p = value ? *(double*)value : 0;
2933 case MONO_TYPE_STRING:
2934 case MONO_TYPE_SZARRAY:
2935 case MONO_TYPE_CLASS:
2936 case MONO_TYPE_OBJECT:
2937 case MONO_TYPE_ARRAY:
2938 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2940 case MONO_TYPE_FNPTR:
2941 case MONO_TYPE_PTR: {
2942 gpointer *p = (gpointer*)dest;
2943 *p = deref_pointer? *(gpointer*)value: value;
2946 case MONO_TYPE_VALUETYPE:
2947 /* note that 't' and 'type->type' can be different */
2948 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2949 t = mono_class_enum_basetype (type->data.klass)->type;
2952 MonoClass *class = mono_class_from_mono_type (type);
2953 int size = mono_class_value_size (class, NULL);
2955 mono_gc_bzero_atomic (dest, size);
2957 mono_gc_wbarrier_value_copy (dest, value, 1, class);
2960 case MONO_TYPE_GENERICINST:
2961 t = type->data.generic_class->container_class->byval_arg.type;
2964 g_error ("got type %x", type->type);
2969 * mono_field_set_value:
2970 * @obj: Instance object
2971 * @field: MonoClassField describing the field to set
2972 * @value: The value to be set
2974 * Sets the value of the field described by @field in the object instance @obj
2975 * to the value passed in @value. This method should only be used for instance
2976 * fields. For static fields, use mono_field_static_set_value.
2978 * The value must be on the native format of the field type.
2981 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2985 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2987 dest = (char*)obj + field->offset;
2988 mono_copy_value (field->type, dest, value, FALSE);
2992 * mono_field_static_set_value:
2993 * @field: MonoClassField describing the field to set
2994 * @value: The value to be set
2996 * Sets the value of the static field described by @field
2997 * to the value passed in @value.
2999 * The value must be on the native format of the field type.
3002 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3006 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3007 /* you cant set a constant! */
3008 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3010 if (field->offset == -1) {
3011 /* Special static */
3014 mono_domain_lock (vt->domain);
3015 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3016 mono_domain_unlock (vt->domain);
3017 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3019 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3021 mono_copy_value (field->type, dest, value, FALSE);
3025 * mono_vtable_get_static_field_data:
3027 * Internal use function: return a pointer to the memory holding the static fields
3028 * for a class or NULL if there are no static fields.
3029 * This is exported only for use by the debugger.
3032 mono_vtable_get_static_field_data (MonoVTable *vt)
3034 if (!vt->has_static_fields)
3036 return vt->vtable [vt->klass->vtable_size];
3040 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3044 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3045 if (field->offset == -1) {
3046 /* Special static */
3049 mono_domain_lock (vt->domain);
3050 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3051 mono_domain_unlock (vt->domain);
3052 src = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3054 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3057 src = (guint8*)obj + field->offset;
3064 * mono_field_get_value:
3065 * @obj: Object instance
3066 * @field: MonoClassField describing the field to fetch information from
3067 * @value: pointer to the location where the value will be stored
3069 * Use this routine to get the value of the field @field in the object
3072 * The pointer provided by value must be of the field type, for reference
3073 * types this is a MonoObject*, for value types its the actual pointer to
3078 * mono_field_get_value (obj, int_field, &i);
3081 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3087 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3089 src = (char*)obj + field->offset;
3090 mono_copy_value (field->type, value, src, TRUE);
3094 * mono_field_get_value_object:
3095 * @domain: domain where the object will be created (if boxing)
3096 * @field: MonoClassField describing the field to fetch information from
3097 * @obj: The object instance for the field.
3099 * Returns: a new MonoObject with the value from the given field. If the
3100 * field represents a value type, the value is boxed.
3104 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3108 MonoVTable *vtable = NULL;
3110 gboolean is_static = FALSE;
3111 gboolean is_ref = FALSE;
3112 gboolean is_literal = FALSE;
3113 gboolean is_ptr = FALSE;
3115 MonoType *type = mono_field_get_type_checked (field, &error);
3117 if (!mono_error_ok (&error))
3118 mono_error_raise_exception (&error);
3120 switch (type->type) {
3121 case MONO_TYPE_STRING:
3122 case MONO_TYPE_OBJECT:
3123 case MONO_TYPE_CLASS:
3124 case MONO_TYPE_ARRAY:
3125 case MONO_TYPE_SZARRAY:
3130 case MONO_TYPE_BOOLEAN:
3133 case MONO_TYPE_CHAR:
3142 case MONO_TYPE_VALUETYPE:
3143 is_ref = type->byref;
3145 case MONO_TYPE_GENERICINST:
3146 is_ref = !mono_type_generic_inst_is_valuetype (type);
3152 g_error ("type 0x%x not handled in "
3153 "mono_field_get_value_object", type->type);
3157 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3160 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3164 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3165 if (!vtable->initialized)
3166 mono_runtime_class_init (vtable);
3174 get_default_field_value (domain, field, &o);
3175 } else if (is_static) {
3176 mono_field_static_get_value (vtable, field, &o);
3178 mono_field_get_value (obj, field, &o);
3184 static MonoMethod *m;
3190 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3191 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3197 get_default_field_value (domain, field, v);
3198 } else if (is_static) {
3199 mono_field_static_get_value (vtable, field, v);
3201 mono_field_get_value (obj, field, v);
3204 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3205 args [0] = ptr ? *ptr : NULL;
3206 args [1] = mono_type_get_object (mono_domain_get (), type);
3208 return mono_runtime_invoke (m, NULL, args, NULL);
3211 /* boxed value type */
3212 klass = mono_class_from_mono_type (type);
3214 if (mono_class_is_nullable (klass))
3215 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3217 o = mono_object_new (domain, klass);
3218 v = ((gchar *) o) + sizeof (MonoObject);
3221 get_default_field_value (domain, field, v);
3222 } else if (is_static) {
3223 mono_field_static_get_value (vtable, field, v);
3225 mono_field_get_value (obj, field, v);
3232 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3235 const char *p = blob;
3236 mono_metadata_decode_blob_size (p, &p);
3239 case MONO_TYPE_BOOLEAN:
3242 *(guint8 *) value = *p;
3244 case MONO_TYPE_CHAR:
3247 *(guint16*) value = read16 (p);
3251 *(guint32*) value = read32 (p);
3255 *(guint64*) value = read64 (p);
3258 readr4 (p, (float*) value);
3261 readr8 (p, (double*) value);
3263 case MONO_TYPE_STRING:
3264 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3266 case MONO_TYPE_CLASS:
3267 *(gpointer*) value = NULL;
3271 g_warning ("type 0x%02x should not be in constant table", type);
3277 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3279 MonoTypeEnum def_type;
3282 data = mono_class_get_field_default_value (field, &def_type);
3283 mono_get_constant_value_from_blob (domain, def_type, data, value);
3287 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3291 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3293 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3294 get_default_field_value (vt->domain, field, value);
3298 if (field->offset == -1) {
3299 /* Special static */
3300 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3301 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3303 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3305 mono_copy_value (field->type, value, src, TRUE);
3309 * mono_field_static_get_value:
3310 * @vt: vtable to the object
3311 * @field: MonoClassField describing the field to fetch information from
3312 * @value: where the value is returned
3314 * Use this routine to get the value of the static field @field value.
3316 * The pointer provided by value must be of the field type, for reference
3317 * types this is a MonoObject*, for value types its the actual pointer to
3322 * mono_field_static_get_value (vt, int_field, &i);
3325 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3327 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3331 * mono_property_set_value:
3332 * @prop: MonoProperty to set
3333 * @obj: instance object on which to act
3334 * @params: parameters to pass to the propery
3335 * @exc: optional exception
3337 * Invokes the property's set method with the given arguments on the
3338 * object instance obj (or NULL for static properties).
3340 * You can pass NULL as the exc argument if you don't want to
3341 * catch exceptions, otherwise, *exc will be set to the exception
3342 * thrown, if any. if an exception is thrown, you can't use the
3343 * MonoObject* result from the function.
3346 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3348 default_mono_runtime_invoke (prop->set, obj, params, exc);
3352 * mono_property_get_value:
3353 * @prop: MonoProperty to fetch
3354 * @obj: instance object on which to act
3355 * @params: parameters to pass to the propery
3356 * @exc: optional exception
3358 * Invokes the property's get method with the given arguments on the
3359 * object instance obj (or NULL for static properties).
3361 * You can pass NULL as the exc argument if you don't want to
3362 * catch exceptions, otherwise, *exc will be set to the exception
3363 * thrown, if any. if an exception is thrown, you can't use the
3364 * MonoObject* result from the function.
3366 * Returns: the value from invoking the get method on the property.
3369 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3371 return default_mono_runtime_invoke (prop->get, obj, params, exc);
3375 * mono_nullable_init:
3376 * @buf: The nullable structure to initialize.
3377 * @value: the value to initialize from
3378 * @klass: the type for the object
3380 * Initialize the nullable structure pointed to by @buf from @value which
3381 * should be a boxed value type. The size of @buf should be able to hold
3382 * as much data as the @klass->instance_size (which is the number of bytes
3383 * that will be copies).
3385 * Since Nullables have variable structure, we can not define a C
3386 * structure for them.
3389 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3391 MonoClass *param_class = klass->cast_class;
3393 mono_class_setup_fields_locking (klass);
3394 g_assert (klass->fields_inited);
3396 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3397 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3399 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3401 if (param_class->has_references)
3402 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3404 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3406 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3411 * mono_nullable_box:
3412 * @buf: The buffer representing the data to be boxed
3413 * @klass: the type to box it as.
3415 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3419 mono_nullable_box (guint8 *buf, MonoClass *klass)
3421 MonoClass *param_class = klass->cast_class;
3423 mono_class_setup_fields_locking (klass);
3424 g_assert (klass->fields_inited);
3426 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3427 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3429 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3430 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
3431 if (param_class->has_references)
3432 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3434 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3442 * mono_get_delegate_invoke:
3443 * @klass: The delegate class
3445 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3448 mono_get_delegate_invoke (MonoClass *klass)
3452 /* This is called at runtime, so avoid the slower search in metadata */
3453 mono_class_setup_methods (klass);
3454 if (klass->exception_type)
3456 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3461 * mono_get_delegate_begin_invoke:
3462 * @klass: The delegate class
3464 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3467 mono_get_delegate_begin_invoke (MonoClass *klass)
3471 /* This is called at runtime, so avoid the slower search in metadata */
3472 mono_class_setup_methods (klass);
3473 if (klass->exception_type)
3475 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3480 * mono_get_delegate_end_invoke:
3481 * @klass: The delegate class
3483 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3486 mono_get_delegate_end_invoke (MonoClass *klass)
3490 /* This is called at runtime, so avoid the slower search in metadata */
3491 mono_class_setup_methods (klass);
3492 if (klass->exception_type)
3494 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3499 * mono_runtime_delegate_invoke:
3500 * @delegate: pointer to a delegate object.
3501 * @params: parameters for the delegate.
3502 * @exc: Pointer to the exception result.
3504 * Invokes the delegate method @delegate with the parameters provided.
3506 * You can pass NULL as the exc argument if you don't want to
3507 * catch exceptions, otherwise, *exc will be set to the exception
3508 * thrown, if any. if an exception is thrown, you can't use the
3509 * MonoObject* result from the function.
3512 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3515 MonoClass *klass = delegate->vtable->klass;
3517 im = mono_get_delegate_invoke (klass);
3519 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3521 return mono_runtime_invoke (im, delegate, params, exc);
3524 static char **main_args = NULL;
3525 static int num_main_args = 0;
3528 * mono_runtime_get_main_args:
3530 * Returns: a MonoArray with the arguments passed to the main program
3533 mono_runtime_get_main_args (void)
3537 MonoDomain *domain = mono_domain_get ();
3539 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3541 for (i = 0; i < num_main_args; ++i)
3542 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3548 free_main_args (void)
3552 for (i = 0; i < num_main_args; ++i)
3553 g_free (main_args [i]);
3560 * mono_runtime_set_main_args:
3561 * @argc: number of arguments from the command line
3562 * @argv: array of strings from the command line
3564 * Set the command line arguments from an embedding application that doesn't otherwise call
3565 * mono_runtime_run_main ().
3568 mono_runtime_set_main_args (int argc, char* argv[])
3573 main_args = g_new0 (char*, argc);
3574 num_main_args = argc;
3576 for (i = 0; i < argc; ++i) {
3579 utf8_arg = mono_utf8_from_external (argv[i]);
3580 if (utf8_arg == NULL) {
3581 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3582 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3586 main_args [i] = utf8_arg;
3593 * mono_runtime_run_main:
3594 * @method: the method to start the application with (usually Main)
3595 * @argc: number of arguments from the command line
3596 * @argv: array of strings from the command line
3597 * @exc: excetption results
3599 * Execute a standard Main() method (argc/argv contains the
3600 * executable name). This method also sets the command line argument value
3601 * needed by System.Environment.
3606 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3610 MonoArray *args = NULL;
3611 MonoDomain *domain = mono_domain_get ();
3612 gchar *utf8_fullpath;
3613 MonoMethodSignature *sig;
3615 g_assert (method != NULL);
3617 mono_thread_set_main (mono_thread_current ());
3619 main_args = g_new0 (char*, argc);
3620 num_main_args = argc;
3622 if (!g_path_is_absolute (argv [0])) {
3623 gchar *basename = g_path_get_basename (argv [0]);
3624 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3628 utf8_fullpath = mono_utf8_from_external (fullpath);
3629 if(utf8_fullpath == NULL) {
3630 /* Printing the arg text will cause glib to
3631 * whinge about "Invalid UTF-8", but at least
3632 * its relevant, and shows the problem text
3635 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3636 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3643 utf8_fullpath = mono_utf8_from_external (argv[0]);
3644 if(utf8_fullpath == NULL) {
3645 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3646 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3651 main_args [0] = utf8_fullpath;
3653 for (i = 1; i < argc; ++i) {
3656 utf8_arg=mono_utf8_from_external (argv[i]);
3657 if(utf8_arg==NULL) {
3658 /* Ditto the comment about Invalid UTF-8 here */
3659 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3660 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3664 main_args [i] = utf8_arg;
3669 sig = mono_method_signature (method);
3671 g_print ("Unable to load Main method.\n");
3675 if (sig->param_count) {
3676 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3677 for (i = 0; i < argc; ++i) {
3678 /* The encodings should all work, given that
3679 * we've checked all these args for the
3682 gchar *str = mono_utf8_from_external (argv [i]);
3683 MonoString *arg = mono_string_new (domain, str);
3684 mono_array_setref (args, i, arg);
3688 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3691 mono_assembly_set_main (method->klass->image->assembly);
3693 return mono_runtime_exec_main (method, args, exc);
3697 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3699 static MonoMethod *serialize_method;
3704 if (!serialize_method) {
3705 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3706 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3709 if (!serialize_method) {
3714 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3718 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3726 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3728 static MonoMethod *deserialize_method;
3733 if (!deserialize_method) {
3734 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3735 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3737 if (!deserialize_method) {
3744 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3751 #ifndef DISABLE_REMOTING
3753 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3755 static MonoMethod *get_proxy_method;
3757 MonoDomain *domain = mono_domain_get ();
3758 MonoRealProxy *real_proxy;
3759 MonoReflectionType *reflection_type;
3760 MonoTransparentProxy *transparent_proxy;
3762 if (!get_proxy_method)
3763 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3765 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3767 real_proxy = (MonoRealProxy*) mono_object_new (domain, mono_defaults.real_proxy_class);
3768 reflection_type = mono_type_get_object (domain, &obj->vtable->klass->byval_arg);
3770 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3771 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3774 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3778 return (MonoObject*) transparent_proxy;
3780 #endif /* DISABLE_REMOTING */
3783 * mono_object_xdomain_representation
3785 * @target_domain: a domain
3786 * @exc: pointer to a MonoObject*
3788 * Creates a representation of obj in the domain target_domain. This
3789 * is either a copy of obj arrived through via serialization and
3790 * deserialization or a proxy, depending on whether the object is
3791 * serializable or marshal by ref. obj must not be in target_domain.
3793 * If the object cannot be represented in target_domain, NULL is
3794 * returned and *exc is set to an appropriate exception.
3797 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3799 MonoObject *deserialized = NULL;
3800 gboolean failure = FALSE;
3804 #ifndef DISABLE_REMOTING
3805 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3806 deserialized = make_transparent_proxy (obj, &failure, exc);
3811 MonoDomain *domain = mono_domain_get ();
3812 MonoObject *serialized;
3814 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3815 serialized = serialize_object (obj, &failure, exc);
3816 mono_domain_set_internal_with_options (target_domain, FALSE);
3818 deserialized = deserialize_object (serialized, &failure, exc);
3819 if (domain != target_domain)
3820 mono_domain_set_internal_with_options (domain, FALSE);
3823 return deserialized;
3826 /* Used in call_unhandled_exception_delegate */
3828 create_unhandled_exception_eventargs (MonoObject *exc)
3832 MonoMethod *method = NULL;
3833 MonoBoolean is_terminating = TRUE;
3836 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
3839 mono_class_init (klass);
3841 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
3842 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
3846 args [1] = &is_terminating;
3848 obj = mono_object_new (mono_domain_get (), klass);
3849 mono_runtime_invoke (method, obj, args, NULL);
3854 /* Used in mono_unhandled_exception */
3856 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
3857 MonoObject *e = NULL;
3859 MonoDomain *current_domain = mono_domain_get ();
3861 if (domain != current_domain)
3862 mono_domain_set_internal_with_options (domain, FALSE);
3864 g_assert (domain == mono_object_domain (domain->domain));
3866 if (mono_object_domain (exc) != domain) {
3867 MonoObject *serialization_exc;
3869 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
3871 if (serialization_exc) {
3873 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
3876 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
3877 "System.Runtime.Serialization", "SerializationException",
3878 "Could not serialize unhandled exception.");
3882 g_assert (mono_object_domain (exc) == domain);
3884 pa [0] = domain->domain;
3885 pa [1] = create_unhandled_exception_eventargs (exc);
3886 mono_runtime_delegate_invoke (delegate, pa, &e);
3888 if (domain != current_domain)
3889 mono_domain_set_internal_with_options (current_domain, FALSE);
3893 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
3894 if (!mono_error_ok (&error)) {
3895 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
3896 mono_error_cleanup (&error);
3898 g_warning ("exception inside UnhandledException handler: %s\n", msg);
3904 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
3907 * mono_runtime_unhandled_exception_policy_set:
3908 * @policy: the new policy
3910 * This is a VM internal routine.
3912 * Sets the runtime policy for handling unhandled exceptions.
3915 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
3916 runtime_unhandled_exception_policy = policy;
3920 * mono_runtime_unhandled_exception_policy_get:
3922 * This is a VM internal routine.
3924 * Gets the runtime policy for handling unhandled exceptions.
3926 MonoRuntimeUnhandledExceptionPolicy
3927 mono_runtime_unhandled_exception_policy_get (void) {
3928 return runtime_unhandled_exception_policy;
3932 * mono_unhandled_exception:
3933 * @exc: exception thrown
3935 * This is a VM internal routine.
3937 * We call this function when we detect an unhandled exception
3938 * in the default domain.
3940 * It invokes the * UnhandledException event in AppDomain or prints
3941 * a warning to the console
3944 mono_unhandled_exception (MonoObject *exc)
3946 MonoDomain *current_domain = mono_domain_get ();
3947 MonoDomain *root_domain = mono_get_root_domain ();
3948 MonoClassField *field;
3949 MonoObject *current_appdomain_delegate;
3950 MonoObject *root_appdomain_delegate;
3952 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
3953 "UnhandledException");
3956 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
3957 gboolean abort_process = (main_thread && (mono_thread_internal_current () == main_thread->internal_thread)) ||
3958 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT);
3959 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
3960 if (current_domain != root_domain) {
3961 current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
3963 current_appdomain_delegate = NULL;
3966 /* set exitcode only if we will abort the process */
3967 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
3969 mono_environment_exitcode_set (1);
3970 mono_print_unhandled_exception (exc);
3972 if (root_appdomain_delegate) {
3973 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
3975 if (current_appdomain_delegate) {
3976 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
3983 * mono_runtime_exec_managed_code:
3984 * @domain: Application domain
3985 * @main_func: function to invoke from the execution thread
3986 * @main_args: parameter to the main_func
3988 * Launch a new thread to execute a function
3990 * main_func is called back from the thread with main_args as the
3991 * parameter. The callback function is expected to start Main()
3992 * eventually. This function then waits for all managed threads to
3994 * It is not necesseray anymore to execute managed code in a subthread,
3995 * so this function should not be used anymore by default: just
3996 * execute the code and then call mono_thread_manage ().
3999 mono_runtime_exec_managed_code (MonoDomain *domain,
4000 MonoMainThreadFunc main_func,
4003 mono_thread_create (domain, main_func, main_args);
4005 mono_thread_manage ();
4009 * Execute a standard Main() method (args doesn't contain the
4013 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4018 MonoCustomAttrInfo* cinfo;
4019 gboolean has_stathread_attribute;
4020 MonoInternalThread* thread = mono_thread_internal_current ();
4026 domain = mono_object_domain (args);
4027 if (!domain->entry_assembly) {
4029 MonoAssembly *assembly;
4031 assembly = method->klass->image->assembly;
4032 domain->entry_assembly = assembly;
4033 /* Domains created from another domain already have application_base and configuration_file set */
4034 if (domain->setup->application_base == NULL) {
4035 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4038 if (domain->setup->configuration_file == NULL) {
4039 str = g_strconcat (assembly->image->name, ".config", NULL);
4040 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4042 mono_set_private_bin_path_from_config (domain);
4046 cinfo = mono_custom_attrs_from_method (method);
4048 static MonoClass *stathread_attribute = NULL;
4049 if (!stathread_attribute)
4050 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4051 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4053 mono_custom_attrs_free (cinfo);
4055 has_stathread_attribute = FALSE;
4057 if (has_stathread_attribute) {
4058 thread->apartment_state = ThreadApartmentState_STA;
4060 thread->apartment_state = ThreadApartmentState_MTA;
4062 mono_thread_init_apartment_state ();
4064 /* FIXME: check signature of method */
4065 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4067 res = mono_runtime_invoke (method, NULL, pa, exc);
4069 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4073 mono_environment_exitcode_set (rval);
4075 mono_runtime_invoke (method, NULL, pa, exc);
4079 /* If the return type of Main is void, only
4080 * set the exitcode if an exception was thrown
4081 * (we don't want to blow away an
4082 * explicitly-set exit code)
4085 mono_environment_exitcode_set (rval);
4093 * mono_install_runtime_invoke:
4094 * @func: Function to install
4096 * This is a VM internal routine
4099 mono_install_runtime_invoke (MonoInvokeFunc func)
4101 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
4106 * mono_runtime_invoke_array:
4107 * @method: method to invoke
4108 * @obJ: object instance
4109 * @params: arguments to the method
4110 * @exc: exception information.
4112 * Invokes the method represented by @method on the object @obj.
4114 * obj is the 'this' pointer, it should be NULL for static
4115 * methods, a MonoObject* for object instances and a pointer to
4116 * the value type for value types.
4118 * The params array contains the arguments to the method with the
4119 * same convention: MonoObject* pointers for object instances and
4120 * pointers to the value type otherwise. The _invoke_array
4121 * variant takes a C# object[] as the params argument (MonoArray
4122 * *params): in this case the value types are boxed inside the
4123 * respective reference representation.
4125 * From unmanaged code you'll usually use the
4126 * mono_runtime_invoke() variant.
4128 * Note that this function doesn't handle virtual methods for
4129 * you, it will exec the exact method you pass: we still need to
4130 * expose a function to lookup the derived class implementation
4131 * of a virtual method (there are examples of this in the code,
4134 * You can pass NULL as the exc argument if you don't want to
4135 * catch exceptions, otherwise, *exc will be set to the exception
4136 * thrown, if any. if an exception is thrown, you can't use the
4137 * MonoObject* result from the function.
4139 * If the method returns a value type, it is boxed in an object
4143 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4146 MonoMethodSignature *sig = mono_method_signature (method);
4147 gpointer *pa = NULL;
4150 gboolean has_byref_nullables = FALSE;
4152 if (NULL != params) {
4153 pa = alloca (sizeof (gpointer) * mono_array_length (params));
4154 for (i = 0; i < mono_array_length (params); i++) {
4155 MonoType *t = sig->params [i];
4161 case MONO_TYPE_BOOLEAN:
4164 case MONO_TYPE_CHAR:
4173 case MONO_TYPE_VALUETYPE:
4174 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4175 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4176 pa [i] = mono_array_get (params, MonoObject*, i);
4178 has_byref_nullables = TRUE;
4180 /* MS seems to create the objects if a null is passed in */
4181 if (!mono_array_get (params, MonoObject*, i))
4182 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i])));
4186 * We can't pass the unboxed vtype byref to the callee, since
4187 * that would mean the callee would be able to modify boxed
4188 * primitive types. So we (and MS) make a copy of the boxed
4189 * object, pass that to the callee, and replace the original
4190 * boxed object in the arg array with the copy.
4192 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4193 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4194 mono_array_setref (params, i, copy);
4197 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4200 case MONO_TYPE_STRING:
4201 case MONO_TYPE_OBJECT:
4202 case MONO_TYPE_CLASS:
4203 case MONO_TYPE_ARRAY:
4204 case MONO_TYPE_SZARRAY:
4206 pa [i] = mono_array_addr (params, MonoObject*, i);
4207 // FIXME: I need to check this code path
4209 pa [i] = mono_array_get (params, MonoObject*, i);
4211 case MONO_TYPE_GENERICINST:
4213 t = &t->data.generic_class->container_class->this_arg;
4215 t = &t->data.generic_class->container_class->byval_arg;
4217 case MONO_TYPE_PTR: {
4220 /* The argument should be an IntPtr */
4221 arg = mono_array_get (params, MonoObject*, i);
4225 g_assert (arg->vtable->klass == mono_defaults.int_class);
4226 pa [i] = ((MonoIntPtr*)arg)->m_value;
4231 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4236 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4239 if (mono_class_is_nullable (method->klass)) {
4240 /* Need to create a boxed vtype instead */
4246 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4250 obj = mono_object_new (mono_domain_get (), method->klass);
4251 g_assert (obj); /*maybe we should raise a TLE instead?*/
4252 #ifndef DISABLE_REMOTING
4253 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4254 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4257 if (method->klass->valuetype)
4258 o = mono_object_unbox (obj);
4261 } else if (method->klass->valuetype) {
4262 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4265 mono_runtime_invoke (method, o, pa, exc);
4268 if (mono_class_is_nullable (method->klass)) {
4269 MonoObject *nullable;
4271 /* Convert the unboxed vtype into a Nullable structure */
4272 nullable = mono_object_new (mono_domain_get (), method->klass);
4274 mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4275 obj = mono_object_unbox (nullable);
4278 /* obj must be already unboxed if needed */
4279 res = mono_runtime_invoke (method, obj, pa, exc);
4281 if (sig->ret->type == MONO_TYPE_PTR) {
4282 MonoClass *pointer_class;
4283 static MonoMethod *box_method;
4285 MonoObject *box_exc;
4288 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4289 * convert it to a Pointer object.
4291 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4293 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4295 g_assert (res->vtable->klass == mono_defaults.int_class);
4296 box_args [0] = ((MonoIntPtr*)res)->m_value;
4297 box_args [1] = mono_type_get_object (mono_domain_get (), sig->ret);
4298 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4299 g_assert (!box_exc);
4302 if (has_byref_nullables) {
4304 * The runtime invoke wrapper already converted byref nullables back,
4305 * and stored them in pa, we just need to copy them back to the
4308 for (i = 0; i < mono_array_length (params); i++) {
4309 MonoType *t = sig->params [i];
4311 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4312 mono_array_setref (params, i, pa [i]);
4321 arith_overflow (void)
4323 mono_raise_exception (mono_get_exception_overflow ());
4327 * mono_object_allocate:
4328 * @size: number of bytes to allocate
4330 * This is a very simplistic routine until we have our GC-aware
4333 * Returns: an allocated object of size @size, or NULL on failure.
4335 static inline void *
4336 mono_object_allocate (size_t size, MonoVTable *vtable)
4339 ALLOC_OBJECT (o, vtable, size);
4344 #ifndef HAVE_SGEN_GC
4346 * mono_object_allocate_ptrfree:
4347 * @size: number of bytes to allocate
4349 * Note that the memory allocated is not zeroed.
4350 * Returns: an allocated object of size @size, or NULL on failure.
4352 static inline void *
4353 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
4356 ALLOC_PTRFREE (o, vtable, size);
4361 static inline void *
4362 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
4365 ALLOC_TYPED (o, size, vtable);
4372 * @klass: the class of the object that we want to create
4374 * Returns: a newly created object whose definition is
4375 * looked up using @klass. This will not invoke any constructors,
4376 * so the consumer of this routine has to invoke any constructors on
4377 * its own to initialize the object.
4379 * It returns NULL on failure.
4382 mono_object_new (MonoDomain *domain, MonoClass *klass)
4386 vtable = mono_class_vtable (domain, klass);
4389 return mono_object_new_specific (vtable);
4393 * mono_object_new_pinned:
4395 * Same as mono_object_new, but the returned object will be pinned.
4396 * For SGEN, these objects will only be freed at appdomain unload.
4399 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass)
4403 vtable = mono_class_vtable (domain, klass);
4408 return mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4410 return mono_object_new_specific (vtable);
4415 * mono_object_new_specific:
4416 * @vtable: the vtable of the object that we want to create
4418 * Returns: A newly created object with class and domain specified
4422 mono_object_new_specific (MonoVTable *vtable)
4426 /* check for is_com_object for COM Interop */
4427 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4430 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4433 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4436 mono_class_init (klass);
4438 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4440 vtable->domain->create_proxy_for_type_method = im;
4443 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
4445 o = mono_runtime_invoke (im, NULL, pa, NULL);
4446 if (o != NULL) return o;
4449 return mono_object_new_alloc_specific (vtable);
4453 mono_object_new_alloc_specific (MonoVTable *vtable)
4457 if (!vtable->klass->has_references) {
4458 o = mono_object_new_ptrfree (vtable);
4459 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4460 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
4462 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4463 o = mono_object_allocate (vtable->klass->instance_size, vtable);
4465 if (G_UNLIKELY (vtable->klass->has_finalize))
4466 mono_object_register_finalizer (o);
4468 if (G_UNLIKELY (profile_allocs))
4469 mono_profiler_allocation (o, vtable->klass);
4474 mono_object_new_fast (MonoVTable *vtable)
4477 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
4482 mono_object_new_ptrfree (MonoVTable *vtable)
4485 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4486 #if NEED_TO_ZERO_PTRFREE
4487 /* an inline memset is much faster for the common vcase of small objects
4488 * note we assume the allocated size is a multiple of sizeof (void*).
4490 if (vtable->klass->instance_size < 128) {
4492 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
4493 p = (gpointer*)((char*)obj + sizeof (MonoObject));
4499 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
4506 mono_object_new_ptrfree_box (MonoVTable *vtable)
4509 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
4510 /* the object will be boxed right away, no need to memzero it */
4515 * mono_class_get_allocation_ftn:
4517 * @for_box: the object will be used for boxing
4518 * @pass_size_in_words:
4520 * Return the allocation function appropriate for the given class.
4524 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4526 *pass_size_in_words = FALSE;
4528 if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4529 profile_allocs = FALSE;
4531 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4532 return mono_object_new_specific;
4534 if (!vtable->klass->has_references) {
4535 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
4537 return mono_object_new_ptrfree_box;
4538 return mono_object_new_ptrfree;
4541 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4543 return mono_object_new_fast;
4546 * FIXME: This is actually slower than mono_object_new_fast, because
4547 * of the overhead of parameter passing.
4550 *pass_size_in_words = TRUE;
4551 #ifdef GC_REDIRECT_TO_LOCAL
4552 return GC_local_gcj_fast_malloc;
4554 return GC_gcj_fast_malloc;
4559 return mono_object_new_specific;
4563 * mono_object_new_from_token:
4564 * @image: Context where the type_token is hosted
4565 * @token: a token of the type that we want to create
4567 * Returns: A newly created object whose definition is
4568 * looked up using @token in the @image image
4571 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4576 class = mono_class_get_checked (image, token, &error);
4577 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4579 return mono_object_new (domain, class);
4584 * mono_object_clone:
4585 * @obj: the object to clone
4587 * Returns: A newly created object who is a shallow copy of @obj
4590 mono_object_clone (MonoObject *obj)
4593 int size = obj->vtable->klass->instance_size;
4595 if (obj->vtable->klass->rank)
4596 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4598 o = mono_object_allocate (size, obj->vtable);
4600 /* If the object doesn't contain references this will do a simple memmove. */
4601 mono_gc_wbarrier_object_copy (o, obj);
4603 if (G_UNLIKELY (profile_allocs))
4604 mono_profiler_allocation (o, obj->vtable->klass);
4606 if (obj->vtable->klass->has_finalize)
4607 mono_object_register_finalizer (o);
4612 * mono_array_full_copy:
4613 * @src: source array to copy
4614 * @dest: destination array
4616 * Copies the content of one array to another with exactly the same type and size.
4619 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4622 MonoClass *klass = src->obj.vtable->klass;
4624 g_assert (klass == dest->obj.vtable->klass);
4626 size = mono_array_length (src);
4627 g_assert (size == mono_array_length (dest));
4628 size *= mono_array_element_size (klass);
4630 if (klass->element_class->valuetype) {
4631 if (klass->element_class->has_references)
4632 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4634 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4636 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4639 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4644 * mono_array_clone_in_domain:
4645 * @domain: the domain in which the array will be cloned into
4646 * @array: the array to clone
4648 * This routine returns a copy of the array that is hosted on the
4649 * specified MonoDomain.
4652 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4657 MonoClass *klass = array->obj.vtable->klass;
4659 if (array->bounds == NULL) {
4660 size = mono_array_length (array);
4661 o = mono_array_new_full (domain, klass, &size, NULL);
4663 size *= mono_array_element_size (klass);
4665 if (klass->element_class->valuetype) {
4666 if (klass->element_class->has_references)
4667 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4669 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4671 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4674 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4679 sizes = alloca (klass->rank * sizeof(intptr_t) * 2);
4680 size = mono_array_element_size (klass);
4681 for (i = 0; i < klass->rank; ++i) {
4682 sizes [i] = array->bounds [i].length;
4683 size *= array->bounds [i].length;
4684 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4686 o = mono_array_new_full (domain, klass, sizes, (intptr_t*)sizes + klass->rank);
4688 if (klass->element_class->valuetype) {
4689 if (klass->element_class->has_references)
4690 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4692 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4694 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4697 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4705 * @array: the array to clone
4707 * Returns: A newly created array who is a shallow copy of @array
4710 mono_array_clone (MonoArray *array)
4712 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4715 /* helper macros to check for overflow when calculating the size of arrays */
4716 #ifdef MONO_BIG_ARRAYS
4717 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4718 #define MYGUINT_MAX MYGUINT64_MAX
4719 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4720 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4721 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4722 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4723 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4725 #define MYGUINT32_MAX 4294967295U
4726 #define MYGUINT_MAX MYGUINT32_MAX
4727 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4728 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4729 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4730 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4731 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4735 mono_array_calc_byte_len (MonoClass *class, uintptr_t len, uintptr_t *res)
4739 byte_len = mono_array_element_size (class);
4740 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
4743 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
4745 byte_len += sizeof (MonoArray);
4753 * mono_array_new_full:
4754 * @domain: domain where the object is created
4755 * @array_class: array class
4756 * @lengths: lengths for each dimension in the array
4757 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
4759 * This routine creates a new array objects with the given dimensions,
4760 * lower bounds and type.
4763 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
4765 uintptr_t byte_len = 0, len, bounds_size;
4768 MonoArrayBounds *bounds;
4772 if (!array_class->inited)
4773 mono_class_init (array_class);
4777 /* A single dimensional array with a 0 lower bound is the same as an szarray */
4778 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
4780 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
4784 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
4786 for (i = 0; i < array_class->rank; ++i) {
4787 if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
4789 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
4790 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4795 if (!mono_array_calc_byte_len (array_class, len, &byte_len))
4796 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4800 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
4801 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4802 byte_len = (byte_len + 3) & ~3;
4803 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
4804 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4805 byte_len += bounds_size;
4808 * Following three lines almost taken from mono_object_new ():
4809 * they need to be kept in sync.
4811 vtable = mono_class_vtable_full (domain, array_class, TRUE);
4812 #ifndef HAVE_SGEN_GC
4813 if (!array_class->has_references) {
4814 o = mono_object_allocate_ptrfree (byte_len, vtable);
4815 #if NEED_TO_ZERO_PTRFREE
4816 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4818 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4819 o = mono_object_allocate_spec (byte_len, vtable);
4821 o = mono_object_allocate (byte_len, vtable);
4824 array = (MonoArray*)o;
4825 array->max_length = len;
4828 bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
4829 array->bounds = bounds;
4833 o = mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
4835 o = mono_gc_alloc_vector (vtable, byte_len, len);
4836 array = (MonoArray*)o;
4838 bounds = array->bounds;
4842 for (i = 0; i < array_class->rank; ++i) {
4843 bounds [i].length = lengths [i];
4845 bounds [i].lower_bound = lower_bounds [i];
4849 if (G_UNLIKELY (profile_allocs))
4850 mono_profiler_allocation (o, array_class);
4857 * @domain: domain where the object is created
4858 * @eclass: element class
4859 * @n: number of array elements
4861 * This routine creates a new szarray with @n elements of type @eclass.
4864 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
4868 ac = mono_array_class_get (eclass, 1);
4871 return mono_array_new_specific (mono_class_vtable_full (domain, ac, TRUE), n);
4875 * mono_array_new_specific:
4876 * @vtable: a vtable in the appropriate domain for an initialized class
4877 * @n: number of array elements
4879 * This routine is a fast alternative to mono_array_new() for code which
4880 * can be sure about the domain it operates in.
4883 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
4889 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
4894 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
4895 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
4898 #ifndef HAVE_SGEN_GC
4899 if (!vtable->klass->has_references) {
4900 o = mono_object_allocate_ptrfree (byte_len, vtable);
4901 #if NEED_TO_ZERO_PTRFREE
4902 ((MonoArray*)o)->bounds = NULL;
4903 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
4905 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
4906 o = mono_object_allocate_spec (byte_len, vtable);
4908 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
4909 o = mono_object_allocate (byte_len, vtable);
4912 ao = (MonoArray *)o;
4915 o = mono_gc_alloc_vector (vtable, byte_len, n);
4919 if (G_UNLIKELY (profile_allocs))
4920 mono_profiler_allocation (o, vtable->klass);
4926 * mono_string_new_utf16:
4927 * @text: a pointer to an utf16 string
4928 * @len: the length of the string
4930 * Returns: A newly created string object which contains @text.
4933 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
4937 s = mono_string_new_size (domain, len);
4938 g_assert (s != NULL);
4940 memcpy (mono_string_chars (s), text, len * 2);
4946 * mono_string_new_utf32:
4947 * @text: a pointer to an utf32 string
4948 * @len: the length of the string
4950 * Returns: A newly created string object which contains @text.
4953 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
4956 mono_unichar2 *utf16_output = NULL;
4957 gint32 utf16_len = 0;
4958 GError *error = NULL;
4959 glong items_written;
4961 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &error);
4964 g_error_free (error);
4966 while (utf16_output [utf16_len]) utf16_len++;
4968 s = mono_string_new_size (domain, utf16_len);
4969 g_assert (s != NULL);
4971 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
4973 g_free (utf16_output);
4979 * mono_string_new_size:
4980 * @text: a pointer to an utf16 string
4981 * @len: the length of the string
4983 * Returns: A newly created string object of @len
4986 mono_string_new_size (MonoDomain *domain, gint32 len)
4992 /* check for overflow */
4993 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2))
4994 mono_gc_out_of_memory (-1);
4996 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
4997 g_assert (size > 0);
4999 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5002 #ifndef HAVE_SGEN_GC
5003 s = mono_object_allocate_ptrfree (size, vtable);
5007 s = mono_gc_alloc_string (vtable, size, len);
5009 #if NEED_TO_ZERO_PTRFREE
5012 if (G_UNLIKELY (profile_allocs))
5013 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
5019 * mono_string_new_len:
5020 * @text: a pointer to an utf8 string
5021 * @length: number of bytes in @text to consider
5023 * Returns: A newly created string object which contains @text.
5026 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5028 GError *error = NULL;
5029 MonoString *o = NULL;
5031 glong items_written;
5033 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5036 o = mono_string_new_utf16 (domain, ut, items_written);
5038 g_error_free (error);
5047 * @text: a pointer to an utf8 string
5049 * Returns: A newly created string object which contains @text.
5052 mono_string_new (MonoDomain *domain, const char *text)
5054 GError *error = NULL;
5055 MonoString *o = NULL;
5057 glong items_written;
5062 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5065 o = mono_string_new_utf16 (domain, ut, items_written);
5067 g_error_free (error);
5070 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5075 MonoString *o = NULL;
5077 if (!g_utf8_validate (text, -1, &end))
5080 len = g_utf8_strlen (text, -1);
5081 o = mono_string_new_size (domain, len);
5082 str = mono_string_chars (o);
5084 while (text < end) {
5085 *str++ = g_utf8_get_char (text);
5086 text = g_utf8_next_char (text);
5093 * mono_string_new_wrapper:
5094 * @text: pointer to utf8 characters.
5096 * Helper function to create a string object from @text in the current domain.
5099 mono_string_new_wrapper (const char *text)
5101 MonoDomain *domain = mono_domain_get ();
5104 return mono_string_new (domain, text);
5111 * @class: the class of the value
5112 * @value: a pointer to the unboxed data
5114 * Returns: A newly created object which contains @value.
5117 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
5123 g_assert (class->valuetype);
5124 if (mono_class_is_nullable (class))
5125 return mono_nullable_box (value, class);
5127 vtable = mono_class_vtable (domain, class);
5130 size = mono_class_instance_size (class);
5131 res = mono_object_new_alloc_specific (vtable);
5132 if (G_UNLIKELY (profile_allocs))
5133 mono_profiler_allocation (res, class);
5135 size = size - sizeof (MonoObject);
5138 g_assert (size == mono_class_value_size (class, NULL));
5139 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
5141 #if NO_UNALIGNED_ACCESS
5142 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5146 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5149 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5152 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5155 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5158 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5162 if (class->has_finalize)
5163 mono_object_register_finalizer (res);
5169 * @dest: destination pointer
5170 * @src: source pointer
5171 * @klass: a valuetype class
5173 * Copy a valuetype from @src to @dest. This function must be used
5174 * when @klass contains references fields.
5177 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5179 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5183 * mono_value_copy_array:
5184 * @dest: destination array
5185 * @dest_idx: index in the @dest array
5186 * @src: source pointer
5187 * @count: number of items
5189 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5190 * This function must be used when @klass contains references fields.
5191 * Overlap is handled.
5194 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5196 int size = mono_array_element_size (dest->obj.vtable->klass);
5197 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5198 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5199 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5203 * mono_object_get_domain:
5204 * @obj: object to query
5206 * Returns: the MonoDomain where the object is hosted
5209 mono_object_get_domain (MonoObject *obj)
5211 return mono_object_domain (obj);
5215 * mono_object_get_class:
5216 * @obj: object to query
5218 * Returns: the MonOClass of the object.
5221 mono_object_get_class (MonoObject *obj)
5223 return mono_object_class (obj);
5226 * mono_object_get_size:
5227 * @o: object to query
5229 * Returns: the size, in bytes, of @o
5232 mono_object_get_size (MonoObject* o)
5234 MonoClass* klass = mono_object_class (o);
5235 if (klass == mono_defaults.string_class) {
5236 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5237 } else if (o->vtable->rank) {
5238 MonoArray *array = (MonoArray*)o;
5239 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
5240 if (array->bounds) {
5243 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5247 return mono_class_instance_size (klass);
5252 * mono_object_unbox:
5253 * @obj: object to unbox
5255 * Returns: a pointer to the start of the valuetype boxed in this
5258 * This method will assert if the object passed is not a valuetype.
5261 mono_object_unbox (MonoObject *obj)
5263 /* add assert for valuetypes? */
5264 g_assert (obj->vtable->klass->valuetype);
5265 return ((char*)obj) + sizeof (MonoObject);
5269 * mono_object_isinst:
5271 * @klass: a pointer to a class
5273 * Returns: @obj if @obj is derived from @klass
5276 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5279 mono_class_init (klass);
5281 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5282 return mono_object_isinst_mbyref (obj, klass);
5287 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5291 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5300 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5301 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5305 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5306 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5309 MonoClass *oklass = vt->klass;
5310 if (mono_class_is_transparent_proxy (oklass))
5311 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5313 mono_class_setup_supertypes (klass);
5314 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5317 #ifndef DISABLE_REMOTING
5318 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5320 MonoDomain *domain = mono_domain_get ();
5322 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5323 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5324 MonoMethod *im = NULL;
5327 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5328 im = mono_object_get_virtual_method (rp, im);
5331 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
5334 res = mono_runtime_invoke (im, rp, pa, NULL);
5336 if (*(MonoBoolean *) mono_object_unbox(res)) {
5337 /* Update the vtable of the remote type, so it can safely cast to this new type */
5338 mono_upgrade_remote_class (domain, obj, klass);
5342 #endif /* DISABLE_REMOTING */
5347 * mono_object_castclass_mbyref:
5349 * @klass: a pointer to a class
5351 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5354 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5356 if (!obj) return NULL;
5357 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5359 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5361 "InvalidCastException"));
5366 MonoDomain *orig_domain;
5372 str_lookup (MonoDomain *domain, gpointer user_data)
5374 LDStrInfo *info = user_data;
5375 if (info->res || domain == info->orig_domain)
5377 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5383 mono_string_get_pinned (MonoString *str)
5387 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5388 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5390 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5391 news->length = mono_string_length (str);
5397 #define mono_string_get_pinned(str) (str)
5401 mono_string_is_interned_lookup (MonoString *str, int insert)
5403 MonoGHashTable *ldstr_table;
5404 MonoString *s, *res;
5407 domain = ((MonoObject *)str)->vtable->domain;
5408 ldstr_table = domain->ldstr_table;
5410 res = mono_g_hash_table_lookup (ldstr_table, str);
5416 /* Allocate outside the lock */
5418 s = mono_string_get_pinned (str);
5421 res = mono_g_hash_table_lookup (ldstr_table, str);
5426 mono_g_hash_table_insert (ldstr_table, s, s);
5431 LDStrInfo ldstr_info;
5432 ldstr_info.orig_domain = domain;
5433 ldstr_info.ins = str;
5434 ldstr_info.res = NULL;
5436 mono_domain_foreach (str_lookup, &ldstr_info);
5437 if (ldstr_info.res) {
5439 * the string was already interned in some other domain:
5440 * intern it in the current one as well.
5442 mono_g_hash_table_insert (ldstr_table, str, str);
5452 * mono_string_is_interned:
5453 * @o: String to probe
5455 * Returns whether the string has been interned.
5458 mono_string_is_interned (MonoString *o)
5460 return mono_string_is_interned_lookup (o, FALSE);
5464 * mono_string_intern:
5465 * @o: String to intern
5467 * Interns the string passed.
5468 * Returns: The interned string.
5471 mono_string_intern (MonoString *str)
5473 return mono_string_is_interned_lookup (str, TRUE);
5478 * @domain: the domain where the string will be used.
5479 * @image: a metadata context
5480 * @idx: index into the user string table.
5482 * Implementation for the ldstr opcode.
5483 * Returns: a loaded string from the @image/@idx combination.
5486 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5488 if (image->dynamic) {
5489 MonoString *str = mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5492 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5493 return NULL; /*FIXME we should probably be raising an exception here*/
5494 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5499 * mono_ldstr_metadata_sig
5500 * @domain: the domain for the string
5501 * @sig: the signature of a metadata string
5503 * Returns: a MonoString for a string stored in the metadata
5506 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5508 const char *str = sig;
5509 MonoString *o, *interned;
5512 len2 = mono_metadata_decode_blob_size (str, &str);
5515 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5516 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5519 guint16 *p2 = (guint16*)mono_string_chars (o);
5520 for (i = 0; i < len2; ++i) {
5521 *p2 = GUINT16_FROM_LE (*p2);
5527 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5530 return interned; /* o will get garbage collected */
5532 o = mono_string_get_pinned (o);
5535 interned = mono_g_hash_table_lookup (domain->ldstr_table, o);
5537 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5547 * mono_string_to_utf8:
5548 * @s: a System.String
5550 * Returns the UTF8 representation for @s.
5551 * The resulting buffer needs to be freed with mono_free().
5553 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5556 mono_string_to_utf8 (MonoString *s)
5559 char *result = mono_string_to_utf8_checked (s, &error);
5561 if (!mono_error_ok (&error))
5562 mono_error_raise_exception (&error);
5567 * mono_string_to_utf8_checked:
5568 * @s: a System.String
5569 * @error: a MonoError.
5571 * Converts a MonoString to its UTF8 representation. May fail; check
5572 * @error to determine whether the conversion was successful.
5573 * The resulting buffer should be freed with mono_free().
5576 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5580 GError *gerror = NULL;
5582 mono_error_init (error);
5588 return g_strdup ("");
5590 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5592 mono_error_set_argument (error, "string", "%s", gerror->message);
5593 g_error_free (gerror);
5596 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5597 if (s->length > written) {
5598 /* allocate the total length and copy the part of the string that has been converted */
5599 char *as2 = g_malloc0 (s->length);
5600 memcpy (as2, as, written);
5609 * mono_string_to_utf8_ignore:
5612 * Converts a MonoString to its UTF8 representation. Will ignore
5613 * invalid surrogate pairs.
5614 * The resulting buffer should be freed with mono_free().
5618 mono_string_to_utf8_ignore (MonoString *s)
5627 return g_strdup ("");
5629 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5631 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5632 if (s->length > written) {
5633 /* allocate the total length and copy the part of the string that has been converted */
5634 char *as2 = g_malloc0 (s->length);
5635 memcpy (as2, as, written);
5644 * mono_string_to_utf8_image_ignore:
5645 * @s: a System.String
5647 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5650 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5652 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5656 * mono_string_to_utf8_mp_ignore:
5657 * @s: a System.String
5659 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5662 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5664 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5669 * mono_string_to_utf16:
5672 * Return an null-terminated array of the utf-16 chars
5673 * contained in @s. The result must be freed with g_free().
5674 * This is a temporary helper until our string implementation
5675 * is reworked to always include the null terminating char.
5678 mono_string_to_utf16 (MonoString *s)
5685 as = g_malloc ((s->length * 2) + 2);
5686 as [(s->length * 2)] = '\0';
5687 as [(s->length * 2) + 1] = '\0';
5690 return (gunichar2 *)(as);
5693 memcpy (as, mono_string_chars(s), s->length * 2);
5694 return (gunichar2 *)(as);
5698 * mono_string_to_utf32:
5701 * Return an null-terminated array of the UTF-32 (UCS-4) chars
5702 * contained in @s. The result must be freed with g_free().
5705 mono_string_to_utf32 (MonoString *s)
5707 mono_unichar4 *utf32_output = NULL;
5708 GError *error = NULL;
5709 glong items_written;
5714 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
5717 g_error_free (error);
5719 return utf32_output;
5723 * mono_string_from_utf16:
5724 * @data: the UTF16 string (LPWSTR) to convert
5726 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
5728 * Returns: a MonoString.
5731 mono_string_from_utf16 (gunichar2 *data)
5733 MonoDomain *domain = mono_domain_get ();
5739 while (data [len]) len++;
5741 return mono_string_new_utf16 (domain, data, len);
5745 * mono_string_from_utf32:
5746 * @data: the UTF32 string (LPWSTR) to convert
5748 * Converts a UTF32 (UCS-4)to a MonoString.
5750 * Returns: a MonoString.
5753 mono_string_from_utf32 (mono_unichar4 *data)
5755 MonoString* result = NULL;
5756 mono_unichar2 *utf16_output = NULL;
5757 GError *error = NULL;
5758 glong items_written;
5764 while (data [len]) len++;
5766 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
5769 g_error_free (error);
5771 result = mono_string_from_utf16 (utf16_output);
5772 g_free (utf16_output);
5777 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
5784 r = mono_string_to_utf8_ignore (s);
5786 r = mono_string_to_utf8_checked (s, error);
5787 if (!mono_error_ok (error))
5794 len = strlen (r) + 1;
5796 mp_s = mono_mempool_alloc (mp, len);
5798 mp_s = mono_image_alloc (image, len);
5800 memcpy (mp_s, r, len);
5808 * mono_string_to_utf8_image:
5809 * @s: a System.String
5811 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
5814 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
5816 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
5820 * mono_string_to_utf8_mp:
5821 * @s: a System.String
5823 * Same as mono_string_to_utf8, but allocate the string from a mempool.
5826 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
5828 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
5832 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
5835 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
5837 eh_callbacks = *cbs;
5840 MonoRuntimeExceptionHandlingCallbacks *
5841 mono_get_eh_callbacks (void)
5843 return &eh_callbacks;
5847 * mono_raise_exception:
5848 * @ex: exception object
5850 * Signal the runtime that the exception @ex has been raised in unmanaged code.
5853 mono_raise_exception (MonoException *ex)
5856 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
5857 * that will cause gcc to omit the function epilog, causing problems when
5858 * the JIT tries to walk the stack, since the return address on the stack
5859 * will point into the next function in the executable, not this one.
5861 eh_callbacks.mono_raise_exception (ex);
5865 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
5867 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
5871 * mono_wait_handle_new:
5872 * @domain: Domain where the object will be created
5873 * @handle: Handle for the wait handle
5875 * Returns: A new MonoWaitHandle created in the given domain for the given handle
5878 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
5880 MonoWaitHandle *res;
5881 gpointer params [1];
5882 static MonoMethod *handle_set;
5884 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
5886 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
5888 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
5890 params [0] = &handle;
5891 mono_runtime_invoke (handle_set, res, params, NULL);
5897 mono_wait_handle_get_handle (MonoWaitHandle *handle)
5899 static MonoClassField *f_os_handle;
5900 static MonoClassField *f_safe_handle;
5902 if (!f_os_handle && !f_safe_handle) {
5903 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
5904 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
5909 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
5913 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
5920 mono_runtime_capture_context (MonoDomain *domain)
5922 RuntimeInvokeFunction runtime_invoke;
5924 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
5925 MonoMethod *method = mono_get_context_capture_method ();
5926 MonoMethod *wrapper;
5929 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
5930 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
5931 domain->capture_context_method = mono_compile_method (method);
5934 runtime_invoke = domain->capture_context_runtime_invoke;
5936 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
5939 * mono_async_result_new:
5940 * @domain:domain where the object will be created.
5941 * @handle: wait handle.
5942 * @state: state to pass to AsyncResult
5943 * @data: C closure data.
5945 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
5946 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
5950 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
5952 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
5953 MonoObject *context = mono_runtime_capture_context (domain);
5954 /* we must capture the execution context from the original thread */
5956 MONO_OBJECT_SETREF (res, execution_context, context);
5957 /* note: result may be null if the flow is suppressed */
5961 MONO_OBJECT_SETREF (res, object_data, object_data);
5962 MONO_OBJECT_SETREF (res, async_state, state);
5964 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
5966 res->sync_completed = FALSE;
5967 res->completed = FALSE;
5973 mono_async_result_invoke (MonoAsyncResult *ares, MonoObject **exc)
5977 MonoInternalThread *thread;
5980 g_assert (ares->async_delegate);
5982 thread = mono_thread_internal_current ();
5984 if (!ares->execution_context) {
5985 ares->original_context = NULL;
5987 /* use captured ExecutionContext (if available) */
5988 MONO_OBJECT_SETREF (ares, original_context, mono_thread_get_execution_context ());
5989 mono_thread_set_execution_context (ares->execution_context);
5992 ac = (MonoAsyncCall*) ares->object_data;
5994 thread->async_invoke_method = ((MonoDelegate*) ares->async_delegate)->method;
5995 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, exc);
5996 thread->async_invoke_method = NULL;
5998 MonoArray *out_args = NULL;
5999 gpointer wait_event = NULL;
6001 ac->msg->exc = NULL;
6002 res = mono_message_invoke (ares->async_delegate, ac->msg, exc, &out_args);
6003 MONO_OBJECT_SETREF (ac->msg, exc, *exc);
6004 MONO_OBJECT_SETREF (ac, res, res);
6005 MONO_OBJECT_SETREF (ac, out_args, out_args);
6007 mono_monitor_enter ((MonoObject*) ares);
6008 ares->completed = 1;
6010 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6011 mono_monitor_exit ((MonoObject*) ares);
6013 if (wait_event != NULL)
6014 SetEvent (wait_event);
6016 if (!ac->cb_method) {
6019 thread->async_invoke_method = ac->cb_method;
6020 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, exc);
6021 thread->async_invoke_method = NULL;
6025 /* restore original thread execution context if flow isn't suppressed, i.e. non null */
6026 if (ares->original_context) {
6027 mono_thread_set_execution_context (ares->original_context);
6028 ares->original_context = NULL;
6035 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *this)
6037 MonoObject *exc = NULL;
6038 MonoObject *res = mono_async_result_invoke (this, &exc);
6040 mono_raise_exception ((MonoException*) exc);
6045 mono_message_init (MonoDomain *domain,
6046 MonoMethodMessage *this,
6047 MonoReflectionMethod *method,
6048 MonoArray *out_args)
6050 static MonoClass *object_array_klass;
6051 static MonoClass *byte_array_klass;
6052 static MonoClass *string_array_klass;
6053 MonoMethodSignature *sig = mono_method_signature (method->method);
6059 if (!object_array_klass) {
6062 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6064 byte_array_klass = klass;
6066 klass = mono_array_class_get (mono_defaults.string_class, 1);
6068 string_array_klass = klass;
6070 klass = mono_array_class_get (mono_defaults.object_class, 1);
6073 mono_atomic_store_release (&object_array_klass, klass);
6076 MONO_OBJECT_SETREF (this, method, method);
6078 MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
6079 MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
6080 this->async_result = NULL;
6081 this->call_type = CallType_Sync;
6083 names = g_new (char *, sig->param_count);
6084 mono_method_get_param_names (method->method, (const char **) names);
6085 MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
6087 for (i = 0; i < sig->param_count; i++) {
6088 name = mono_string_new (domain, names [i]);
6089 mono_array_setref (this->names, i, name);
6093 for (i = 0, j = 0; i < sig->param_count; i++) {
6094 if (sig->params [i]->byref) {
6096 MonoObject* arg = mono_array_get (out_args, gpointer, j);
6097 mono_array_setref (this->args, i, arg);
6101 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6105 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6108 mono_array_set (this->arg_types, guint8, i, arg_type);
6112 #ifndef DISABLE_REMOTING
6114 * mono_remoting_invoke:
6115 * @real_proxy: pointer to a RealProxy object
6116 * @msg: The MonoMethodMessage to execute
6117 * @exc: used to store exceptions
6118 * @out_args: used to store output arguments
6120 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6121 * IMessage interface and it is not trivial to extract results from there. So
6122 * we call an helper method PrivateInvoke instead of calling
6123 * RealProxy::Invoke() directly.
6125 * Returns: the result object.
6128 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6129 MonoObject **exc, MonoArray **out_args)
6131 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6134 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6137 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6139 real_proxy->vtable->domain->private_invoke_method = im;
6142 pa [0] = real_proxy;
6147 return mono_runtime_invoke (im, NULL, pa, exc);
6152 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6153 MonoObject **exc, MonoArray **out_args)
6155 static MonoClass *object_array_klass;
6158 MonoMethodSignature *sig;
6160 int i, j, outarg_count = 0;
6162 #ifndef DISABLE_REMOTING
6163 if (target && mono_object_is_transparent_proxy (target)) {
6164 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6165 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6166 target = tp->rp->unwrapped_server;
6168 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6173 domain = mono_domain_get ();
6174 method = msg->method->method;
6175 sig = mono_method_signature (method);
6177 for (i = 0; i < sig->param_count; i++) {
6178 if (sig->params [i]->byref)
6182 if (!object_array_klass) {
6185 klass = mono_array_class_get (mono_defaults.object_class, 1);
6188 mono_memory_barrier ();
6189 object_array_klass = klass;
6192 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
6193 *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
6196 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6198 for (i = 0, j = 0; i < sig->param_count; i++) {
6199 if (sig->params [i]->byref) {
6201 arg = mono_array_get (msg->args, gpointer, i);
6202 mono_array_setref (*out_args, j, arg);
6211 * mono_object_to_string:
6213 * @exc: Any exception thrown by ToString (). May be NULL.
6215 * Returns: the result of calling ToString () on an object.
6218 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6220 static MonoMethod *to_string = NULL;
6227 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6229 method = mono_object_get_virtual_method (obj, to_string);
6231 // Unbox value type if needed
6232 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6233 target = mono_object_unbox (obj);
6236 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6240 * mono_print_unhandled_exception:
6241 * @exc: The exception
6243 * Prints the unhandled exception.
6246 mono_print_unhandled_exception (MonoObject *exc)
6249 char *message = (char*)"";
6250 gboolean free_message = FALSE;
6253 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6254 message = g_strdup ("OutOfMemoryException");
6255 free_message = TRUE;
6256 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6257 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6258 free_message = TRUE;
6261 if (((MonoException*)exc)->native_trace_ips) {
6262 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6263 free_message = TRUE;
6265 MonoObject *other_exc = NULL;
6266 str = mono_object_to_string (exc, &other_exc);
6268 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6269 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6271 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6272 original_backtrace, nested_backtrace);
6274 g_free (original_backtrace);
6275 g_free (nested_backtrace);
6276 free_message = TRUE;
6278 message = mono_string_to_utf8_checked (str, &error);
6279 if (!mono_error_ok (&error)) {
6280 mono_error_cleanup (&error);
6281 message = (char *) "";
6283 free_message = TRUE;
6290 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6291 * exc->vtable->klass->name, message);
6293 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6300 * mono_delegate_ctor:
6301 * @this: pointer to an uninitialized delegate object
6302 * @target: target object
6303 * @addr: pointer to native code
6306 * Initialize a delegate and sets a specific method, not the one
6307 * associated with addr. This is useful when sharing generic code.
6308 * In that case addr will most probably not be associated with the
6309 * correct instantiation of the method.
6312 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
6314 MonoDelegate *delegate = (MonoDelegate *)this;
6319 g_assert (mono_class_has_parent (mono_object_class (this), mono_defaults.multicastdelegate_class));
6322 delegate->method = method;
6324 mono_stats.delegate_creations++;
6326 #ifndef DISABLE_REMOTING
6327 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6329 method = mono_marshal_get_remoting_invoke (method);
6330 delegate->method_ptr = mono_compile_method (method);
6331 MONO_OBJECT_SETREF (delegate, target, target);
6335 delegate->method_ptr = addr;
6336 MONO_OBJECT_SETREF (delegate, target, target);
6339 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6343 * mono_delegate_ctor:
6344 * @this: pointer to an uninitialized delegate object
6345 * @target: target object
6346 * @addr: pointer to native code
6348 * This is used to initialize a delegate.
6351 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
6353 MonoDomain *domain = mono_domain_get ();
6355 MonoMethod *method = NULL;
6359 ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr));
6361 if (!ji && domain != mono_get_root_domain ())
6362 ji = mono_jit_info_table_find (mono_get_root_domain (), mono_get_addr_from_ftnptr (addr));
6364 method = mono_jit_info_get_method (ji);
6365 g_assert (!method->klass->generic_container);
6368 mono_delegate_ctor_with_method (this, target, addr, method);
6372 * mono_method_call_message_new:
6373 * @method: method to encapsulate
6374 * @params: parameters to the method
6375 * @invoke: optional, delegate invoke.
6376 * @cb: async callback delegate.
6377 * @state: state passed to the async callback.
6379 * Translates arguments pointers into a MonoMethodMessage.
6382 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6383 MonoDelegate **cb, MonoObject **state)
6385 MonoDomain *domain = mono_domain_get ();
6386 MonoMethodSignature *sig = mono_method_signature (method);
6387 MonoMethodMessage *msg;
6390 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6393 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6394 count = sig->param_count - 2;
6396 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6397 count = sig->param_count;
6400 for (i = 0; i < count; i++) {
6405 if (sig->params [i]->byref)
6406 vpos = *((gpointer *)params [i]);
6410 class = mono_class_from_mono_type (sig->params [i]);
6412 if (class->valuetype)
6413 arg = mono_value_box (domain, class, vpos);
6415 arg = *((MonoObject **)vpos);
6417 mono_array_setref (msg->args, i, arg);
6420 if (cb != NULL && state != NULL) {
6421 *cb = *((MonoDelegate **)params [i]);
6423 *state = *((MonoObject **)params [i]);
6430 * mono_method_return_message_restore:
6432 * Restore results from message based processing back to arguments pointers
6435 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6437 MonoMethodSignature *sig = mono_method_signature (method);
6438 int i, j, type, size, out_len;
6440 if (out_args == NULL)
6442 out_len = mono_array_length (out_args);
6446 for (i = 0, j = 0; i < sig->param_count; i++) {
6447 MonoType *pt = sig->params [i];
6452 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6454 arg = mono_array_get (out_args, gpointer, j);
6457 g_assert (type != MONO_TYPE_VOID);
6459 if (MONO_TYPE_IS_REFERENCE (pt)) {
6460 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6463 MonoClass *class = ((MonoObject*)arg)->vtable->klass;
6464 size = mono_class_value_size (class, NULL);
6465 if (class->has_references)
6466 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, class);
6468 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6470 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6471 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6480 #ifndef DISABLE_REMOTING
6483 * mono_load_remote_field:
6484 * @this: pointer to an object
6485 * @klass: klass of the object containing @field
6486 * @field: the field to load
6487 * @res: a storage to store the result
6489 * This method is called by the runtime on attempts to load fields of
6490 * transparent proxy objects. @this points to such TP, @klass is the class of
6491 * the object containing @field. @res is a storage location which can be
6492 * used to store the result.
6494 * Returns: an address pointing to the value of field.
6497 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
6499 static MonoMethod *getter = NULL;
6500 MonoDomain *domain = mono_domain_get ();
6501 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6502 MonoClass *field_class;
6503 MonoMethodMessage *msg;
6504 MonoArray *out_args;
6508 g_assert (mono_object_is_transparent_proxy (this));
6509 g_assert (res != NULL);
6511 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6512 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6517 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6521 field_class = mono_class_from_mono_type (field->type);
6523 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6524 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6525 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6527 full_name = mono_type_get_full_name (klass);
6528 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6529 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6532 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6534 if (exc) mono_raise_exception ((MonoException *)exc);
6536 if (mono_array_length (out_args) == 0)
6539 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6541 if (field_class->valuetype) {
6542 return ((char *)*res) + sizeof (MonoObject);
6548 * mono_load_remote_field_new:
6553 * Missing documentation.
6556 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
6558 static MonoMethod *getter = NULL;
6559 MonoDomain *domain = mono_domain_get ();
6560 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6561 MonoClass *field_class;
6562 MonoMethodMessage *msg;
6563 MonoArray *out_args;
6564 MonoObject *exc, *res;
6567 g_assert (mono_object_is_transparent_proxy (this));
6569 field_class = mono_class_from_mono_type (field->type);
6571 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6573 if (field_class->valuetype) {
6574 res = mono_object_new (domain, field_class);
6575 val = ((gchar *) res) + sizeof (MonoObject);
6579 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6584 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6588 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6589 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6591 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6593 full_name = mono_type_get_full_name (klass);
6594 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6595 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6598 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6600 if (exc) mono_raise_exception ((MonoException *)exc);
6602 if (mono_array_length (out_args) == 0)
6605 res = mono_array_get (out_args, MonoObject *, 0);
6611 * mono_store_remote_field:
6612 * @this: pointer to an object
6613 * @klass: klass of the object containing @field
6614 * @field: the field to load
6615 * @val: the value/object to store
6617 * This method is called by the runtime on attempts to store fields of
6618 * transparent proxy objects. @this points to such TP, @klass is the class of
6619 * the object containing @field. @val is the new value to store in @field.
6622 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
6624 static MonoMethod *setter = NULL;
6625 MonoDomain *domain = mono_domain_get ();
6626 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6627 MonoClass *field_class;
6628 MonoMethodMessage *msg;
6629 MonoArray *out_args;
6634 g_assert (mono_object_is_transparent_proxy (this));
6636 field_class = mono_class_from_mono_type (field->type);
6638 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6639 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
6640 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
6645 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6649 if (field_class->valuetype)
6650 arg = mono_value_box (domain, field_class, val);
6652 arg = *((MonoObject **)val);
6655 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6656 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6658 full_name = mono_type_get_full_name (klass);
6659 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6660 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6661 mono_array_setref (msg->args, 2, arg);
6664 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6666 if (exc) mono_raise_exception ((MonoException *)exc);
6670 * mono_store_remote_field_new:
6676 * Missing documentation
6679 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
6681 static MonoMethod *setter = NULL;
6682 MonoDomain *domain = mono_domain_get ();
6683 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
6684 MonoClass *field_class;
6685 MonoMethodMessage *msg;
6686 MonoArray *out_args;
6690 g_assert (mono_object_is_transparent_proxy (this));
6692 field_class = mono_class_from_mono_type (field->type);
6694 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6695 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
6696 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
6701 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
6705 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6706 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
6708 full_name = mono_type_get_full_name (klass);
6709 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6710 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6711 mono_array_setref (msg->args, 2, arg);
6714 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6716 if (exc) mono_raise_exception ((MonoException *)exc);
6721 * mono_create_ftnptr:
6723 * Given a function address, create a function descriptor for it.
6724 * This is only needed on some platforms.
6727 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
6729 return callbacks.create_ftnptr (domain, addr);
6733 * mono_get_addr_from_ftnptr:
6735 * Given a pointer to a function descriptor, return the function address.
6736 * This is only needed on some platforms.
6739 mono_get_addr_from_ftnptr (gpointer descr)
6741 return callbacks.get_addr_from_ftnptr (descr);
6745 * mono_string_chars:
6748 * Returns a pointer to the UCS16 characters stored in the MonoString
6751 mono_string_chars (MonoString *s)
6757 * mono_string_length:
6760 * Returns the lenght in characters of the string
6763 mono_string_length (MonoString *s)
6769 * mono_array_length:
6770 * @array: a MonoArray*
6772 * Returns the total number of elements in the array. This works for
6773 * both vectors and multidimensional arrays.
6776 mono_array_length (MonoArray *array)
6778 return array->max_length;
6782 * mono_array_addr_with_size:
6783 * @array: a MonoArray*
6784 * @size: size of the array elements
6785 * @idx: index into the array
6787 * Returns the address of the @idx element in the array.
6790 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
6792 return ((char*)(array)->vector) + size * idx;