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-internals.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/marshal.h>
31 #include "mono/metadata/debug-helpers.h"
32 #include "mono/metadata/marshal.h"
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/environment.h>
36 #include "mono/metadata/profiler-private.h"
37 #include "mono/metadata/security-manager.h"
38 #include "mono/metadata/mono-debug-debugger.h"
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-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 <mono/utils/checked-build.h>
47 #include <mono/utils/mono-threads.h>
48 #include "cominterop.h"
51 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
54 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
57 free_main_args (void);
60 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
63 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
64 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
65 static mono_mutex_t ldstr_section;
68 mono_runtime_object_init (MonoObject *this_obj)
70 MONO_REQ_GC_UNSAFE_MODE;
72 MonoMethod *method = NULL;
73 MonoClass *klass = this_obj->vtable->klass;
75 method = mono_class_get_method_from_name (klass, ".ctor", 0);
77 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
79 if (method->klass->valuetype)
80 this_obj = (MonoObject *)mono_object_unbox (this_obj);
81 mono_runtime_invoke (method, this_obj, NULL, NULL);
84 /* The pseudo algorithm for type initialization from the spec
85 Note it doesn't say anything about domains - only threads.
87 2. If the type is initialized you are done.
88 2.1. If the type is not yet initialized, try to take an
90 2.2. If successful, record this thread as responsible for
91 initializing the type and proceed to step 2.3.
92 2.2.1. If not, see whether this thread or any thread
93 waiting for this thread to complete already holds the lock.
94 2.2.2. If so, return since blocking would create a deadlock. This thread
95 will now see an incompletely initialized state for the type,
96 but no deadlock will arise.
97 2.2.3 If not, block until the type is initialized then return.
98 2.3 Initialize the parent type and then all interfaces implemented
100 2.4 Execute the type initialization code for this type.
101 2.5 Mark the type as initialized, release the initialization lock,
102 awaken any threads waiting for this type to be initialized,
109 MonoNativeThreadId initializing_tid;
110 guint32 waiting_count;
112 MonoCoopMutex initialization_section;
113 } TypeInitializationLock;
115 /* for locking access to type_initialization_hash and blocked_thread_hash */
116 static MonoCoopMutex type_initialization_section;
119 mono_type_initialization_lock (void)
121 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
122 mono_coop_mutex_lock (&type_initialization_section);
126 mono_type_initialization_unlock (void)
128 mono_coop_mutex_unlock (&type_initialization_section);
132 mono_type_init_lock (TypeInitializationLock *lock)
134 MONO_REQ_GC_NEUTRAL_MODE;
136 mono_coop_mutex_lock (&lock->initialization_section);
140 mono_type_init_unlock (TypeInitializationLock *lock)
142 mono_coop_mutex_unlock (&lock->initialization_section);
145 /* from vtable to lock */
146 static GHashTable *type_initialization_hash;
148 /* from thread id to thread id being waited on */
149 static GHashTable *blocked_thread_hash;
152 static MonoThread *main_thread;
154 /* Functions supplied by the runtime */
155 static MonoRuntimeCallbacks callbacks;
158 * mono_thread_set_main:
159 * @thread: thread to set as the main thread
161 * This function can be used to instruct the runtime to treat @thread
162 * as the main thread, ie, the thread that would normally execute the Main()
163 * method. This basically means that at the end of @thread, the runtime will
164 * wait for the existing foreground threads to quit and other such details.
167 mono_thread_set_main (MonoThread *thread)
169 MONO_REQ_GC_UNSAFE_MODE;
171 static gboolean registered = FALSE;
174 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
178 main_thread = thread;
182 mono_thread_get_main (void)
184 MONO_REQ_GC_UNSAFE_MODE;
190 mono_type_initialization_init (void)
192 mono_coop_mutex_init_recursive (&type_initialization_section);
193 type_initialization_hash = g_hash_table_new (NULL, NULL);
194 blocked_thread_hash = g_hash_table_new (NULL, NULL);
195 mono_os_mutex_init_recursive (&ldstr_section);
199 mono_type_initialization_cleanup (void)
202 /* This is causing race conditions with
203 * mono_release_type_locks
205 mono_coop_mutex_destroy (&type_initialization_section);
206 g_hash_table_destroy (type_initialization_hash);
207 type_initialization_hash = NULL;
209 mono_os_mutex_destroy (&ldstr_section);
210 g_hash_table_destroy (blocked_thread_hash);
211 blocked_thread_hash = NULL;
217 * get_type_init_exception_for_vtable:
219 * Return the stored type initialization exception for VTABLE.
221 static MonoException*
222 get_type_init_exception_for_vtable (MonoVTable *vtable)
224 MONO_REQ_GC_UNSAFE_MODE;
226 MonoDomain *domain = vtable->domain;
227 MonoClass *klass = vtable->klass;
231 if (!vtable->init_failed)
232 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
235 * If the initializing thread was rudely aborted, the exception is not stored
239 mono_domain_lock (domain);
240 if (domain->type_init_exception_hash)
241 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
242 mono_domain_unlock (domain);
245 if (klass->name_space && *klass->name_space)
246 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
248 full_name = g_strdup (klass->name);
249 ex = mono_get_exception_type_initialization (full_name, NULL);
256 * mono_runtime_class_init:
257 * @vtable: vtable that needs to be initialized
259 * This routine calls the class constructor for @vtable.
262 mono_runtime_class_init (MonoVTable *vtable)
264 MONO_REQ_GC_UNSAFE_MODE;
266 mono_runtime_class_init_full (vtable, TRUE);
270 * mono_runtime_class_init_full:
271 * @vtable that neeeds to be initialized
272 * @raise_exception is TRUE, exceptions are raised intead of returned
276 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
278 MONO_REQ_GC_UNSAFE_MODE;
281 MonoException *exc_to_throw;
282 MonoMethod *method = NULL;
285 MonoDomain *domain = vtable->domain;
286 TypeInitializationLock *lock;
287 MonoNativeThreadId tid;
288 int do_initialization = 0;
289 MonoDomain *last_domain = NULL;
291 if (vtable->initialized)
295 klass = vtable->klass;
297 if (!klass->image->checked_module_cctor) {
298 mono_image_check_for_module_cctor (klass->image);
299 if (klass->image->has_module_cctor) {
301 MonoClass *module_klass;
302 MonoVTable *module_vtable;
304 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
306 exc = mono_error_convert_to_exception (&error);
308 mono_raise_exception (exc);
312 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
315 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
320 method = mono_class_get_cctor (klass);
322 vtable->initialized = 1;
326 tid = mono_native_thread_id_get ();
328 mono_type_initialization_lock ();
329 /* double check... */
330 if (vtable->initialized) {
331 mono_type_initialization_unlock ();
334 if (vtable->init_failed) {
335 mono_type_initialization_unlock ();
337 /* The type initialization already failed once, rethrow the same exception */
339 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
340 return get_type_init_exception_for_vtable (vtable);
342 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
344 /* This thread will get to do the initialization */
345 if (mono_domain_get () != domain) {
346 /* Transfer into the target domain */
347 last_domain = mono_domain_get ();
348 if (!mono_domain_set (domain, FALSE)) {
349 vtable->initialized = 1;
350 mono_type_initialization_unlock ();
352 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
353 return mono_get_exception_appdomain_unloaded ();
356 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
357 mono_coop_mutex_init_recursive (&lock->initialization_section);
358 lock->initializing_tid = tid;
359 lock->waiting_count = 1;
361 /* grab the vtable lock while this thread still owns type_initialization_section */
362 /* This is why type_initialization_lock needs to enter blocking mode */
363 mono_type_init_lock (lock);
364 g_hash_table_insert (type_initialization_hash, vtable, lock);
365 do_initialization = 1;
368 TypeInitializationLock *pending_lock;
370 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
371 mono_type_initialization_unlock ();
374 /* see if the thread doing the initialization is already blocked on this thread */
375 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
376 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
377 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
378 if (!pending_lock->done) {
379 mono_type_initialization_unlock ();
382 /* the thread doing the initialization is blocked on this thread,
383 but on a lock that has already been freed. It just hasn't got
388 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
390 ++lock->waiting_count;
391 /* record the fact that we are waiting on the initializing thread */
392 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
394 mono_type_initialization_unlock ();
396 if (do_initialization) {
397 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
399 /* If the initialization failed, mark the class as unusable. */
400 /* Avoid infinite loops */
402 (klass->image == mono_defaults.corlib &&
403 !strcmp (klass->name_space, "System") &&
404 !strcmp (klass->name, "TypeInitializationException")))) {
405 vtable->init_failed = 1;
407 if (klass->name_space && *klass->name_space)
408 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
410 full_name = g_strdup (klass->name);
411 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
415 * Store the exception object so it could be thrown on subsequent
418 mono_domain_lock (domain);
419 if (!domain->type_init_exception_hash)
420 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
421 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
422 mono_domain_unlock (domain);
426 mono_domain_set (last_domain, TRUE);
428 mono_type_init_unlock (lock);
430 /* this just blocks until the initializing thread is done */
431 mono_type_init_lock (lock);
432 mono_type_init_unlock (lock);
435 mono_type_initialization_lock ();
436 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
437 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
438 --lock->waiting_count;
439 if (lock->waiting_count == 0) {
440 mono_coop_mutex_destroy (&lock->initialization_section);
441 g_hash_table_remove (type_initialization_hash, vtable);
444 mono_memory_barrier ();
445 if (!vtable->init_failed)
446 vtable->initialized = 1;
447 mono_type_initialization_unlock ();
449 if (vtable->init_failed) {
450 /* Either we were the initializing thread or we waited for the initialization */
452 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
453 return get_type_init_exception_for_vtable (vtable);
459 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
461 MONO_REQ_GC_NEUTRAL_MODE;
463 MonoVTable *vtable = (MonoVTable*)key;
465 TypeInitializationLock *lock = (TypeInitializationLock*) value;
466 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
469 * Have to set this since it cannot be set by the normal code in
470 * mono_runtime_class_init (). In this case, the exception object is not stored,
471 * and get_type_init_exception_for_class () needs to be aware of this.
473 vtable->init_failed = 1;
474 mono_type_init_unlock (lock);
475 --lock->waiting_count;
476 if (lock->waiting_count == 0) {
477 mono_coop_mutex_destroy (&lock->initialization_section);
486 mono_release_type_locks (MonoInternalThread *thread)
488 MONO_REQ_GC_UNSAFE_MODE;
490 mono_type_initialization_lock ();
491 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
492 mono_type_initialization_unlock ();
496 default_trampoline (MonoMethod *method)
502 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
504 g_assert_not_reached ();
509 #ifndef DISABLE_REMOTING
512 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
514 g_error ("remoting not installed");
518 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
522 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
524 g_assert_not_reached ();
528 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
529 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
530 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
531 static MonoImtThunkBuilder imt_thunk_builder;
532 static gboolean always_build_imt_thunks;
534 #if (MONO_IMT_SIZE > 32)
535 #error "MONO_IMT_SIZE cannot be larger than 32"
539 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
541 memcpy (&callbacks, cbs, sizeof (*cbs));
544 MonoRuntimeCallbacks*
545 mono_get_runtime_callbacks (void)
551 mono_install_trampoline (MonoTrampoline func)
553 arch_create_jit_trampoline = func? func: default_trampoline;
557 mono_install_jump_trampoline (MonoJumpTrampoline func)
559 arch_create_jump_trampoline = func? func: default_jump_trampoline;
562 #ifndef DISABLE_REMOTING
564 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
566 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
571 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
573 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
577 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
578 imt_thunk_builder = func;
582 mono_set_always_build_imt_thunks (gboolean value)
584 always_build_imt_thunks = value;
588 * mono_compile_method:
589 * @method: The method to compile.
591 * This JIT-compiles the method, and returns the pointer to the native code
595 mono_compile_method (MonoMethod *method)
600 MONO_REQ_GC_NEUTRAL_MODE
602 if (!callbacks.compile_method) {
603 g_error ("compile method called on uninitialized runtime");
606 res = callbacks.compile_method (method, &error);
607 if (!mono_error_ok (&error))
608 mono_error_raise_exception (&error);
613 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
615 MONO_REQ_GC_NEUTRAL_MODE
617 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
621 mono_runtime_create_delegate_trampoline (MonoClass *klass)
623 MONO_REQ_GC_NEUTRAL_MODE
625 return arch_create_delegate_trampoline (mono_domain_get (), klass);
628 static MonoFreeMethodFunc default_mono_free_method = NULL;
631 * mono_install_free_method:
632 * @func: pointer to the MonoFreeMethodFunc used to release a method
634 * This is an internal VM routine, it is used for the engines to
635 * register a handler to release the resources associated with a method.
637 * Methods are freed when no more references to the delegate that holds
641 mono_install_free_method (MonoFreeMethodFunc func)
643 default_mono_free_method = func;
647 * mono_runtime_free_method:
648 * @domain; domain where the method is hosted
649 * @method: method to release
651 * This routine is invoked to free the resources associated with
652 * a method that has been JIT compiled. This is used to discard
653 * methods that were used only temporarily (for example, used in marshalling)
657 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
659 MONO_REQ_GC_NEUTRAL_MODE
661 if (default_mono_free_method != NULL)
662 default_mono_free_method (domain, method);
664 mono_method_clear_object (domain, method);
666 mono_free_method (method);
670 * The vtables in the root appdomain are assumed to be reachable by other
671 * roots, and we don't use typed allocation in the other domains.
674 /* The sync block is no longer a GC pointer */
675 #define GC_HEADER_BITMAP (0)
677 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
680 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
682 MONO_REQ_GC_NEUTRAL_MODE;
684 MonoClassField *field;
690 max_size = mono_class_data_size (klass) / sizeof (gpointer);
692 max_size = klass->instance_size / sizeof (gpointer);
693 if (max_size > size) {
694 g_assert (offset <= 0);
695 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
700 /*An Ephemeron cannot be marked by sgen*/
701 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
703 memset (bitmap, 0, size / 8);
708 for (p = klass; p != NULL; p = p->parent) {
709 gpointer iter = NULL;
710 while ((field = mono_class_get_fields (p, &iter))) {
714 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
716 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
719 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
722 /* FIXME: should not happen, flag as type load error */
723 if (field->type->byref)
726 if (static_fields && field->offset == -1)
730 pos = field->offset / sizeof (gpointer);
733 type = mono_type_get_underlying_type (field->type);
734 switch (type->type) {
737 case MONO_TYPE_FNPTR:
739 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
744 if (klass->image != mono_defaults.corlib)
747 case MONO_TYPE_STRING:
748 case MONO_TYPE_SZARRAY:
749 case MONO_TYPE_CLASS:
750 case MONO_TYPE_OBJECT:
751 case MONO_TYPE_ARRAY:
752 g_assert ((field->offset % sizeof(gpointer)) == 0);
754 g_assert (pos < size || pos <= max_size);
755 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
756 *max_set = MAX (*max_set, pos);
758 case MONO_TYPE_GENERICINST:
759 if (!mono_type_generic_inst_is_valuetype (type)) {
760 g_assert ((field->offset % sizeof(gpointer)) == 0);
762 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
763 *max_set = MAX (*max_set, pos);
768 case MONO_TYPE_VALUETYPE: {
769 MonoClass *fclass = mono_class_from_mono_type (field->type);
770 if (fclass->has_references) {
771 /* remove the object header */
772 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
786 case MONO_TYPE_BOOLEAN:
790 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
801 * mono_class_compute_bitmap:
803 * Mono internal function to compute a bitmap of reference fields in a class.
806 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
808 MONO_REQ_GC_NEUTRAL_MODE;
810 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
815 * similar to the above, but sets the bits in the bitmap for any non-ref field
816 * and ignores static fields
819 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
821 MonoClassField *field;
826 max_size = class->instance_size / sizeof (gpointer);
827 if (max_size >= size) {
828 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
831 for (p = class; p != NULL; p = p->parent) {
832 gpointer iter = NULL;
833 while ((field = mono_class_get_fields (p, &iter))) {
836 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
838 /* FIXME: should not happen, flag as type load error */
839 if (field->type->byref)
842 pos = field->offset / sizeof (gpointer);
845 type = mono_type_get_underlying_type (field->type);
846 switch (type->type) {
847 #if SIZEOF_VOID_P == 8
851 case MONO_TYPE_FNPTR:
856 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
857 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
858 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
861 #if SIZEOF_VOID_P == 4
865 case MONO_TYPE_FNPTR:
870 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
871 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
872 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
878 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
879 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
880 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
883 case MONO_TYPE_BOOLEAN:
886 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
888 case MONO_TYPE_STRING:
889 case MONO_TYPE_SZARRAY:
890 case MONO_TYPE_CLASS:
891 case MONO_TYPE_OBJECT:
892 case MONO_TYPE_ARRAY:
894 case MONO_TYPE_GENERICINST:
895 if (!mono_type_generic_inst_is_valuetype (type)) {
900 case MONO_TYPE_VALUETYPE: {
901 MonoClass *fclass = mono_class_from_mono_type (field->type);
902 /* remove the object header */
903 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
907 g_assert_not_reached ();
916 * mono_class_insecure_overlapping:
917 * check if a class with explicit layout has references and non-references
918 * fields overlapping.
920 * Returns: TRUE if it is insecure to load the type.
923 mono_class_insecure_overlapping (MonoClass *klass)
927 gsize default_bitmap [4] = {0};
929 gsize default_nrbitmap [4] = {0};
930 int i, insecure = FALSE;
933 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
934 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
936 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
937 int idx = i % (sizeof (bitmap [0]) * 8);
938 if (bitmap [idx] & nrbitmap [idx]) {
943 if (bitmap != default_bitmap)
945 if (nrbitmap != default_nrbitmap)
948 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
956 ves_icall_string_alloc (int length)
959 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
960 mono_error_raise_exception (&error);
966 mono_class_compute_gc_descriptor (MonoClass *klass)
968 MONO_REQ_GC_NEUTRAL_MODE;
972 gsize default_bitmap [4] = {0};
973 static gboolean gcj_inited = FALSE;
978 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
979 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
982 mono_loader_unlock ();
986 mono_class_init (klass);
988 if (klass->gc_descr_inited)
991 klass->gc_descr_inited = TRUE;
992 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
994 bitmap = default_bitmap;
995 if (klass == mono_defaults.string_class) {
996 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
997 } else if (klass->rank) {
998 mono_class_compute_gc_descriptor (klass->element_class);
999 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1001 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1002 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1003 class->name_space, class->name);*/
1005 /* remove the object header */
1006 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1007 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1008 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1009 class->name_space, class->name);*/
1010 if (bitmap != default_bitmap)
1014 /*static int count = 0;
1017 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1018 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1020 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1021 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1023 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1024 if (bitmap != default_bitmap)
1030 * field_is_special_static:
1031 * @fklass: The MonoClass to look up.
1032 * @field: The MonoClassField describing the field.
1034 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1035 * SPECIAL_STATIC_NONE otherwise.
1038 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1040 MONO_REQ_GC_NEUTRAL_MODE;
1042 MonoCustomAttrInfo *ainfo;
1044 ainfo = mono_custom_attrs_from_field (fklass, field);
1047 for (i = 0; i < ainfo->num_attrs; ++i) {
1048 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1049 if (klass->image == mono_defaults.corlib) {
1050 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1051 mono_custom_attrs_free (ainfo);
1052 return SPECIAL_STATIC_THREAD;
1054 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1055 mono_custom_attrs_free (ainfo);
1056 return SPECIAL_STATIC_CONTEXT;
1060 mono_custom_attrs_free (ainfo);
1061 return SPECIAL_STATIC_NONE;
1064 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1065 #define mix(a,b,c) { \
1066 a -= c; a ^= rot(c, 4); c += b; \
1067 b -= a; b ^= rot(a, 6); a += c; \
1068 c -= b; c ^= rot(b, 8); b += a; \
1069 a -= c; a ^= rot(c,16); c += b; \
1070 b -= a; b ^= rot(a,19); a += c; \
1071 c -= b; c ^= rot(b, 4); b += a; \
1073 #define final(a,b,c) { \
1074 c ^= b; c -= rot(b,14); \
1075 a ^= c; a -= rot(c,11); \
1076 b ^= a; b -= rot(a,25); \
1077 c ^= b; c -= rot(b,16); \
1078 a ^= c; a -= rot(c,4); \
1079 b ^= a; b -= rot(a,14); \
1080 c ^= b; c -= rot(b,24); \
1084 * mono_method_get_imt_slot:
1086 * The IMT slot is embedded into AOTed code, so this must return the same value
1087 * for the same method across all executions. This means:
1088 * - pointers shouldn't be used as hash values.
1089 * - mono_metadata_str_hash () should be used for hashing strings.
1092 mono_method_get_imt_slot (MonoMethod *method)
1094 MONO_REQ_GC_NEUTRAL_MODE;
1096 MonoMethodSignature *sig;
1098 guint32 *hashes_start, *hashes;
1102 /* This can be used to stress tests the collision code */
1106 * We do this to simplify generic sharing. It will hurt
1107 * performance in cases where a class implements two different
1108 * instantiations of the same generic interface.
1109 * The code in build_imt_slots () depends on this.
1111 if (method->is_inflated)
1112 method = ((MonoMethodInflated*)method)->declaring;
1114 sig = mono_method_signature (method);
1115 hashes_count = sig->param_count + 4;
1116 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1117 hashes = hashes_start;
1119 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1120 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1121 method->klass->name_space, method->klass->name, method->name);
1124 /* Initialize hashes */
1125 hashes [0] = mono_metadata_str_hash (method->klass->name);
1126 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1127 hashes [2] = mono_metadata_str_hash (method->name);
1128 hashes [3] = mono_metadata_type_hash (sig->ret);
1129 for (i = 0; i < sig->param_count; i++) {
1130 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1133 /* Setup internal state */
1134 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1136 /* Handle most of the hashes */
1137 while (hashes_count > 3) {
1146 /* Handle the last 3 hashes (all the case statements fall through) */
1147 switch (hashes_count) {
1148 case 3 : c += hashes [2];
1149 case 2 : b += hashes [1];
1150 case 1 : a += hashes [0];
1152 case 0: /* nothing left to add */
1156 free (hashes_start);
1157 /* Report the result */
1158 return c % MONO_IMT_SIZE;
1167 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1168 MONO_REQ_GC_NEUTRAL_MODE;
1170 guint32 imt_slot = mono_method_get_imt_slot (method);
1171 MonoImtBuilderEntry *entry;
1173 if (slot_num >= 0 && imt_slot != slot_num) {
1174 /* we build just a single imt slot and this is not it */
1178 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1179 entry->key = method;
1180 entry->value.vtable_slot = vtable_slot;
1181 entry->next = imt_builder [imt_slot];
1182 if (imt_builder [imt_slot] != NULL) {
1183 entry->children = imt_builder [imt_slot]->children + 1;
1184 if (entry->children == 1) {
1185 mono_stats.imt_slots_with_collisions++;
1186 *imt_collisions_bitmap |= (1 << imt_slot);
1189 entry->children = 0;
1190 mono_stats.imt_used_slots++;
1192 imt_builder [imt_slot] = entry;
1195 char *method_name = mono_method_full_name (method, TRUE);
1196 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1197 method, method_name, imt_slot, vtable_slot, entry->children);
1198 g_free (method_name);
1205 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1207 MonoMethod *method = e->key;
1208 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1212 method->klass->name_space,
1213 method->klass->name,
1216 printf (" * %s: NULL\n", message);
1222 compare_imt_builder_entries (const void *p1, const void *p2) {
1223 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1224 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1226 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1230 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1232 MONO_REQ_GC_NEUTRAL_MODE;
1234 int count = end - start;
1235 int chunk_start = out_array->len;
1238 for (i = start; i < end; ++i) {
1239 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1240 item->key = sorted_array [i]->key;
1241 item->value = sorted_array [i]->value;
1242 item->has_target_code = sorted_array [i]->has_target_code;
1243 item->is_equals = TRUE;
1245 item->check_target_idx = out_array->len + 1;
1247 item->check_target_idx = 0;
1248 g_ptr_array_add (out_array, item);
1251 int middle = start + count / 2;
1252 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1254 item->key = sorted_array [middle]->key;
1255 item->is_equals = FALSE;
1256 g_ptr_array_add (out_array, item);
1257 imt_emit_ir (sorted_array, start, middle, out_array);
1258 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1264 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1265 MONO_REQ_GC_NEUTRAL_MODE;
1267 int number_of_entries = entries->children + 1;
1268 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1269 GPtrArray *result = g_ptr_array_new ();
1270 MonoImtBuilderEntry *current_entry;
1273 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1274 sorted_array [i] = current_entry;
1276 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1278 /*for (i = 0; i < number_of_entries; i++) {
1279 print_imt_entry (" sorted array:", sorted_array [i], i);
1282 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1284 free (sorted_array);
1289 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1291 MONO_REQ_GC_NEUTRAL_MODE;
1293 if (imt_builder_entry != NULL) {
1294 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1295 /* No collision, return the vtable slot contents */
1296 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1298 /* Collision, build the thunk */
1299 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1302 result = imt_thunk_builder (vtable, domain,
1303 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1304 for (i = 0; i < imt_ir->len; ++i)
1305 g_free (g_ptr_array_index (imt_ir, i));
1306 g_ptr_array_free (imt_ir, TRUE);
1318 static MonoImtBuilderEntry*
1319 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1322 * LOCKING: requires the loader and domain locks.
1326 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1328 MONO_REQ_GC_NEUTRAL_MODE;
1332 guint32 imt_collisions_bitmap = 0;
1333 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1334 int method_count = 0;
1335 gboolean record_method_count_for_max_collisions = FALSE;
1336 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1339 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1341 for (i = 0; i < klass->interface_offsets_count; ++i) {
1342 MonoClass *iface = klass->interfaces_packed [i];
1343 int interface_offset = klass->interface_offsets_packed [i];
1344 int method_slot_in_interface, vt_slot;
1346 if (mono_class_has_variant_generic_params (iface))
1347 has_variant_iface = TRUE;
1349 mono_class_setup_methods (iface);
1350 vt_slot = interface_offset;
1351 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1354 if (slot_num >= 0 && iface->is_inflated) {
1356 * The imt slot of the method is the same as for its declaring method,
1357 * see the comment in mono_method_get_imt_slot (), so we can
1358 * avoid inflating methods which will be discarded by
1359 * add_imt_builder_entry anyway.
1361 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1362 if (mono_method_get_imt_slot (method) != slot_num) {
1367 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1368 if (method->is_generic) {
1369 has_generic_virtual = TRUE;
1374 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1375 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1380 if (extra_interfaces) {
1381 int interface_offset = klass->vtable_size;
1383 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1384 MonoClass* iface = (MonoClass *)list_item->data;
1385 int method_slot_in_interface;
1386 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1387 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1389 if (method->is_generic)
1390 has_generic_virtual = TRUE;
1391 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1393 interface_offset += iface->method.count;
1396 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1397 /* overwrite the imt slot only if we're building all the entries or if
1398 * we're building this specific one
1400 if (slot_num < 0 || i == slot_num) {
1401 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1404 if (imt_builder [i]) {
1405 MonoImtBuilderEntry *entry;
1407 /* Link entries with imt_builder [i] */
1408 for (entry = entries; entry->next; entry = entry->next) {
1410 MonoMethod *method = (MonoMethod*)entry->key;
1411 char *method_name = mono_method_full_name (method, TRUE);
1412 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1413 g_free (method_name);
1416 entry->next = imt_builder [i];
1417 entries->children += imt_builder [i]->children + 1;
1419 imt_builder [i] = entries;
1422 if (has_generic_virtual || has_variant_iface) {
1424 * There might be collisions later when the the thunk is expanded.
1426 imt_collisions_bitmap |= (1 << i);
1429 * The IMT thunk might be called with an instance of one of the
1430 * generic virtual methods, so has to fallback to the IMT trampoline.
1432 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1434 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1437 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1441 if (imt_builder [i] != NULL) {
1442 int methods_in_slot = imt_builder [i]->children + 1;
1443 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1444 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1445 record_method_count_for_max_collisions = TRUE;
1447 method_count += methods_in_slot;
1451 mono_stats.imt_number_of_methods += method_count;
1452 if (record_method_count_for_max_collisions) {
1453 mono_stats.imt_method_count_when_max_collisions = method_count;
1456 for (i = 0; i < MONO_IMT_SIZE; i++) {
1457 MonoImtBuilderEntry* entry = imt_builder [i];
1458 while (entry != NULL) {
1459 MonoImtBuilderEntry* next = entry->next;
1465 /* we OR the bitmap since we may build just a single imt slot at a time */
1466 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1470 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1471 MONO_REQ_GC_NEUTRAL_MODE;
1473 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1477 * mono_vtable_build_imt_slot:
1478 * @vtable: virtual object table struct
1479 * @imt_slot: slot in the IMT table
1481 * Fill the given @imt_slot in the IMT table of @vtable with
1482 * a trampoline or a thunk for the case of collisions.
1483 * This is part of the internal mono API.
1485 * LOCKING: Take the domain lock.
1488 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1490 MONO_REQ_GC_NEUTRAL_MODE;
1492 gpointer *imt = (gpointer*)vtable;
1493 imt -= MONO_IMT_SIZE;
1494 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1496 /* no support for extra interfaces: the proxy objects will need
1497 * to build the complete IMT
1498 * Update and heck needs to ahppen inside the proper domain lock, as all
1499 * the changes made to a MonoVTable.
1501 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1502 mono_domain_lock (vtable->domain);
1503 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1504 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1505 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1506 mono_domain_unlock (vtable->domain);
1507 mono_loader_unlock ();
1512 * The first two free list entries both belong to the wait list: The
1513 * first entry is the pointer to the head of the list and the second
1514 * entry points to the last element. That way appending and removing
1515 * the first element are both O(1) operations.
1517 #ifdef MONO_SMALL_CONFIG
1518 #define NUM_FREE_LISTS 6
1520 #define NUM_FREE_LISTS 12
1522 #define FIRST_FREE_LIST_SIZE 64
1523 #define MAX_WAIT_LENGTH 50
1524 #define THUNK_THRESHOLD 10
1527 * LOCKING: The domain lock must be held.
1530 init_thunk_free_lists (MonoDomain *domain)
1532 MONO_REQ_GC_NEUTRAL_MODE;
1534 if (domain->thunk_free_lists)
1536 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1540 list_index_for_size (int item_size)
1543 int size = FIRST_FREE_LIST_SIZE;
1545 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1554 * mono_method_alloc_generic_virtual_thunk:
1556 * @size: size in bytes
1558 * Allocs size bytes to be used for the code of a generic virtual
1559 * thunk. It's either allocated from the domain's code manager or
1560 * reused from a previously invalidated piece.
1562 * LOCKING: The domain lock must be held.
1565 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1567 MONO_REQ_GC_NEUTRAL_MODE;
1569 static gboolean inited = FALSE;
1570 static int generic_virtual_thunks_size = 0;
1574 MonoThunkFreeList **l;
1576 init_thunk_free_lists (domain);
1578 size += sizeof (guint32);
1579 if (size < sizeof (MonoThunkFreeList))
1580 size = sizeof (MonoThunkFreeList);
1582 i = list_index_for_size (size);
1583 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1584 if ((*l)->size >= size) {
1585 MonoThunkFreeList *item = *l;
1587 return ((guint32*)item) + 1;
1591 /* no suitable item found - search lists of larger sizes */
1592 while (++i < NUM_FREE_LISTS) {
1593 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1596 g_assert (item->size > size);
1597 domain->thunk_free_lists [i] = item->next;
1598 return ((guint32*)item) + 1;
1601 /* still nothing found - allocate it */
1603 mono_counters_register ("Generic virtual thunk bytes",
1604 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1607 generic_virtual_thunks_size += size;
1609 p = (guint32 *)mono_domain_code_reserve (domain, size);
1612 mono_domain_lock (domain);
1613 if (!domain->generic_virtual_thunks)
1614 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1615 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1616 mono_domain_unlock (domain);
1622 * LOCKING: The domain lock must be held.
1625 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1627 MONO_REQ_GC_NEUTRAL_MODE;
1629 guint32 *p = (guint32 *)code;
1630 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1631 gboolean found = FALSE;
1633 mono_domain_lock (domain);
1634 if (!domain->generic_virtual_thunks)
1635 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1636 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1638 mono_domain_unlock (domain);
1641 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1643 init_thunk_free_lists (domain);
1645 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1646 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1647 int length = item->length;
1650 /* unlink the first item from the wait list */
1651 domain->thunk_free_lists [0] = item->next;
1652 domain->thunk_free_lists [0]->length = length - 1;
1654 i = list_index_for_size (item->size);
1656 /* put it in the free list */
1657 item->next = domain->thunk_free_lists [i];
1658 domain->thunk_free_lists [i] = item;
1662 if (domain->thunk_free_lists [1]) {
1663 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1664 domain->thunk_free_lists [0]->length++;
1666 g_assert (!domain->thunk_free_lists [0]);
1668 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1669 domain->thunk_free_lists [0]->length = 1;
1673 typedef struct _GenericVirtualCase {
1677 struct _GenericVirtualCase *next;
1678 } GenericVirtualCase;
1681 * get_generic_virtual_entries:
1683 * Return IMT entries for the generic virtual method instances and
1684 * variant interface methods for vtable slot
1687 static MonoImtBuilderEntry*
1688 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1690 MONO_REQ_GC_NEUTRAL_MODE;
1692 GenericVirtualCase *list;
1693 MonoImtBuilderEntry *entries;
1695 mono_domain_lock (domain);
1696 if (!domain->generic_virtual_cases)
1697 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1699 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1702 for (; list; list = list->next) {
1703 MonoImtBuilderEntry *entry;
1705 if (list->count < THUNK_THRESHOLD)
1708 entry = g_new0 (MonoImtBuilderEntry, 1);
1709 entry->key = list->method;
1710 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1711 entry->has_target_code = 1;
1713 entry->children = entries->children + 1;
1714 entry->next = entries;
1718 mono_domain_unlock (domain);
1720 /* FIXME: Leaking memory ? */
1725 * mono_method_add_generic_virtual_invocation:
1727 * @vtable_slot: pointer to the vtable slot
1728 * @method: the inflated generic virtual method
1729 * @code: the method's code
1731 * Registers a call via unmanaged code to a generic virtual method
1732 * instantiation or variant interface method. If the number of calls reaches a threshold
1733 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1734 * virtual method thunk.
1737 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1738 gpointer *vtable_slot,
1739 MonoMethod *method, gpointer code)
1741 MONO_REQ_GC_NEUTRAL_MODE;
1743 static gboolean inited = FALSE;
1744 static int num_added = 0;
1746 GenericVirtualCase *gvc, *list;
1747 MonoImtBuilderEntry *entries;
1751 mono_domain_lock (domain);
1752 if (!domain->generic_virtual_cases)
1753 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1755 /* Check whether the case was already added */
1756 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1759 if (gvc->method == method)
1764 /* If not found, make a new one */
1766 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1767 gvc->method = method;
1770 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1772 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1775 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1781 if (++gvc->count == THUNK_THRESHOLD) {
1782 gpointer *old_thunk = (void **)*vtable_slot;
1783 gpointer vtable_trampoline = NULL;
1784 gpointer imt_trampoline = NULL;
1786 if ((gpointer)vtable_slot < (gpointer)vtable) {
1787 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1788 int imt_slot = MONO_IMT_SIZE + displacement;
1790 /* Force the rebuild of the thunk at the next call */
1791 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1792 *vtable_slot = imt_trampoline;
1794 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1796 entries = get_generic_virtual_entries (domain, vtable_slot);
1798 sorted = imt_sort_slot_entries (entries);
1800 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1804 MonoImtBuilderEntry *next = entries->next;
1809 for (i = 0; i < sorted->len; ++i)
1810 g_free (g_ptr_array_index (sorted, i));
1811 g_ptr_array_free (sorted, TRUE);
1814 #ifndef __native_client__
1815 /* We don't re-use any thunks as there is a lot of overhead */
1816 /* to deleting and re-using code in Native Client. */
1817 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1818 invalidate_generic_virtual_thunk (domain, old_thunk);
1822 mono_domain_unlock (domain);
1825 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1828 * mono_class_vtable:
1829 * @domain: the application domain
1830 * @class: the class to initialize
1832 * VTables are domain specific because we create domain specific code, and
1833 * they contain the domain specific static class data.
1834 * On failure, NULL is returned, and class->exception_type is set.
1837 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1839 return mono_class_vtable_full (domain, klass, FALSE);
1843 * mono_class_vtable_full:
1844 * @domain: the application domain
1845 * @class: the class to initialize
1846 * @raise_on_error if an exception should be raised on failure or not
1848 * VTables are domain specific because we create domain specific code, and
1849 * they contain the domain specific static class data.
1852 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1854 MONO_REQ_GC_UNSAFE_MODE;
1856 MonoClassRuntimeInfo *runtime_info;
1860 if (klass->exception_type) {
1862 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1866 /* this check can be inlined in jitted code, too */
1867 runtime_info = klass->runtime_info;
1868 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1869 return runtime_info->domain_vtables [domain->domain_id];
1870 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1874 * mono_class_try_get_vtable:
1875 * @domain: the application domain
1876 * @class: the class to initialize
1878 * This function tries to get the associated vtable from @class if
1879 * it was already created.
1882 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1884 MONO_REQ_GC_NEUTRAL_MODE;
1886 MonoClassRuntimeInfo *runtime_info;
1890 runtime_info = klass->runtime_info;
1891 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1892 return runtime_info->domain_vtables [domain->domain_id];
1897 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1899 MONO_REQ_GC_NEUTRAL_MODE;
1901 size_t alloc_offset;
1904 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1905 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1906 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1908 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1909 g_assert ((imt_table_bytes & 7) == 4);
1916 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1920 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1922 MONO_REQ_GC_UNSAFE_MODE;
1926 MonoClassRuntimeInfo *runtime_info, *old_info;
1927 MonoClassField *field;
1929 int i, vtable_slots;
1930 size_t imt_table_bytes;
1932 guint32 vtable_size, class_size;
1934 gpointer *interface_offsets;
1936 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1937 mono_domain_lock (domain);
1938 runtime_info = klass->runtime_info;
1939 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1940 mono_domain_unlock (domain);
1941 mono_loader_unlock ();
1942 return runtime_info->domain_vtables [domain->domain_id];
1944 if (!klass->inited || klass->exception_type) {
1945 if (!mono_class_init (klass) || klass->exception_type) {
1946 mono_domain_unlock (domain);
1947 mono_loader_unlock ();
1949 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1954 /* Array types require that their element type be valid*/
1955 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1956 MonoClass *element_class = klass->element_class;
1957 if (!element_class->inited)
1958 mono_class_init (element_class);
1960 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1961 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1962 mono_class_setup_vtable (element_class);
1964 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1965 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1966 if (klass->exception_type == MONO_EXCEPTION_NONE)
1967 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1968 mono_domain_unlock (domain);
1969 mono_loader_unlock ();
1971 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1977 * For some classes, mono_class_init () already computed klass->vtable_size, and
1978 * that is all that is needed because of the vtable trampolines.
1980 if (!klass->vtable_size)
1981 mono_class_setup_vtable (klass);
1983 if (klass->generic_class && !klass->vtable)
1984 mono_class_check_vtable_constraints (klass, NULL);
1986 /* Initialize klass->has_finalize */
1987 mono_class_has_finalizer (klass);
1989 if (klass->exception_type) {
1990 mono_domain_unlock (domain);
1991 mono_loader_unlock ();
1993 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1997 vtable_slots = klass->vtable_size;
1998 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1999 class_size = mono_class_data_size (klass);
2003 if (klass->interface_offsets_count) {
2004 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2005 mono_stats.imt_number_of_tables++;
2006 mono_stats.imt_tables_size += imt_table_bytes;
2008 imt_table_bytes = 0;
2011 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2013 mono_stats.used_class_count++;
2014 mono_stats.class_vtable_size += vtable_size;
2016 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2017 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2018 g_assert (!((gsize)vt & 7));
2021 vt->rank = klass->rank;
2022 vt->domain = domain;
2024 mono_class_compute_gc_descriptor (klass);
2026 * We can't use typed allocation in the non-root domains, since the
2027 * collector needs the GC descriptor stored in the vtable even after
2028 * the mempool containing the vtable is destroyed when the domain is
2029 * unloaded. An alternative might be to allocate vtables in the GC
2030 * heap, but this does not seem to work (it leads to crashes inside
2031 * libgc). If that approach is tried, two gc descriptors need to be
2032 * allocated for each class: one for the root domain, and one for all
2033 * other domains. The second descriptor should contain a bit for the
2034 * vtable field in MonoObject, since we can no longer assume the
2035 * vtable is reachable by other roots after the appdomain is unloaded.
2037 #ifdef HAVE_BOEHM_GC
2038 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2039 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2042 vt->gc_descr = klass->gc_descr;
2044 gc_bits = mono_gc_get_vtable_bits (klass);
2045 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2047 vt->gc_bits = gc_bits;
2050 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2051 if (klass->has_static_refs) {
2052 MonoGCDescriptor statics_gc_descr;
2054 gsize default_bitmap [4] = {0};
2057 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2058 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2059 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2060 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2061 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2062 if (bitmap != default_bitmap)
2065 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2067 vt->has_static_fields = TRUE;
2068 mono_stats.class_static_data_size += class_size;
2072 while ((field = mono_class_get_fields (klass, &iter))) {
2073 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2075 if (mono_field_is_deleted (field))
2077 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2078 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2079 if (special_static != SPECIAL_STATIC_NONE) {
2080 guint32 size, offset;
2082 gsize default_bitmap [4] = {0};
2087 if (mono_type_is_reference (field->type)) {
2088 default_bitmap [0] = 1;
2090 bitmap = default_bitmap;
2091 } else if (mono_type_is_struct (field->type)) {
2092 fclass = mono_class_from_mono_type (field->type);
2093 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2094 numbits = max_set + 1;
2096 default_bitmap [0] = 0;
2098 bitmap = default_bitmap;
2100 size = mono_type_size (field->type, &align);
2101 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2102 if (!domain->special_static_fields)
2103 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2104 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2105 if (bitmap != default_bitmap)
2108 * This marks the field as special static to speed up the
2109 * checks in mono_field_static_get/set_value ().
2115 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2116 MonoClass *fklass = mono_class_from_mono_type (field->type);
2117 const char *data = mono_field_get_data (field);
2119 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2120 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2121 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2124 if (fklass->valuetype) {
2125 memcpy (t, data, mono_class_value_size (fklass, NULL));
2127 /* it's a pointer type: add check */
2128 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2135 vt->max_interface_id = klass->max_interface_id;
2136 vt->interface_bitmap = klass->interface_bitmap;
2138 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2139 // class->name, klass->interface_offsets_count);
2141 /* Initialize vtable */
2142 if (callbacks.get_vtable_trampoline) {
2143 // This also covers the AOT case
2144 for (i = 0; i < klass->vtable_size; ++i) {
2145 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2148 mono_class_setup_vtable (klass);
2150 for (i = 0; i < klass->vtable_size; ++i) {
2153 if ((cm = klass->vtable [i]))
2154 vt->vtable [i] = arch_create_jit_trampoline (cm);
2158 if (imt_table_bytes) {
2159 /* Now that the vtable is full, we can actually fill up the IMT */
2160 for (i = 0; i < MONO_IMT_SIZE; ++i)
2161 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2165 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2166 * re-acquire them and check if another thread has created the vtable in the meantime.
2168 /* Special case System.MonoType to avoid infinite recursion */
2169 if (klass != mono_defaults.monotype_class) {
2170 /*FIXME check for OOM*/
2171 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2172 mono_error_raise_exception (&error); /* FIXME don't raise here */
2174 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2175 /* This is unregistered in
2176 unregister_vtable_reflection_type() in
2178 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2181 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2183 /* class_vtable_array keeps an array of created vtables
2185 g_ptr_array_add (domain->class_vtable_array, vt);
2186 /* klass->runtime_info is protected by the loader lock, both when
2187 * it it enlarged and when it is stored info.
2191 * Store the vtable in klass->runtime_info.
2192 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2194 mono_memory_barrier ();
2196 old_info = klass->runtime_info;
2197 if (old_info && old_info->max_domain >= domain->domain_id) {
2198 /* someone already created a large enough runtime info */
2199 old_info->domain_vtables [domain->domain_id] = vt;
2201 int new_size = domain->domain_id;
2203 new_size = MAX (new_size, old_info->max_domain);
2205 /* make the new size a power of two */
2207 while (new_size > i)
2210 /* this is a bounded memory retention issue: may want to
2211 * handle it differently when we'll have a rcu-like system.
2213 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2214 runtime_info->max_domain = new_size - 1;
2215 /* copy the stuff from the older info */
2217 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2219 runtime_info->domain_vtables [domain->domain_id] = vt;
2221 mono_memory_barrier ();
2222 klass->runtime_info = runtime_info;
2225 if (klass == mono_defaults.monotype_class) {
2226 /*FIXME check for OOM*/
2227 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2228 mono_error_raise_exception (&error); /* FIXME don't raise here */
2230 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2231 /* This is unregistered in
2232 unregister_vtable_reflection_type() in
2234 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2237 mono_domain_unlock (domain);
2238 mono_loader_unlock ();
2240 /* make sure the parent is initialized */
2241 /*FIXME shouldn't this fail the current type?*/
2243 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2248 #ifndef DISABLE_REMOTING
2250 * mono_class_proxy_vtable:
2251 * @domain: the application domain
2252 * @remove_class: the remote class
2254 * Creates a vtable for transparent proxies. It is basically
2255 * a copy of the real vtable of the class wrapped in @remote_class,
2256 * but all function pointers invoke the remoting functions, and
2257 * vtable->klass points to the transparent proxy class, and not to @class.
2260 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2262 MONO_REQ_GC_UNSAFE_MODE;
2265 MonoVTable *vt, *pvt;
2266 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2268 GSList *extra_interfaces = NULL;
2269 MonoClass *klass = remote_class->proxy_class;
2270 gpointer *interface_offsets;
2273 size_t imt_table_bytes;
2275 #ifdef COMPRESSED_INTERFACE_BITMAP
2279 vt = mono_class_vtable (domain, klass);
2280 g_assert (vt); /*FIXME property handle failure*/
2281 max_interface_id = vt->max_interface_id;
2283 /* Calculate vtable space for extra interfaces */
2284 for (j = 0; j < remote_class->interface_count; j++) {
2285 MonoClass* iclass = remote_class->interfaces[j];
2289 /*FIXME test for interfaces with variant generic arguments*/
2290 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2291 continue; /* interface implemented by the class */
2292 if (g_slist_find (extra_interfaces, iclass))
2295 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2297 method_count = mono_class_num_methods (iclass);
2299 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2300 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2302 for (i = 0; i < ifaces->len; ++i) {
2303 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2304 /*FIXME test for interfaces with variant generic arguments*/
2305 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2306 continue; /* interface implemented by the class */
2307 if (g_slist_find (extra_interfaces, ic))
2309 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2310 method_count += mono_class_num_methods (ic);
2312 g_ptr_array_free (ifaces, TRUE);
2315 extra_interface_vtsize += method_count * sizeof (gpointer);
2316 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2319 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2320 mono_stats.imt_number_of_tables++;
2321 mono_stats.imt_tables_size += imt_table_bytes;
2323 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2325 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2327 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2328 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2329 g_assert (!((gsize)pvt & 7));
2331 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2333 pvt->klass = mono_defaults.transparent_proxy_class;
2334 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2335 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2337 /* initialize vtable */
2338 mono_class_setup_vtable (klass);
2339 for (i = 0; i < klass->vtable_size; ++i) {
2342 if ((cm = klass->vtable [i]))
2343 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2345 pvt->vtable [i] = NULL;
2348 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2349 /* create trampolines for abstract methods */
2350 for (k = klass; k; k = k->parent) {
2352 gpointer iter = NULL;
2353 while ((m = mono_class_get_methods (k, &iter)))
2354 if (!pvt->vtable [m->slot])
2355 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2359 pvt->max_interface_id = max_interface_id;
2360 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2361 #ifdef COMPRESSED_INTERFACE_BITMAP
2362 bitmap = (uint8_t *)g_malloc0 (bsize);
2364 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2367 for (i = 0; i < klass->interface_offsets_count; ++i) {
2368 int interface_id = klass->interfaces_packed [i]->interface_id;
2369 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2372 if (extra_interfaces) {
2373 int slot = klass->vtable_size;
2379 /* Create trampolines for the methods of the interfaces */
2380 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2381 interf = (MonoClass *)list_item->data;
2383 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2387 while ((cm = mono_class_get_methods (interf, &iter)))
2388 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2390 slot += mono_class_num_methods (interf);
2394 /* Now that the vtable is full, we can actually fill up the IMT */
2395 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2396 if (extra_interfaces) {
2397 g_slist_free (extra_interfaces);
2400 #ifdef COMPRESSED_INTERFACE_BITMAP
2401 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2402 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2403 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2406 pvt->interface_bitmap = bitmap;
2411 #endif /* DISABLE_REMOTING */
2414 * mono_class_field_is_special_static:
2416 * Returns whether @field is a thread/context static field.
2419 mono_class_field_is_special_static (MonoClassField *field)
2421 MONO_REQ_GC_NEUTRAL_MODE
2423 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2425 if (mono_field_is_deleted (field))
2427 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2428 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2435 * mono_class_field_get_special_static_type:
2436 * @field: The MonoClassField describing the field.
2438 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2439 * SPECIAL_STATIC_NONE otherwise.
2442 mono_class_field_get_special_static_type (MonoClassField *field)
2444 MONO_REQ_GC_NEUTRAL_MODE
2446 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2447 return SPECIAL_STATIC_NONE;
2448 if (mono_field_is_deleted (field))
2449 return SPECIAL_STATIC_NONE;
2450 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2451 return field_is_special_static (field->parent, field);
2452 return SPECIAL_STATIC_NONE;
2456 * mono_class_has_special_static_fields:
2458 * Returns whenever @klass has any thread/context static fields.
2461 mono_class_has_special_static_fields (MonoClass *klass)
2463 MONO_REQ_GC_NEUTRAL_MODE
2465 MonoClassField *field;
2469 while ((field = mono_class_get_fields (klass, &iter))) {
2470 g_assert (field->parent == klass);
2471 if (mono_class_field_is_special_static (field))
2478 #ifndef DISABLE_REMOTING
2480 * create_remote_class_key:
2481 * Creates an array of pointers that can be used as a hash key for a remote class.
2482 * The first element of the array is the number of pointers.
2485 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2487 MONO_REQ_GC_NEUTRAL_MODE;
2492 if (remote_class == NULL) {
2493 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2494 key = (void **)g_malloc (sizeof(gpointer) * 3);
2495 key [0] = GINT_TO_POINTER (2);
2496 key [1] = mono_defaults.marshalbyrefobject_class;
2497 key [2] = extra_class;
2499 key = (void **)g_malloc (sizeof(gpointer) * 2);
2500 key [0] = GINT_TO_POINTER (1);
2501 key [1] = extra_class;
2504 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2505 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2506 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2507 key [1] = remote_class->proxy_class;
2509 // Keep the list of interfaces sorted
2510 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2511 if (extra_class && remote_class->interfaces [i] > extra_class) {
2512 key [j++] = extra_class;
2515 key [j] = remote_class->interfaces [i];
2518 key [j] = extra_class;
2520 // Replace the old class. The interface list is the same
2521 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2522 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2523 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2524 for (i = 0; i < remote_class->interface_count; i++)
2525 key [2 + i] = remote_class->interfaces [i];
2533 * copy_remote_class_key:
2535 * Make a copy of KEY in the domain and return the copy.
2538 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2540 MONO_REQ_GC_NEUTRAL_MODE
2542 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2543 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2545 memcpy (mp_key, key, key_size);
2551 * mono_remote_class:
2552 * @domain: the application domain
2553 * @class_name: name of the remote class
2555 * Creates and initializes a MonoRemoteClass object for a remote type.
2557 * Can raise an exception on failure.
2560 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2562 MONO_REQ_GC_UNSAFE_MODE;
2565 MonoRemoteClass *rc;
2566 gpointer* key, *mp_key;
2569 key = create_remote_class_key (NULL, proxy_class);
2571 mono_domain_lock (domain);
2572 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2576 mono_domain_unlock (domain);
2580 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2581 if (!mono_error_ok (&error)) {
2583 mono_domain_unlock (domain);
2584 mono_error_raise_exception (&error);
2587 mp_key = copy_remote_class_key (domain, key);
2591 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2592 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2593 rc->interface_count = 1;
2594 rc->interfaces [0] = proxy_class;
2595 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2597 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2598 rc->interface_count = 0;
2599 rc->proxy_class = proxy_class;
2602 rc->default_vtable = NULL;
2603 rc->xdomain_vtable = NULL;
2604 rc->proxy_class_name = name;
2605 #ifndef DISABLE_PERFCOUNTERS
2606 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2609 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2611 mono_domain_unlock (domain);
2616 * clone_remote_class:
2617 * Creates a copy of the remote_class, adding the provided class or interface
2619 static MonoRemoteClass*
2620 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2622 MONO_REQ_GC_NEUTRAL_MODE;
2624 MonoRemoteClass *rc;
2625 gpointer* key, *mp_key;
2627 key = create_remote_class_key (remote_class, extra_class);
2628 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2634 mp_key = copy_remote_class_key (domain, key);
2638 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2640 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2641 rc->proxy_class = remote_class->proxy_class;
2642 rc->interface_count = remote_class->interface_count + 1;
2644 // Keep the list of interfaces sorted, since the hash key of
2645 // the remote class depends on this
2646 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2647 if (remote_class->interfaces [i] > extra_class && i == j)
2648 rc->interfaces [j++] = extra_class;
2649 rc->interfaces [j] = remote_class->interfaces [i];
2652 rc->interfaces [j] = extra_class;
2654 // Replace the old class. The interface array is the same
2655 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2656 rc->proxy_class = extra_class;
2657 rc->interface_count = remote_class->interface_count;
2658 if (rc->interface_count > 0)
2659 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2662 rc->default_vtable = NULL;
2663 rc->xdomain_vtable = NULL;
2664 rc->proxy_class_name = remote_class->proxy_class_name;
2666 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2672 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2674 MONO_REQ_GC_UNSAFE_MODE;
2676 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2677 mono_domain_lock (domain);
2678 if (rp->target_domain_id != -1) {
2679 if (remote_class->xdomain_vtable == NULL)
2680 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2681 mono_domain_unlock (domain);
2682 mono_loader_unlock ();
2683 return remote_class->xdomain_vtable;
2685 if (remote_class->default_vtable == NULL) {
2688 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2689 klass = mono_class_from_mono_type (type);
2691 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)))
2692 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2695 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2698 mono_domain_unlock (domain);
2699 mono_loader_unlock ();
2700 return remote_class->default_vtable;
2704 * mono_upgrade_remote_class:
2705 * @domain: the application domain
2706 * @tproxy: the proxy whose remote class has to be upgraded.
2707 * @klass: class to which the remote class can be casted.
2709 * Updates the vtable of the remote class by adding the necessary method slots
2710 * and interface offsets so it can be safely casted to klass. klass can be a
2711 * class or an interface.
2714 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2716 MONO_REQ_GC_UNSAFE_MODE;
2718 MonoTransparentProxy *tproxy;
2719 MonoRemoteClass *remote_class;
2720 gboolean redo_vtable;
2722 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2723 mono_domain_lock (domain);
2725 tproxy = (MonoTransparentProxy*) proxy_object;
2726 remote_class = tproxy->remote_class;
2728 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2731 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2732 if (remote_class->interfaces [i] == klass)
2733 redo_vtable = FALSE;
2736 redo_vtable = (remote_class->proxy_class != klass);
2740 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2741 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2744 mono_domain_unlock (domain);
2745 mono_loader_unlock ();
2747 #endif /* DISABLE_REMOTING */
2751 * mono_object_get_virtual_method:
2752 * @obj: object to operate on.
2755 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2756 * the instance of a callvirt of method.
2759 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2761 MONO_REQ_GC_UNSAFE_MODE;
2764 MonoMethod **vtable;
2765 gboolean is_proxy = FALSE;
2766 MonoMethod *res = NULL;
2768 klass = mono_object_class (obj);
2769 #ifndef DISABLE_REMOTING
2770 if (klass == mono_defaults.transparent_proxy_class) {
2771 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2776 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2779 mono_class_setup_vtable (klass);
2780 vtable = klass->vtable;
2782 if (method->slot == -1) {
2783 /* method->slot might not be set for instances of generic methods */
2784 if (method->is_inflated) {
2785 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2786 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2789 g_assert_not_reached ();
2793 /* check method->slot is a valid index: perform isinstance? */
2794 if (method->slot != -1) {
2795 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2797 gboolean variance_used = FALSE;
2798 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2799 g_assert (iface_offset > 0);
2800 res = vtable [iface_offset + method->slot];
2803 res = vtable [method->slot];
2807 #ifndef DISABLE_REMOTING
2809 /* It may be an interface, abstract class method or generic method */
2810 if (!res || mono_method_signature (res)->generic_param_count)
2813 /* generic methods demand invoke_with_check */
2814 if (mono_method_signature (res)->generic_param_count)
2815 res = mono_marshal_get_remoting_invoke_with_check (res);
2818 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2819 res = mono_cominterop_get_invoke (res);
2822 res = mono_marshal_get_remoting_invoke (res);
2827 if (method->is_inflated) {
2829 /* Have to inflate the result */
2830 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2831 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2841 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2843 MonoObject *result = NULL;
2846 g_assert (callbacks.runtime_invoke);
2847 result = callbacks.runtime_invoke (method, obj, params, &error, exc);
2848 if (!mono_error_ok (&error)) {
2850 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
2853 mono_error_raise_exception (&error);
2861 * mono_runtime_invoke:
2862 * @method: method to invoke
2863 * @obJ: object instance
2864 * @params: arguments to the method
2865 * @exc: exception information.
2867 * Invokes the method represented by @method on the object @obj.
2869 * obj is the 'this' pointer, it should be NULL for static
2870 * methods, a MonoObject* for object instances and a pointer to
2871 * the value type for value types.
2873 * The params array contains the arguments to the method with the
2874 * same convention: MonoObject* pointers for object instances and
2875 * pointers to the value type otherwise.
2877 * From unmanaged code you'll usually use the
2878 * mono_runtime_invoke() variant.
2880 * Note that this function doesn't handle virtual methods for
2881 * you, it will exec the exact method you pass: we still need to
2882 * expose a function to lookup the derived class implementation
2883 * of a virtual method (there are examples of this in the code,
2886 * You can pass NULL as the exc argument if you don't want to
2887 * catch exceptions, otherwise, *exc will be set to the exception
2888 * thrown, if any. if an exception is thrown, you can't use the
2889 * MonoObject* result from the function.
2891 * If the method returns a value type, it is boxed in an object
2895 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2897 MONO_REQ_GC_UNSAFE_MODE;
2902 if (mono_runtime_get_no_exec ())
2903 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2905 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2906 mono_profiler_method_start_invoke (method);
2908 MONO_PREPARE_RESET_BLOCKING;
2910 result = do_runtime_invoke (method, obj, params, exc, &error);
2911 mono_error_raise_exception (&error); /* FIXME don't raise here */
2913 MONO_FINISH_RESET_BLOCKING;
2915 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2916 mono_profiler_method_end_invoke (method);
2922 * mono_method_get_unmanaged_thunk:
2923 * @method: method to generate a thunk for.
2925 * Returns an unmanaged->managed thunk that can be used to call
2926 * a managed method directly from C.
2928 * The thunk's C signature closely matches the managed signature:
2930 * C#: public bool Equals (object obj);
2931 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2932 * MonoObject*, MonoException**);
2934 * The 1st ("this") parameter must not be used with static methods:
2936 * C#: public static bool ReferenceEquals (object a, object b);
2937 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2940 * The last argument must be a non-null pointer of a MonoException* pointer.
2941 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2942 * exception has been thrown in managed code. Otherwise it will point
2943 * to the MonoException* caught by the thunk. In this case, the result of
2944 * the thunk is undefined:
2946 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2947 * MonoException *ex = NULL;
2948 * Equals func = mono_method_get_unmanaged_thunk (method);
2949 * MonoBoolean res = func (thisObj, objToCompare, &ex);
2951 * // handle exception
2954 * The calling convention of the thunk matches the platform's default
2955 * convention. This means that under Windows, C declarations must
2956 * contain the __stdcall attribute:
2958 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2959 * MonoObject*, MonoException**);
2963 * Value type arguments and return values are treated as they were objects:
2965 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2966 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2968 * Arguments must be properly boxed upon trunk's invocation, while return
2969 * values must be unboxed.
2972 mono_method_get_unmanaged_thunk (MonoMethod *method)
2974 MONO_REQ_GC_NEUTRAL_MODE;
2975 MONO_REQ_API_ENTRYPOINT;
2979 MONO_PREPARE_RESET_BLOCKING;
2980 method = mono_marshal_get_thunk_invoke_wrapper (method);
2981 res = mono_compile_method (method);
2982 MONO_FINISH_RESET_BLOCKING;
2988 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
2990 MONO_REQ_GC_UNSAFE_MODE;
2994 /* object fields cannot be byref, so we don't need a
2996 gpointer *p = (gpointer*)dest;
3003 case MONO_TYPE_BOOLEAN:
3005 case MONO_TYPE_U1: {
3006 guint8 *p = (guint8*)dest;
3007 *p = value ? *(guint8*)value : 0;
3012 case MONO_TYPE_CHAR: {
3013 guint16 *p = (guint16*)dest;
3014 *p = value ? *(guint16*)value : 0;
3017 #if SIZEOF_VOID_P == 4
3022 case MONO_TYPE_U4: {
3023 gint32 *p = (gint32*)dest;
3024 *p = value ? *(gint32*)value : 0;
3027 #if SIZEOF_VOID_P == 8
3032 case MONO_TYPE_U8: {
3033 gint64 *p = (gint64*)dest;
3034 *p = value ? *(gint64*)value : 0;
3037 case MONO_TYPE_R4: {
3038 float *p = (float*)dest;
3039 *p = value ? *(float*)value : 0;
3042 case MONO_TYPE_R8: {
3043 double *p = (double*)dest;
3044 *p = value ? *(double*)value : 0;
3047 case MONO_TYPE_STRING:
3048 case MONO_TYPE_SZARRAY:
3049 case MONO_TYPE_CLASS:
3050 case MONO_TYPE_OBJECT:
3051 case MONO_TYPE_ARRAY:
3052 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3054 case MONO_TYPE_FNPTR:
3055 case MONO_TYPE_PTR: {
3056 gpointer *p = (gpointer*)dest;
3057 *p = deref_pointer? *(gpointer*)value: value;
3060 case MONO_TYPE_VALUETYPE:
3061 /* note that 't' and 'type->type' can be different */
3062 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3063 t = mono_class_enum_basetype (type->data.klass)->type;
3066 MonoClass *klass = mono_class_from_mono_type (type);
3067 int size = mono_class_value_size (klass, NULL);
3069 mono_gc_bzero_atomic (dest, size);
3071 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3074 case MONO_TYPE_GENERICINST:
3075 t = type->data.generic_class->container_class->byval_arg.type;
3078 g_error ("got type %x", type->type);
3083 * mono_field_set_value:
3084 * @obj: Instance object
3085 * @field: MonoClassField describing the field to set
3086 * @value: The value to be set
3088 * Sets the value of the field described by @field in the object instance @obj
3089 * to the value passed in @value. This method should only be used for instance
3090 * fields. For static fields, use mono_field_static_set_value.
3092 * The value must be on the native format of the field type.
3095 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3097 MONO_REQ_GC_UNSAFE_MODE;
3101 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3103 dest = (char*)obj + field->offset;
3104 mono_copy_value (field->type, dest, value, FALSE);
3108 * mono_field_static_set_value:
3109 * @field: MonoClassField describing the field to set
3110 * @value: The value to be set
3112 * Sets the value of the static field described by @field
3113 * to the value passed in @value.
3115 * The value must be on the native format of the field type.
3118 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3120 MONO_REQ_GC_UNSAFE_MODE;
3124 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3125 /* you cant set a constant! */
3126 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3128 if (field->offset == -1) {
3129 /* Special static */
3132 mono_domain_lock (vt->domain);
3133 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3134 mono_domain_unlock (vt->domain);
3135 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3137 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3139 mono_copy_value (field->type, dest, value, FALSE);
3143 * mono_vtable_get_static_field_data:
3145 * Internal use function: return a pointer to the memory holding the static fields
3146 * for a class or NULL if there are no static fields.
3147 * This is exported only for use by the debugger.
3150 mono_vtable_get_static_field_data (MonoVTable *vt)
3152 MONO_REQ_GC_NEUTRAL_MODE
3154 if (!vt->has_static_fields)
3156 return vt->vtable [vt->klass->vtable_size];
3160 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3162 MONO_REQ_GC_UNSAFE_MODE;
3166 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3167 if (field->offset == -1) {
3168 /* Special static */
3171 mono_domain_lock (vt->domain);
3172 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3173 mono_domain_unlock (vt->domain);
3174 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3176 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3179 src = (guint8*)obj + field->offset;
3186 * mono_field_get_value:
3187 * @obj: Object instance
3188 * @field: MonoClassField describing the field to fetch information from
3189 * @value: pointer to the location where the value will be stored
3191 * Use this routine to get the value of the field @field in the object
3194 * The pointer provided by value must be of the field type, for reference
3195 * types this is a MonoObject*, for value types its the actual pointer to
3200 * mono_field_get_value (obj, int_field, &i);
3203 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3205 MONO_REQ_GC_UNSAFE_MODE;
3211 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3213 src = (char*)obj + field->offset;
3214 mono_copy_value (field->type, value, src, TRUE);
3218 * mono_field_get_value_object:
3219 * @domain: domain where the object will be created (if boxing)
3220 * @field: MonoClassField describing the field to fetch information from
3221 * @obj: The object instance for the field.
3223 * Returns: a new MonoObject with the value from the given field. If the
3224 * field represents a value type, the value is boxed.
3228 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3230 MONO_REQ_GC_UNSAFE_MODE;
3235 MonoVTable *vtable = NULL;
3237 gboolean is_static = FALSE;
3238 gboolean is_ref = FALSE;
3239 gboolean is_literal = FALSE;
3240 gboolean is_ptr = FALSE;
3241 MonoType *type = mono_field_get_type_checked (field, &error);
3243 if (!mono_error_ok (&error))
3244 mono_error_raise_exception (&error);
3246 switch (type->type) {
3247 case MONO_TYPE_STRING:
3248 case MONO_TYPE_OBJECT:
3249 case MONO_TYPE_CLASS:
3250 case MONO_TYPE_ARRAY:
3251 case MONO_TYPE_SZARRAY:
3256 case MONO_TYPE_BOOLEAN:
3259 case MONO_TYPE_CHAR:
3268 case MONO_TYPE_VALUETYPE:
3269 is_ref = type->byref;
3271 case MONO_TYPE_GENERICINST:
3272 is_ref = !mono_type_generic_inst_is_valuetype (type);
3278 g_error ("type 0x%x not handled in "
3279 "mono_field_get_value_object", type->type);
3283 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3286 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3290 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3291 if (!vtable->initialized)
3292 mono_runtime_class_init (vtable);
3300 get_default_field_value (domain, field, &o);
3301 } else if (is_static) {
3302 mono_field_static_get_value (vtable, field, &o);
3304 mono_field_get_value (obj, field, &o);
3310 static MonoMethod *m;
3316 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3317 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3323 get_default_field_value (domain, field, v);
3324 } else if (is_static) {
3325 mono_field_static_get_value (vtable, field, v);
3327 mono_field_get_value (obj, field, v);
3330 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3331 args [0] = ptr ? *ptr : NULL;
3332 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3333 mono_error_raise_exception (&error); /* FIXME don't raise here */
3335 return mono_runtime_invoke (m, NULL, args, NULL);
3338 /* boxed value type */
3339 klass = mono_class_from_mono_type (type);
3341 if (mono_class_is_nullable (klass))
3342 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3344 o = mono_object_new_checked (domain, klass, &error);
3345 mono_error_raise_exception (&error); /* FIXME don't raise here */
3346 v = ((gchar *) o) + sizeof (MonoObject);
3349 get_default_field_value (domain, field, v);
3350 } else if (is_static) {
3351 mono_field_static_get_value (vtable, field, v);
3353 mono_field_get_value (obj, field, v);
3360 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3362 MONO_REQ_GC_UNSAFE_MODE;
3365 const char *p = blob;
3366 mono_metadata_decode_blob_size (p, &p);
3369 case MONO_TYPE_BOOLEAN:
3372 *(guint8 *) value = *p;
3374 case MONO_TYPE_CHAR:
3377 *(guint16*) value = read16 (p);
3381 *(guint32*) value = read32 (p);
3385 *(guint64*) value = read64 (p);
3388 readr4 (p, (float*) value);
3391 readr8 (p, (double*) value);
3393 case MONO_TYPE_STRING:
3394 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3396 case MONO_TYPE_CLASS:
3397 *(gpointer*) value = NULL;
3401 g_warning ("type 0x%02x should not be in constant table", type);
3407 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3409 MONO_REQ_GC_NEUTRAL_MODE;
3411 MonoTypeEnum def_type;
3414 data = mono_class_get_field_default_value (field, &def_type);
3415 mono_get_constant_value_from_blob (domain, def_type, data, value);
3419 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3421 MONO_REQ_GC_UNSAFE_MODE;
3425 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3427 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3428 get_default_field_value (vt->domain, field, value);
3432 if (field->offset == -1) {
3433 /* Special static */
3434 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3435 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3437 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3439 mono_copy_value (field->type, value, src, TRUE);
3443 * mono_field_static_get_value:
3444 * @vt: vtable to the object
3445 * @field: MonoClassField describing the field to fetch information from
3446 * @value: where the value is returned
3448 * Use this routine to get the value of the static field @field value.
3450 * The pointer provided by value must be of the field type, for reference
3451 * types this is a MonoObject*, for value types its the actual pointer to
3456 * mono_field_static_get_value (vt, int_field, &i);
3459 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3461 MONO_REQ_GC_NEUTRAL_MODE;
3463 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3467 * mono_property_set_value:
3468 * @prop: MonoProperty to set
3469 * @obj: instance object on which to act
3470 * @params: parameters to pass to the propery
3471 * @exc: optional exception
3473 * Invokes the property's set method with the given arguments on the
3474 * object instance obj (or NULL for static properties).
3476 * You can pass NULL as the exc argument if you don't want to
3477 * catch exceptions, otherwise, *exc will be set to the exception
3478 * thrown, if any. if an exception is thrown, you can't use the
3479 * MonoObject* result from the function.
3482 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3484 MONO_REQ_GC_UNSAFE_MODE;
3487 do_runtime_invoke (prop->set, obj, params, exc, &error);
3488 mono_error_raise_exception (&error); /* FIXME don't raise here */
3492 * mono_property_get_value:
3493 * @prop: MonoProperty to fetch
3494 * @obj: instance object on which to act
3495 * @params: parameters to pass to the propery
3496 * @exc: optional exception
3498 * Invokes the property's get method with the given arguments on the
3499 * object instance obj (or NULL for static properties).
3501 * You can pass NULL as the exc argument if you don't want to
3502 * catch exceptions, otherwise, *exc will be set to the exception
3503 * thrown, if any. if an exception is thrown, you can't use the
3504 * MonoObject* result from the function.
3506 * Returns: the value from invoking the get method on the property.
3509 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3511 MONO_REQ_GC_UNSAFE_MODE;
3514 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3515 mono_error_raise_exception (&error); /* FIXME don't raise here */
3521 * mono_nullable_init:
3522 * @buf: The nullable structure to initialize.
3523 * @value: the value to initialize from
3524 * @klass: the type for the object
3526 * Initialize the nullable structure pointed to by @buf from @value which
3527 * should be a boxed value type. The size of @buf should be able to hold
3528 * as much data as the @klass->instance_size (which is the number of bytes
3529 * that will be copies).
3531 * Since Nullables have variable structure, we can not define a C
3532 * structure for them.
3535 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3537 MONO_REQ_GC_UNSAFE_MODE;
3539 MonoClass *param_class = klass->cast_class;
3541 mono_class_setup_fields_locking (klass);
3542 g_assert (klass->fields_inited);
3544 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3545 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3547 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3549 if (param_class->has_references)
3550 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3552 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3554 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3559 * mono_nullable_box:
3560 * @buf: The buffer representing the data to be boxed
3561 * @klass: the type to box it as.
3563 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3567 mono_nullable_box (guint8 *buf, MonoClass *klass)
3569 MONO_REQ_GC_UNSAFE_MODE;
3573 MonoClass *param_class = klass->cast_class;
3575 mono_class_setup_fields_locking (klass);
3576 g_assert (klass->fields_inited);
3578 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3579 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3581 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3582 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3583 mono_error_raise_exception (&error); /* FIXME don't raise here */
3584 if (param_class->has_references)
3585 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3587 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3595 * mono_get_delegate_invoke:
3596 * @klass: The delegate class
3598 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3601 mono_get_delegate_invoke (MonoClass *klass)
3603 MONO_REQ_GC_NEUTRAL_MODE;
3607 /* This is called at runtime, so avoid the slower search in metadata */
3608 mono_class_setup_methods (klass);
3609 if (klass->exception_type)
3611 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3616 * mono_get_delegate_begin_invoke:
3617 * @klass: The delegate class
3619 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3622 mono_get_delegate_begin_invoke (MonoClass *klass)
3624 MONO_REQ_GC_NEUTRAL_MODE;
3628 /* This is called at runtime, so avoid the slower search in metadata */
3629 mono_class_setup_methods (klass);
3630 if (klass->exception_type)
3632 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3637 * mono_get_delegate_end_invoke:
3638 * @klass: The delegate class
3640 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3643 mono_get_delegate_end_invoke (MonoClass *klass)
3645 MONO_REQ_GC_NEUTRAL_MODE;
3649 /* This is called at runtime, so avoid the slower search in metadata */
3650 mono_class_setup_methods (klass);
3651 if (klass->exception_type)
3653 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3658 * mono_runtime_delegate_invoke:
3659 * @delegate: pointer to a delegate object.
3660 * @params: parameters for the delegate.
3661 * @exc: Pointer to the exception result.
3663 * Invokes the delegate method @delegate with the parameters provided.
3665 * You can pass NULL as the exc argument if you don't want to
3666 * catch exceptions, otherwise, *exc will be set to the exception
3667 * thrown, if any. if an exception is thrown, you can't use the
3668 * MonoObject* result from the function.
3671 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3673 MONO_REQ_GC_UNSAFE_MODE;
3676 MonoClass *klass = delegate->vtable->klass;
3678 im = mono_get_delegate_invoke (klass);
3680 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3682 return mono_runtime_invoke (im, delegate, params, exc);
3685 static char **main_args = NULL;
3686 static int num_main_args = 0;
3689 * mono_runtime_get_main_args:
3691 * Returns: a MonoArray with the arguments passed to the main program
3694 mono_runtime_get_main_args (void)
3696 MONO_REQ_GC_UNSAFE_MODE;
3700 MonoDomain *domain = mono_domain_get ();
3702 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3704 for (i = 0; i < num_main_args; ++i)
3705 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3711 free_main_args (void)
3713 MONO_REQ_GC_NEUTRAL_MODE;
3717 for (i = 0; i < num_main_args; ++i)
3718 g_free (main_args [i]);
3725 * mono_runtime_set_main_args:
3726 * @argc: number of arguments from the command line
3727 * @argv: array of strings from the command line
3729 * Set the command line arguments from an embedding application that doesn't otherwise call
3730 * mono_runtime_run_main ().
3733 mono_runtime_set_main_args (int argc, char* argv[])
3735 MONO_REQ_GC_NEUTRAL_MODE;
3740 main_args = g_new0 (char*, argc);
3741 num_main_args = argc;
3743 for (i = 0; i < argc; ++i) {
3746 utf8_arg = mono_utf8_from_external (argv[i]);
3747 if (utf8_arg == NULL) {
3748 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3749 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3753 main_args [i] = utf8_arg;
3760 * mono_runtime_run_main:
3761 * @method: the method to start the application with (usually Main)
3762 * @argc: number of arguments from the command line
3763 * @argv: array of strings from the command line
3764 * @exc: excetption results
3766 * Execute a standard Main() method (argc/argv contains the
3767 * executable name). This method also sets the command line argument value
3768 * needed by System.Environment.
3773 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3776 MONO_REQ_GC_UNSAFE_MODE;
3779 MonoArray *args = NULL;
3780 MonoDomain *domain = mono_domain_get ();
3781 gchar *utf8_fullpath;
3782 MonoMethodSignature *sig;
3784 g_assert (method != NULL);
3786 mono_thread_set_main (mono_thread_current ());
3788 main_args = g_new0 (char*, argc);
3789 num_main_args = argc;
3791 if (!g_path_is_absolute (argv [0])) {
3792 gchar *basename = g_path_get_basename (argv [0]);
3793 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3797 utf8_fullpath = mono_utf8_from_external (fullpath);
3798 if(utf8_fullpath == NULL) {
3799 /* Printing the arg text will cause glib to
3800 * whinge about "Invalid UTF-8", but at least
3801 * its relevant, and shows the problem text
3804 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3805 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3812 utf8_fullpath = mono_utf8_from_external (argv[0]);
3813 if(utf8_fullpath == NULL) {
3814 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3815 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3820 main_args [0] = utf8_fullpath;
3822 for (i = 1; i < argc; ++i) {
3825 utf8_arg=mono_utf8_from_external (argv[i]);
3826 if(utf8_arg==NULL) {
3827 /* Ditto the comment about Invalid UTF-8 here */
3828 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3829 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3833 main_args [i] = utf8_arg;
3838 sig = mono_method_signature (method);
3840 g_print ("Unable to load Main method.\n");
3844 if (sig->param_count) {
3845 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3846 for (i = 0; i < argc; ++i) {
3847 /* The encodings should all work, given that
3848 * we've checked all these args for the
3851 gchar *str = mono_utf8_from_external (argv [i]);
3852 MonoString *arg = mono_string_new (domain, str);
3853 mono_array_setref (args, i, arg);
3857 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3860 mono_assembly_set_main (method->klass->image->assembly);
3862 return mono_runtime_exec_main (method, args, exc);
3866 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3868 static MonoMethod *serialize_method;
3873 if (!serialize_method) {
3874 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3875 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
3878 if (!serialize_method) {
3883 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
3887 array = mono_runtime_invoke (serialize_method, NULL, params, exc);
3895 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3897 MONO_REQ_GC_UNSAFE_MODE;
3899 static MonoMethod *deserialize_method;
3904 if (!deserialize_method) {
3905 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
3906 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
3908 if (!deserialize_method) {
3915 result = mono_runtime_invoke (deserialize_method, NULL, params, exc);
3922 #ifndef DISABLE_REMOTING
3924 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
3926 MONO_REQ_GC_UNSAFE_MODE;
3928 static MonoMethod *get_proxy_method;
3931 MonoDomain *domain = mono_domain_get ();
3932 MonoRealProxy *real_proxy;
3933 MonoReflectionType *reflection_type;
3934 MonoTransparentProxy *transparent_proxy;
3936 if (!get_proxy_method)
3937 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
3939 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
3941 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
3942 mono_error_raise_exception (&error); /* FIXME don't raise here */
3943 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
3944 mono_error_raise_exception (&error); /* FIXME don't raise here */
3946 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
3947 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
3950 transparent_proxy = (MonoTransparentProxy*) mono_runtime_invoke (get_proxy_method, real_proxy, NULL, exc);
3954 return (MonoObject*) transparent_proxy;
3956 #endif /* DISABLE_REMOTING */
3959 * mono_object_xdomain_representation
3961 * @target_domain: a domain
3962 * @exc: pointer to a MonoObject*
3964 * Creates a representation of obj in the domain target_domain. This
3965 * is either a copy of obj arrived through via serialization and
3966 * deserialization or a proxy, depending on whether the object is
3967 * serializable or marshal by ref. obj must not be in target_domain.
3969 * If the object cannot be represented in target_domain, NULL is
3970 * returned and *exc is set to an appropriate exception.
3973 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
3975 MONO_REQ_GC_UNSAFE_MODE;
3977 MonoObject *deserialized = NULL;
3978 gboolean failure = FALSE;
3982 #ifndef DISABLE_REMOTING
3983 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
3984 deserialized = make_transparent_proxy (obj, &failure, exc);
3989 MonoDomain *domain = mono_domain_get ();
3990 MonoObject *serialized;
3992 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
3993 serialized = serialize_object (obj, &failure, exc);
3994 mono_domain_set_internal_with_options (target_domain, FALSE);
3996 deserialized = deserialize_object (serialized, &failure, exc);
3997 if (domain != target_domain)
3998 mono_domain_set_internal_with_options (domain, FALSE);
4001 return deserialized;
4004 /* Used in call_unhandled_exception_delegate */
4006 create_unhandled_exception_eventargs (MonoObject *exc)
4008 MONO_REQ_GC_UNSAFE_MODE;
4013 MonoMethod *method = NULL;
4014 MonoBoolean is_terminating = TRUE;
4017 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
4020 mono_class_init (klass);
4022 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4023 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4027 args [1] = &is_terminating;
4029 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4030 mono_error_raise_exception (&error); /* FIXME don't raise here */
4031 mono_runtime_invoke (method, obj, args, NULL);
4036 /* Used in mono_unhandled_exception */
4038 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4039 MONO_REQ_GC_UNSAFE_MODE;
4041 MonoObject *e = NULL;
4043 MonoDomain *current_domain = mono_domain_get ();
4045 if (domain != current_domain)
4046 mono_domain_set_internal_with_options (domain, FALSE);
4048 g_assert (domain == mono_object_domain (domain->domain));
4050 if (mono_object_domain (exc) != domain) {
4051 MonoObject *serialization_exc;
4053 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4055 if (serialization_exc) {
4057 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4060 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4061 "System.Runtime.Serialization", "SerializationException",
4062 "Could not serialize unhandled exception.");
4066 g_assert (mono_object_domain (exc) == domain);
4068 pa [0] = domain->domain;
4069 pa [1] = create_unhandled_exception_eventargs (exc);
4070 mono_runtime_delegate_invoke (delegate, pa, &e);
4072 if (domain != current_domain)
4073 mono_domain_set_internal_with_options (current_domain, FALSE);
4077 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4078 if (!mono_error_ok (&error)) {
4079 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4080 mono_error_cleanup (&error);
4082 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4088 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4091 * mono_runtime_unhandled_exception_policy_set:
4092 * @policy: the new policy
4094 * This is a VM internal routine.
4096 * Sets the runtime policy for handling unhandled exceptions.
4099 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4100 runtime_unhandled_exception_policy = policy;
4104 * mono_runtime_unhandled_exception_policy_get:
4106 * This is a VM internal routine.
4108 * Gets the runtime policy for handling unhandled exceptions.
4110 MonoRuntimeUnhandledExceptionPolicy
4111 mono_runtime_unhandled_exception_policy_get (void) {
4112 return runtime_unhandled_exception_policy;
4116 * mono_unhandled_exception:
4117 * @exc: exception thrown
4119 * This is a VM internal routine.
4121 * We call this function when we detect an unhandled exception
4122 * in the default domain.
4124 * It invokes the * UnhandledException event in AppDomain or prints
4125 * a warning to the console
4128 mono_unhandled_exception (MonoObject *exc)
4130 MONO_REQ_GC_UNSAFE_MODE;
4132 MonoClassField *field;
4133 MonoDomain *current_domain, *root_domain;
4134 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4136 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4139 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4142 current_domain = mono_domain_get ();
4143 root_domain = mono_get_root_domain ();
4145 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4146 if (current_domain != root_domain)
4147 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4149 /* set exitcode only if we will abort the process */
4150 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4151 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4152 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4154 mono_environment_exitcode_set (1);
4157 mono_print_unhandled_exception (exc);
4159 if (root_appdomain_delegate)
4160 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4161 if (current_appdomain_delegate)
4162 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4167 * mono_runtime_exec_managed_code:
4168 * @domain: Application domain
4169 * @main_func: function to invoke from the execution thread
4170 * @main_args: parameter to the main_func
4172 * Launch a new thread to execute a function
4174 * main_func is called back from the thread with main_args as the
4175 * parameter. The callback function is expected to start Main()
4176 * eventually. This function then waits for all managed threads to
4178 * It is not necesseray anymore to execute managed code in a subthread,
4179 * so this function should not be used anymore by default: just
4180 * execute the code and then call mono_thread_manage ().
4183 mono_runtime_exec_managed_code (MonoDomain *domain,
4184 MonoMainThreadFunc main_func,
4187 mono_thread_create (domain, main_func, main_args);
4189 mono_thread_manage ();
4193 * Execute a standard Main() method (args doesn't contain the
4197 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4199 MONO_REQ_GC_UNSAFE_MODE;
4204 MonoCustomAttrInfo* cinfo;
4205 gboolean has_stathread_attribute;
4206 MonoInternalThread* thread = mono_thread_internal_current ();
4212 domain = mono_object_domain (args);
4213 if (!domain->entry_assembly) {
4215 MonoAssembly *assembly;
4217 assembly = method->klass->image->assembly;
4218 domain->entry_assembly = assembly;
4219 /* Domains created from another domain already have application_base and configuration_file set */
4220 if (domain->setup->application_base == NULL) {
4221 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4224 if (domain->setup->configuration_file == NULL) {
4225 str = g_strconcat (assembly->image->name, ".config", NULL);
4226 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4228 mono_domain_set_options_from_config (domain);
4232 cinfo = mono_custom_attrs_from_method (method);
4234 static MonoClass *stathread_attribute = NULL;
4235 if (!stathread_attribute)
4236 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4237 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4239 mono_custom_attrs_free (cinfo);
4241 has_stathread_attribute = FALSE;
4243 if (has_stathread_attribute) {
4244 thread->apartment_state = ThreadApartmentState_STA;
4246 thread->apartment_state = ThreadApartmentState_MTA;
4248 mono_thread_init_apartment_state ();
4250 /* FIXME: check signature of method */
4251 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4253 res = mono_runtime_invoke (method, NULL, pa, exc);
4255 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4259 mono_environment_exitcode_set (rval);
4261 mono_runtime_invoke (method, NULL, pa, exc);
4265 /* If the return type of Main is void, only
4266 * set the exitcode if an exception was thrown
4267 * (we don't want to blow away an
4268 * explicitly-set exit code)
4271 mono_environment_exitcode_set (rval);
4279 * mono_runtime_invoke_array:
4280 * @method: method to invoke
4281 * @obJ: object instance
4282 * @params: arguments to the method
4283 * @exc: exception information.
4285 * Invokes the method represented by @method on the object @obj.
4287 * obj is the 'this' pointer, it should be NULL for static
4288 * methods, a MonoObject* for object instances and a pointer to
4289 * the value type for value types.
4291 * The params array contains the arguments to the method with the
4292 * same convention: MonoObject* pointers for object instances and
4293 * pointers to the value type otherwise. The _invoke_array
4294 * variant takes a C# object[] as the params argument (MonoArray
4295 * *params): in this case the value types are boxed inside the
4296 * respective reference representation.
4298 * From unmanaged code you'll usually use the
4299 * mono_runtime_invoke() variant.
4301 * Note that this function doesn't handle virtual methods for
4302 * you, it will exec the exact method you pass: we still need to
4303 * expose a function to lookup the derived class implementation
4304 * of a virtual method (there are examples of this in the code,
4307 * You can pass NULL as the exc argument if you don't want to
4308 * catch exceptions, otherwise, *exc will be set to the exception
4309 * thrown, if any. if an exception is thrown, you can't use the
4310 * MonoObject* result from the function.
4312 * If the method returns a value type, it is boxed in an object
4316 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4319 MONO_REQ_GC_UNSAFE_MODE;
4322 MonoMethodSignature *sig = mono_method_signature (method);
4323 gpointer *pa = NULL;
4326 gboolean has_byref_nullables = FALSE;
4328 if (NULL != params) {
4329 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4330 for (i = 0; i < mono_array_length (params); i++) {
4331 MonoType *t = sig->params [i];
4337 case MONO_TYPE_BOOLEAN:
4340 case MONO_TYPE_CHAR:
4349 case MONO_TYPE_VALUETYPE:
4350 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4351 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4352 pa [i] = mono_array_get (params, MonoObject*, i);
4354 has_byref_nullables = TRUE;
4356 /* MS seems to create the objects if a null is passed in */
4357 if (!mono_array_get (params, MonoObject*, i)) {
4358 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4359 mono_error_raise_exception (&error); /* FIXME don't raise here */
4360 mono_array_setref (params, i, o);
4365 * We can't pass the unboxed vtype byref to the callee, since
4366 * that would mean the callee would be able to modify boxed
4367 * primitive types. So we (and MS) make a copy of the boxed
4368 * object, pass that to the callee, and replace the original
4369 * boxed object in the arg array with the copy.
4371 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4372 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4373 mono_array_setref (params, i, copy);
4376 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4379 case MONO_TYPE_STRING:
4380 case MONO_TYPE_OBJECT:
4381 case MONO_TYPE_CLASS:
4382 case MONO_TYPE_ARRAY:
4383 case MONO_TYPE_SZARRAY:
4385 pa [i] = mono_array_addr (params, MonoObject*, i);
4386 // FIXME: I need to check this code path
4388 pa [i] = mono_array_get (params, MonoObject*, i);
4390 case MONO_TYPE_GENERICINST:
4392 t = &t->data.generic_class->container_class->this_arg;
4394 t = &t->data.generic_class->container_class->byval_arg;
4396 case MONO_TYPE_PTR: {
4399 /* The argument should be an IntPtr */
4400 arg = mono_array_get (params, MonoObject*, i);
4404 g_assert (arg->vtable->klass == mono_defaults.int_class);
4405 pa [i] = ((MonoIntPtr*)arg)->m_value;
4410 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4415 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4418 if (mono_class_is_nullable (method->klass)) {
4419 /* Need to create a boxed vtype instead */
4425 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4429 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4430 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4431 #ifndef DISABLE_REMOTING
4432 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4433 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4436 if (method->klass->valuetype)
4437 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4440 } else if (method->klass->valuetype) {
4441 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4444 mono_runtime_invoke (method, o, pa, exc);
4445 return (MonoObject *)obj;
4447 if (mono_class_is_nullable (method->klass)) {
4448 MonoObject *nullable;
4450 /* Convert the unboxed vtype into a Nullable structure */
4451 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4452 mono_error_raise_exception (&error); /* FIXME don't raise here */
4454 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4455 obj = mono_object_unbox (nullable);
4458 /* obj must be already unboxed if needed */
4459 res = mono_runtime_invoke (method, obj, pa, exc);
4461 if (sig->ret->type == MONO_TYPE_PTR) {
4462 MonoClass *pointer_class;
4463 static MonoMethod *box_method;
4465 MonoObject *box_exc;
4468 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4469 * convert it to a Pointer object.
4471 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4473 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4475 g_assert (res->vtable->klass == mono_defaults.int_class);
4476 box_args [0] = ((MonoIntPtr*)res)->m_value;
4477 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4478 mono_error_raise_exception (&error); /* FIXME don't raise here */
4480 res = mono_runtime_invoke (box_method, NULL, box_args, &box_exc);
4481 g_assert (!box_exc);
4484 if (has_byref_nullables) {
4486 * The runtime invoke wrapper already converted byref nullables back,
4487 * and stored them in pa, we just need to copy them back to the
4490 for (i = 0; i < mono_array_length (params); i++) {
4491 MonoType *t = sig->params [i];
4493 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4494 mono_array_setref (params, i, pa [i]);
4504 * @klass: the class of the object that we want to create
4506 * Returns: a newly created object whose definition is
4507 * looked up using @klass. This will not invoke any constructors,
4508 * so the consumer of this routine has to invoke any constructors on
4509 * its own to initialize the object.
4511 * It returns NULL on failure.
4514 mono_object_new (MonoDomain *domain, MonoClass *klass)
4516 MONO_REQ_GC_UNSAFE_MODE;
4520 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4522 mono_error_raise_exception (&error);
4527 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4529 MONO_REQ_GC_UNSAFE_MODE;
4533 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4535 mono_error_raise_exception (&error);
4540 * mono_object_new_checked:
4541 * @klass: the class of the object that we want to create
4542 * @error: set on error
4544 * Returns: a newly created object whose definition is
4545 * looked up using @klass. This will not invoke any constructors,
4546 * so the consumer of this routine has to invoke any constructors on
4547 * its own to initialize the object.
4549 * It returns NULL on failure and sets @error.
4552 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4554 MONO_REQ_GC_UNSAFE_MODE;
4558 vtable = mono_class_vtable (domain, klass);
4559 g_assert (vtable); /* FIXME don't swallow the error */
4561 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4566 * mono_object_new_pinned:
4568 * Same as mono_object_new, but the returned object will be pinned.
4569 * For SGEN, these objects will only be freed at appdomain unload.
4572 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4574 MONO_REQ_GC_UNSAFE_MODE;
4578 mono_error_init (error);
4580 vtable = mono_class_vtable (domain, klass);
4581 g_assert (vtable); /* FIXME don't swallow the error */
4583 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4585 if (G_UNLIKELY (!o))
4586 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4587 else if (G_UNLIKELY (vtable->klass->has_finalize))
4588 mono_object_register_finalizer (o);
4594 * mono_object_new_specific:
4595 * @vtable: the vtable of the object that we want to create
4597 * Returns: A newly created object with class and domain specified
4601 mono_object_new_specific (MonoVTable *vtable)
4604 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4605 mono_error_raise_exception (&error);
4611 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4613 MONO_REQ_GC_UNSAFE_MODE;
4617 mono_error_init (error);
4619 /* check for is_com_object for COM Interop */
4620 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4623 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4626 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4629 mono_class_init (klass);
4631 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4633 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4636 vtable->domain->create_proxy_for_type_method = im;
4639 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4640 if (!mono_error_ok (error))
4643 o = mono_runtime_invoke (im, NULL, pa, NULL);
4644 if (o != NULL) return o;
4647 return mono_object_new_alloc_specific_checked (vtable, error);
4651 ves_icall_object_new_specific (MonoVTable *vtable)
4654 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4655 mono_error_raise_exception (&error);
4661 mono_object_new_alloc_specific (MonoVTable *vtable)
4664 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4665 mono_error_raise_exception (&error);
4671 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4673 MONO_REQ_GC_UNSAFE_MODE;
4677 mono_error_init (error);
4679 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4681 if (G_UNLIKELY (!o))
4682 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4683 else if (G_UNLIKELY (vtable->klass->has_finalize))
4684 mono_object_register_finalizer (o);
4690 mono_object_new_fast (MonoVTable *vtable)
4693 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4694 mono_error_raise_exception (&error);
4700 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4702 MONO_REQ_GC_UNSAFE_MODE;
4706 mono_error_init (error);
4708 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4710 if (G_UNLIKELY (!o))
4711 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4717 ves_icall_object_new_fast (MonoVTable *vtable)
4720 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4721 mono_error_raise_exception (&error);
4727 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4729 MONO_REQ_GC_UNSAFE_MODE;
4733 mono_error_init (error);
4735 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4737 if (G_UNLIKELY (!o))
4738 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4739 else if (G_UNLIKELY (vtable->klass->has_finalize))
4740 mono_object_register_finalizer (o);
4746 * mono_class_get_allocation_ftn:
4748 * @for_box: the object will be used for boxing
4749 * @pass_size_in_words:
4751 * Return the allocation function appropriate for the given class.
4755 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4757 MONO_REQ_GC_NEUTRAL_MODE;
4759 *pass_size_in_words = FALSE;
4761 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4762 return ves_icall_object_new_specific;
4764 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4766 return ves_icall_object_new_fast;
4769 * FIXME: This is actually slower than ves_icall_object_new_fast, because
4770 * of the overhead of parameter passing.
4773 *pass_size_in_words = TRUE;
4774 #ifdef GC_REDIRECT_TO_LOCAL
4775 return GC_local_gcj_fast_malloc;
4777 return GC_gcj_fast_malloc;
4782 return ves_icall_object_new_specific;
4786 * mono_object_new_from_token:
4787 * @image: Context where the type_token is hosted
4788 * @token: a token of the type that we want to create
4790 * Returns: A newly created object whose definition is
4791 * looked up using @token in the @image image
4794 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4796 MONO_REQ_GC_UNSAFE_MODE;
4802 klass = mono_class_get_checked (image, token, &error);
4803 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4805 result = mono_object_new_checked (domain, klass, &error);
4807 mono_error_raise_exception (&error); /* FIXME don't raise here */
4814 * mono_object_clone:
4815 * @obj: the object to clone
4817 * Returns: A newly created object who is a shallow copy of @obj
4820 mono_object_clone (MonoObject *obj)
4823 MonoObject *o = mono_object_clone_checked (obj, &error);
4824 mono_error_raise_exception (&error);
4830 mono_object_clone_checked (MonoObject *obj, MonoError *error)
4832 MONO_REQ_GC_UNSAFE_MODE;
4837 mono_error_init (error);
4839 size = obj->vtable->klass->instance_size;
4841 if (obj->vtable->klass->rank)
4842 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
4844 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
4846 if (G_UNLIKELY (!o)) {
4847 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
4851 /* If the object doesn't contain references this will do a simple memmove. */
4852 mono_gc_wbarrier_object_copy (o, obj);
4854 if (obj->vtable->klass->has_finalize)
4855 mono_object_register_finalizer (o);
4860 * mono_array_full_copy:
4861 * @src: source array to copy
4862 * @dest: destination array
4864 * Copies the content of one array to another with exactly the same type and size.
4867 mono_array_full_copy (MonoArray *src, MonoArray *dest)
4869 MONO_REQ_GC_UNSAFE_MODE;
4872 MonoClass *klass = src->obj.vtable->klass;
4874 g_assert (klass == dest->obj.vtable->klass);
4876 size = mono_array_length (src);
4877 g_assert (size == mono_array_length (dest));
4878 size *= mono_array_element_size (klass);
4880 if (klass->element_class->valuetype) {
4881 if (klass->element_class->has_references)
4882 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
4884 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4886 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
4889 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
4894 * mono_array_clone_in_domain:
4895 * @domain: the domain in which the array will be cloned into
4896 * @array: the array to clone
4898 * This routine returns a copy of the array that is hosted on the
4899 * specified MonoDomain.
4902 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
4904 MONO_REQ_GC_UNSAFE_MODE;
4910 MonoClass *klass = array->obj.vtable->klass;
4912 if (array->bounds == NULL) {
4913 size = mono_array_length (array);
4914 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
4915 mono_error_raise_exception (&error); /* FIXME don't raise here */
4917 size *= mono_array_element_size (klass);
4919 if (klass->element_class->valuetype) {
4920 if (klass->element_class->has_references)
4921 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4923 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4925 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4928 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4933 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
4934 size = mono_array_element_size (klass);
4935 for (i = 0; i < klass->rank; ++i) {
4936 sizes [i] = array->bounds [i].length;
4937 size *= array->bounds [i].length;
4938 sizes [i + klass->rank] = array->bounds [i].lower_bound;
4940 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
4941 mono_error_raise_exception (&error); /* FIXME don't raise here */
4943 if (klass->element_class->valuetype) {
4944 if (klass->element_class->has_references)
4945 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
4947 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4949 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
4952 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
4960 * @array: the array to clone
4962 * Returns: A newly created array who is a shallow copy of @array
4965 mono_array_clone (MonoArray *array)
4967 MONO_REQ_GC_UNSAFE_MODE;
4969 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
4972 /* helper macros to check for overflow when calculating the size of arrays */
4973 #ifdef MONO_BIG_ARRAYS
4974 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
4975 #define MYGUINT_MAX MYGUINT64_MAX
4976 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4977 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
4978 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4979 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
4980 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
4982 #define MYGUINT32_MAX 4294967295U
4983 #define MYGUINT_MAX MYGUINT32_MAX
4984 #define CHECK_ADD_OVERFLOW_UN(a,b) \
4985 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
4986 #define CHECK_MUL_OVERFLOW_UN(a,b) \
4987 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
4988 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
4992 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
4994 MONO_REQ_GC_NEUTRAL_MODE;
4998 byte_len = mono_array_element_size (klass);
4999 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5002 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5004 byte_len += MONO_SIZEOF_MONO_ARRAY;
5012 * mono_array_new_full:
5013 * @domain: domain where the object is created
5014 * @array_class: array class
5015 * @lengths: lengths for each dimension in the array
5016 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5018 * This routine creates a new array objects with the given dimensions,
5019 * lower bounds and type.
5022 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5025 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5026 mono_error_raise_exception (&error);
5032 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5034 MONO_REQ_GC_UNSAFE_MODE;
5036 uintptr_t byte_len = 0, len, bounds_size;
5039 MonoArrayBounds *bounds;
5043 mono_error_init (error);
5045 if (!array_class->inited)
5046 mono_class_init (array_class);
5050 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5051 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5053 if (len > MONO_ARRAY_MAX_INDEX) {
5054 mono_error_set_generic_error (error, "System", "OverflowException", "");
5059 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5061 for (i = 0; i < array_class->rank; ++i) {
5062 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5063 mono_error_set_generic_error (error, "System", "OverflowException", "");
5066 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5067 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5074 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5075 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5081 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5082 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5085 byte_len = (byte_len + 3) & ~3;
5086 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5087 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5090 byte_len += bounds_size;
5093 * Following three lines almost taken from mono_object_new ():
5094 * they need to be kept in sync.
5096 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5098 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5100 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5102 if (G_UNLIKELY (!o)) {
5103 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5107 array = (MonoArray*)o;
5109 bounds = array->bounds;
5112 for (i = 0; i < array_class->rank; ++i) {
5113 bounds [i].length = lengths [i];
5115 bounds [i].lower_bound = lower_bounds [i];
5124 * @domain: domain where the object is created
5125 * @eclass: element class
5126 * @n: number of array elements
5128 * This routine creates a new szarray with @n elements of type @eclass.
5131 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5133 MONO_REQ_GC_UNSAFE_MODE;
5139 ac = mono_array_class_get (eclass, 1);
5142 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5143 mono_error_raise_exception (&error); /* FIXME don't raise here */
5149 * mono_array_new_specific:
5150 * @vtable: a vtable in the appropriate domain for an initialized class
5151 * @n: number of array elements
5153 * This routine is a fast alternative to mono_array_new() for code which
5154 * can be sure about the domain it operates in.
5157 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5160 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5161 mono_error_raise_exception (&error); /* FIXME don't raise here */
5167 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5169 MONO_REQ_GC_UNSAFE_MODE;
5174 mono_error_init (error);
5176 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5177 mono_error_set_generic_error (error, "System", "OverflowException", "");
5181 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5182 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5185 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5187 if (G_UNLIKELY (!o)) {
5188 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5192 return (MonoArray*)o;
5196 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5199 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5200 mono_error_raise_exception (&error);
5206 * mono_string_new_utf16:
5207 * @text: a pointer to an utf16 string
5208 * @len: the length of the string
5210 * Returns: A newly created string object which contains @text.
5213 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5215 MONO_REQ_GC_UNSAFE_MODE;
5218 MonoString *res = NULL;
5219 res = mono_string_new_utf16_checked (domain, text, len, &error);
5220 mono_error_raise_exception (&error);
5226 * mono_string_new_utf16_checked:
5227 * @text: a pointer to an utf16 string
5228 * @len: the length of the string
5229 * @error: written on error.
5231 * Returns: A newly created string object which contains @text.
5232 * On error, returns NULL and sets @error.
5235 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5237 MONO_REQ_GC_UNSAFE_MODE;
5241 mono_error_init (error);
5243 s = mono_string_new_size_checked (domain, len, error);
5245 memcpy (mono_string_chars (s), text, len * 2);
5251 * mono_string_new_utf32:
5252 * @text: a pointer to an utf32 string
5253 * @len: the length of the string
5255 * Returns: A newly created string object which contains @text.
5258 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5260 MONO_REQ_GC_UNSAFE_MODE;
5264 mono_unichar2 *utf16_output = NULL;
5265 gint32 utf16_len = 0;
5266 GError *gerror = NULL;
5267 glong items_written;
5269 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5272 g_error_free (gerror);
5274 while (utf16_output [utf16_len]) utf16_len++;
5276 s = mono_string_new_size_checked (domain, utf16_len, &error);
5277 mono_error_raise_exception (&error); /* FIXME don't raise here */
5279 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5281 g_free (utf16_output);
5287 * mono_string_new_size:
5288 * @text: a pointer to an utf16 string
5289 * @len: the length of the string
5291 * Returns: A newly created string object of @len
5294 mono_string_new_size (MonoDomain *domain, gint32 len)
5297 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5298 mono_error_raise_exception (&error);
5304 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5306 MONO_REQ_GC_UNSAFE_MODE;
5312 mono_error_init (error);
5314 /* check for overflow */
5315 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5316 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5320 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5321 g_assert (size > 0);
5323 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5326 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5328 if (G_UNLIKELY (!s)) {
5329 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5337 * mono_string_new_len:
5338 * @text: a pointer to an utf8 string
5339 * @length: number of bytes in @text to consider
5341 * Returns: A newly created string object which contains @text.
5344 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5346 MONO_REQ_GC_UNSAFE_MODE;
5349 GError *eg_error = NULL;
5350 MonoString *o = NULL;
5352 glong items_written;
5354 mono_error_init (&error);
5356 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5359 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5361 g_error_free (eg_error);
5365 mono_error_raise_exception (&error); /* FIXME don't raise here */
5371 * @text: a pointer to an utf8 string
5373 * Returns: A newly created string object which contains @text.
5375 * This function asserts if it cannot allocate a new string.
5377 * @deprecated Use mono_string_new_checked in new code.
5380 mono_string_new (MonoDomain *domain, const char *text)
5383 MonoString *res = NULL;
5384 res = mono_string_new_checked (domain, text, &error);
5385 mono_error_assert_ok (&error);
5390 * mono_string_new_checked:
5391 * @text: a pointer to an utf8 string
5392 * @merror: set on error
5394 * Returns: A newly created string object which contains @text.
5395 * On error returns NULL and sets @merror.
5398 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5400 MONO_REQ_GC_UNSAFE_MODE;
5402 GError *eg_error = NULL;
5403 MonoString *o = NULL;
5405 glong items_written;
5408 mono_error_init (error);
5412 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5415 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5417 g_error_free (eg_error);
5420 mono_error_raise_exception (error);
5422 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5427 MonoString *o = NULL;
5429 if (!g_utf8_validate (text, -1, &end)) {
5430 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5434 len = g_utf8_strlen (text, -1);
5435 o = mono_string_new_size_checked (domain, len, error);
5438 str = mono_string_chars (o);
5440 while (text < end) {
5441 *str++ = g_utf8_get_char (text);
5442 text = g_utf8_next_char (text);
5451 * mono_string_new_wrapper:
5452 * @text: pointer to utf8 characters.
5454 * Helper function to create a string object from @text in the current domain.
5457 mono_string_new_wrapper (const char *text)
5459 MONO_REQ_GC_UNSAFE_MODE;
5461 MonoDomain *domain = mono_domain_get ();
5464 return mono_string_new (domain, text);
5471 * @class: the class of the value
5472 * @value: a pointer to the unboxed data
5474 * Returns: A newly created object which contains @value.
5477 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5479 MONO_REQ_GC_UNSAFE_MODE;
5486 g_assert (klass->valuetype);
5487 if (mono_class_is_nullable (klass))
5488 return mono_nullable_box ((guint8 *)value, klass);
5490 vtable = mono_class_vtable (domain, klass);
5493 size = mono_class_instance_size (klass);
5494 res = mono_object_new_alloc_specific_checked (vtable, &error);
5495 mono_error_raise_exception (&error); /* FIXME don't raise here */
5497 size = size - sizeof (MonoObject);
5500 g_assert (size == mono_class_value_size (klass, NULL));
5501 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5503 #if NO_UNALIGNED_ACCESS
5504 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5508 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5511 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5514 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5517 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5520 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5524 if (klass->has_finalize)
5525 mono_object_register_finalizer (res);
5531 * @dest: destination pointer
5532 * @src: source pointer
5533 * @klass: a valuetype class
5535 * Copy a valuetype from @src to @dest. This function must be used
5536 * when @klass contains references fields.
5539 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5541 MONO_REQ_GC_UNSAFE_MODE;
5543 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5547 * mono_value_copy_array:
5548 * @dest: destination array
5549 * @dest_idx: index in the @dest array
5550 * @src: source pointer
5551 * @count: number of items
5553 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5554 * This function must be used when @klass contains references fields.
5555 * Overlap is handled.
5558 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5560 MONO_REQ_GC_UNSAFE_MODE;
5562 int size = mono_array_element_size (dest->obj.vtable->klass);
5563 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5564 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5565 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5569 * mono_object_get_domain:
5570 * @obj: object to query
5572 * Returns: the MonoDomain where the object is hosted
5575 mono_object_get_domain (MonoObject *obj)
5577 MONO_REQ_GC_UNSAFE_MODE;
5579 return mono_object_domain (obj);
5583 * mono_object_get_class:
5584 * @obj: object to query
5586 * Returns: the MonOClass of the object.
5589 mono_object_get_class (MonoObject *obj)
5591 MONO_REQ_GC_UNSAFE_MODE;
5593 return mono_object_class (obj);
5596 * mono_object_get_size:
5597 * @o: object to query
5599 * Returns: the size, in bytes, of @o
5602 mono_object_get_size (MonoObject* o)
5604 MONO_REQ_GC_UNSAFE_MODE;
5606 MonoClass* klass = mono_object_class (o);
5607 if (klass == mono_defaults.string_class) {
5608 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5609 } else if (o->vtable->rank) {
5610 MonoArray *array = (MonoArray*)o;
5611 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5612 if (array->bounds) {
5615 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5619 return mono_class_instance_size (klass);
5624 * mono_object_unbox:
5625 * @obj: object to unbox
5627 * Returns: a pointer to the start of the valuetype boxed in this
5630 * This method will assert if the object passed is not a valuetype.
5633 mono_object_unbox (MonoObject *obj)
5635 MONO_REQ_GC_UNSAFE_MODE;
5637 /* add assert for valuetypes? */
5638 g_assert (obj->vtable->klass->valuetype);
5639 return ((char*)obj) + sizeof (MonoObject);
5643 * mono_object_isinst:
5645 * @klass: a pointer to a class
5647 * Returns: @obj if @obj is derived from @klass
5650 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5652 MONO_REQ_GC_UNSAFE_MODE;
5655 mono_class_init (klass);
5657 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5658 return mono_object_isinst_mbyref (obj, klass);
5663 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5667 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5669 MONO_REQ_GC_UNSAFE_MODE;
5679 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5680 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5684 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5685 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5688 MonoClass *oklass = vt->klass;
5689 if (mono_class_is_transparent_proxy (oklass))
5690 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5692 mono_class_setup_supertypes (klass);
5693 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5696 #ifndef DISABLE_REMOTING
5697 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5699 MonoDomain *domain = mono_domain_get ();
5701 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5702 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5703 MonoMethod *im = NULL;
5706 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5708 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5709 im = mono_object_get_virtual_method (rp, im);
5712 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5713 mono_error_raise_exception (&error); /* FIXME don't raise here */
5716 res = mono_runtime_invoke (im, rp, pa, NULL);
5718 if (*(MonoBoolean *) mono_object_unbox(res)) {
5719 /* Update the vtable of the remote type, so it can safely cast to this new type */
5720 mono_upgrade_remote_class (domain, obj, klass);
5724 #endif /* DISABLE_REMOTING */
5729 * mono_object_castclass_mbyref:
5731 * @klass: a pointer to a class
5733 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5736 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5738 MONO_REQ_GC_UNSAFE_MODE;
5740 if (!obj) return NULL;
5741 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5743 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5745 "InvalidCastException"));
5750 MonoDomain *orig_domain;
5756 str_lookup (MonoDomain *domain, gpointer user_data)
5758 MONO_REQ_GC_UNSAFE_MODE;
5760 LDStrInfo *info = (LDStrInfo *)user_data;
5761 if (info->res || domain == info->orig_domain)
5763 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5767 mono_string_get_pinned (MonoString *str, MonoError *error)
5769 MONO_REQ_GC_UNSAFE_MODE;
5771 mono_error_init (error);
5773 /* We only need to make a pinned version of a string if this is a moving GC */
5774 if (!mono_gc_is_moving ())
5778 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5779 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5781 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5782 news->length = mono_string_length (str);
5784 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5790 mono_string_is_interned_lookup (MonoString *str, int insert)
5792 MONO_REQ_GC_UNSAFE_MODE;
5795 MonoGHashTable *ldstr_table;
5796 MonoString *s, *res;
5799 domain = ((MonoObject *)str)->vtable->domain;
5800 ldstr_table = domain->ldstr_table;
5802 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5808 /* Allocate outside the lock */
5810 s = mono_string_get_pinned (str, &error);
5811 mono_error_raise_exception (&error); /* FIXME don't raise here */
5814 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5819 mono_g_hash_table_insert (ldstr_table, s, s);
5824 LDStrInfo ldstr_info;
5825 ldstr_info.orig_domain = domain;
5826 ldstr_info.ins = str;
5827 ldstr_info.res = NULL;
5829 mono_domain_foreach (str_lookup, &ldstr_info);
5830 if (ldstr_info.res) {
5832 * the string was already interned in some other domain:
5833 * intern it in the current one as well.
5835 mono_g_hash_table_insert (ldstr_table, str, str);
5845 * mono_string_is_interned:
5846 * @o: String to probe
5848 * Returns whether the string has been interned.
5851 mono_string_is_interned (MonoString *o)
5853 MONO_REQ_GC_UNSAFE_MODE;
5855 return mono_string_is_interned_lookup (o, FALSE);
5859 * mono_string_intern:
5860 * @o: String to intern
5862 * Interns the string passed.
5863 * Returns: The interned string.
5866 mono_string_intern (MonoString *str)
5868 MONO_REQ_GC_UNSAFE_MODE;
5870 return mono_string_is_interned_lookup (str, TRUE);
5875 * @domain: the domain where the string will be used.
5876 * @image: a metadata context
5877 * @idx: index into the user string table.
5879 * Implementation for the ldstr opcode.
5880 * Returns: a loaded string from the @image/@idx combination.
5883 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5885 MONO_REQ_GC_UNSAFE_MODE;
5887 if (image->dynamic) {
5888 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5891 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5892 return NULL; /*FIXME we should probably be raising an exception here*/
5893 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5898 * mono_ldstr_metadata_sig
5899 * @domain: the domain for the string
5900 * @sig: the signature of a metadata string
5902 * Returns: a MonoString for a string stored in the metadata
5905 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5907 MONO_REQ_GC_UNSAFE_MODE;
5910 const char *str = sig;
5911 MonoString *o, *interned;
5914 len2 = mono_metadata_decode_blob_size (str, &str);
5917 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
5918 mono_error_raise_exception (&error); /* FIXME don't raise here */
5919 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5922 guint16 *p2 = (guint16*)mono_string_chars (o);
5923 for (i = 0; i < len2; ++i) {
5924 *p2 = GUINT16_FROM_LE (*p2);
5930 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5933 return interned; /* o will get garbage collected */
5935 o = mono_string_get_pinned (o, &error);
5936 mono_error_raise_exception (&error); /* FIXME don't raise here */
5939 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5941 mono_g_hash_table_insert (domain->ldstr_table, o, o);
5951 * mono_string_to_utf8:
5952 * @s: a System.String
5954 * Returns the UTF8 representation for @s.
5955 * The resulting buffer needs to be freed with mono_free().
5957 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5960 mono_string_to_utf8 (MonoString *s)
5962 MONO_REQ_GC_UNSAFE_MODE;
5965 char *result = mono_string_to_utf8_checked (s, &error);
5967 if (!mono_error_ok (&error))
5968 mono_error_raise_exception (&error);
5973 * mono_string_to_utf8_checked:
5974 * @s: a System.String
5975 * @error: a MonoError.
5977 * Converts a MonoString to its UTF8 representation. May fail; check
5978 * @error to determine whether the conversion was successful.
5979 * The resulting buffer should be freed with mono_free().
5982 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5984 MONO_REQ_GC_UNSAFE_MODE;
5988 GError *gerror = NULL;
5990 mono_error_init (error);
5996 return g_strdup ("");
5998 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6000 mono_error_set_argument (error, "string", "%s", gerror->message);
6001 g_error_free (gerror);
6004 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6005 if (s->length > written) {
6006 /* allocate the total length and copy the part of the string that has been converted */
6007 char *as2 = (char *)g_malloc0 (s->length);
6008 memcpy (as2, as, written);
6017 * mono_string_to_utf8_ignore:
6020 * Converts a MonoString to its UTF8 representation. Will ignore
6021 * invalid surrogate pairs.
6022 * The resulting buffer should be freed with mono_free().
6026 mono_string_to_utf8_ignore (MonoString *s)
6028 MONO_REQ_GC_UNSAFE_MODE;
6037 return g_strdup ("");
6039 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6041 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6042 if (s->length > written) {
6043 /* allocate the total length and copy the part of the string that has been converted */
6044 char *as2 = (char *)g_malloc0 (s->length);
6045 memcpy (as2, as, written);
6054 * mono_string_to_utf8_image_ignore:
6055 * @s: a System.String
6057 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6060 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6062 MONO_REQ_GC_UNSAFE_MODE;
6064 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6068 * mono_string_to_utf8_mp_ignore:
6069 * @s: a System.String
6071 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6074 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6076 MONO_REQ_GC_UNSAFE_MODE;
6078 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6083 * mono_string_to_utf16:
6086 * Return an null-terminated array of the utf-16 chars
6087 * contained in @s. The result must be freed with g_free().
6088 * This is a temporary helper until our string implementation
6089 * is reworked to always include the null terminating char.
6092 mono_string_to_utf16 (MonoString *s)
6094 MONO_REQ_GC_UNSAFE_MODE;
6101 as = (char *)g_malloc ((s->length * 2) + 2);
6102 as [(s->length * 2)] = '\0';
6103 as [(s->length * 2) + 1] = '\0';
6106 return (gunichar2 *)(as);
6109 memcpy (as, mono_string_chars(s), s->length * 2);
6110 return (gunichar2 *)(as);
6114 * mono_string_to_utf32:
6117 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6118 * contained in @s. The result must be freed with g_free().
6121 mono_string_to_utf32 (MonoString *s)
6123 MONO_REQ_GC_UNSAFE_MODE;
6125 mono_unichar4 *utf32_output = NULL;
6126 GError *error = NULL;
6127 glong items_written;
6132 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6135 g_error_free (error);
6137 return utf32_output;
6141 * mono_string_from_utf16:
6142 * @data: the UTF16 string (LPWSTR) to convert
6144 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6146 * Returns: a MonoString.
6149 mono_string_from_utf16 (gunichar2 *data)
6151 MONO_REQ_GC_UNSAFE_MODE;
6154 MonoString *res = NULL;
6155 MonoDomain *domain = mono_domain_get ();
6161 while (data [len]) len++;
6163 res = mono_string_new_utf16_checked (domain, data, len, &error);
6164 mono_error_raise_exception (&error); /* FIXME don't raise here */
6169 * mono_string_from_utf32:
6170 * @data: the UTF32 string (LPWSTR) to convert
6172 * Converts a UTF32 (UCS-4)to a MonoString.
6174 * Returns: a MonoString.
6177 mono_string_from_utf32 (mono_unichar4 *data)
6179 MONO_REQ_GC_UNSAFE_MODE;
6181 MonoString* result = NULL;
6182 mono_unichar2 *utf16_output = NULL;
6183 GError *error = NULL;
6184 glong items_written;
6190 while (data [len]) len++;
6192 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6195 g_error_free (error);
6197 result = mono_string_from_utf16 (utf16_output);
6198 g_free (utf16_output);
6203 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6205 MONO_REQ_GC_UNSAFE_MODE;
6212 r = mono_string_to_utf8_ignore (s);
6214 r = mono_string_to_utf8_checked (s, error);
6215 if (!mono_error_ok (error))
6222 len = strlen (r) + 1;
6224 mp_s = (char *)mono_mempool_alloc (mp, len);
6226 mp_s = (char *)mono_image_alloc (image, len);
6228 memcpy (mp_s, r, len);
6236 * mono_string_to_utf8_image:
6237 * @s: a System.String
6239 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6242 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6244 MONO_REQ_GC_UNSAFE_MODE;
6246 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6250 * mono_string_to_utf8_mp:
6251 * @s: a System.String
6253 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6256 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6258 MONO_REQ_GC_UNSAFE_MODE;
6260 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6264 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6267 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6269 eh_callbacks = *cbs;
6272 MonoRuntimeExceptionHandlingCallbacks *
6273 mono_get_eh_callbacks (void)
6275 return &eh_callbacks;
6279 * mono_raise_exception:
6280 * @ex: exception object
6282 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6285 mono_raise_exception (MonoException *ex)
6287 MONO_REQ_GC_UNSAFE_MODE;
6290 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6291 * that will cause gcc to omit the function epilog, causing problems when
6292 * the JIT tries to walk the stack, since the return address on the stack
6293 * will point into the next function in the executable, not this one.
6295 eh_callbacks.mono_raise_exception (ex);
6299 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6301 MONO_REQ_GC_UNSAFE_MODE;
6303 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6307 * mono_wait_handle_new:
6308 * @domain: Domain where the object will be created
6309 * @handle: Handle for the wait handle
6311 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6314 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6316 MONO_REQ_GC_UNSAFE_MODE;
6319 MonoWaitHandle *res;
6320 gpointer params [1];
6321 static MonoMethod *handle_set;
6323 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6324 mono_error_raise_exception (&error); /* FIXME don't raise here */
6326 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6328 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6330 params [0] = &handle;
6331 mono_runtime_invoke (handle_set, res, params, NULL);
6337 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6339 MONO_REQ_GC_UNSAFE_MODE;
6341 static MonoClassField *f_os_handle;
6342 static MonoClassField *f_safe_handle;
6344 if (!f_os_handle && !f_safe_handle) {
6345 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6346 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6351 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6355 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6362 mono_runtime_capture_context (MonoDomain *domain)
6364 MONO_REQ_GC_UNSAFE_MODE;
6366 RuntimeInvokeFunction runtime_invoke;
6368 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6369 MonoMethod *method = mono_get_context_capture_method ();
6370 MonoMethod *wrapper;
6373 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6374 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6375 domain->capture_context_method = mono_compile_method (method);
6378 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6380 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6383 * mono_async_result_new:
6384 * @domain:domain where the object will be created.
6385 * @handle: wait handle.
6386 * @state: state to pass to AsyncResult
6387 * @data: C closure data.
6389 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6390 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6394 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6396 MONO_REQ_GC_UNSAFE_MODE;
6399 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6400 mono_error_raise_exception (&error); /* FIXME don't raise here */
6401 MonoObject *context = mono_runtime_capture_context (domain);
6402 /* we must capture the execution context from the original thread */
6404 MONO_OBJECT_SETREF (res, execution_context, context);
6405 /* note: result may be null if the flow is suppressed */
6408 res->data = (void **)data;
6409 MONO_OBJECT_SETREF (res, object_data, object_data);
6410 MONO_OBJECT_SETREF (res, async_state, state);
6412 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6414 res->sync_completed = FALSE;
6415 res->completed = FALSE;
6421 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6423 MONO_REQ_GC_UNSAFE_MODE;
6429 g_assert (ares->async_delegate);
6431 ac = (MonoAsyncCall*) ares->object_data;
6433 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6435 gpointer wait_event = NULL;
6437 ac->msg->exc = NULL;
6438 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6439 MONO_OBJECT_SETREF (ac, res, res);
6441 mono_monitor_enter ((MonoObject*) ares);
6442 ares->completed = 1;
6444 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6445 mono_monitor_exit ((MonoObject*) ares);
6447 if (wait_event != NULL)
6448 SetEvent (wait_event);
6450 if (ac->cb_method) {
6451 /* we swallow the excepton as it is the behavior on .NET */
6452 MonoObject *exc = NULL;
6453 mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6455 mono_unhandled_exception (exc);
6463 mono_message_init (MonoDomain *domain,
6464 MonoMethodMessage *this_obj,
6465 MonoReflectionMethod *method,
6466 MonoArray *out_args)
6468 MONO_REQ_GC_UNSAFE_MODE;
6470 static MonoClass *object_array_klass;
6471 static MonoClass *byte_array_klass;
6472 static MonoClass *string_array_klass;
6474 MonoMethodSignature *sig = mono_method_signature (method->method);
6481 if (!object_array_klass) {
6484 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6486 byte_array_klass = klass;
6488 klass = mono_array_class_get (mono_defaults.string_class, 1);
6490 string_array_klass = klass;
6492 klass = mono_array_class_get (mono_defaults.object_class, 1);
6495 mono_atomic_store_release (&object_array_klass, klass);
6498 MONO_OBJECT_SETREF (this_obj, method, method);
6500 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6501 mono_error_raise_exception (&error); /* FIXME don't raise here */
6503 MONO_OBJECT_SETREF (this_obj, args, arr);
6505 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6506 mono_error_raise_exception (&error); /* FIXME don't raise here */
6508 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6510 this_obj->async_result = NULL;
6511 this_obj->call_type = CallType_Sync;
6513 names = g_new (char *, sig->param_count);
6514 mono_method_get_param_names (method->method, (const char **) names);
6516 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6517 mono_error_raise_exception (&error); /* FIXME don't raise here */
6519 MONO_OBJECT_SETREF (this_obj, names, arr);
6521 for (i = 0; i < sig->param_count; i++) {
6522 name = mono_string_new (domain, names [i]);
6523 mono_array_setref (this_obj->names, i, name);
6527 for (i = 0, j = 0; i < sig->param_count; i++) {
6528 if (sig->params [i]->byref) {
6530 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6531 mono_array_setref (this_obj->args, i, arg);
6535 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6539 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6542 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6546 #ifndef DISABLE_REMOTING
6548 * mono_remoting_invoke:
6549 * @real_proxy: pointer to a RealProxy object
6550 * @msg: The MonoMethodMessage to execute
6551 * @exc: used to store exceptions
6552 * @out_args: used to store output arguments
6554 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6555 * IMessage interface and it is not trivial to extract results from there. So
6556 * we call an helper method PrivateInvoke instead of calling
6557 * RealProxy::Invoke() directly.
6559 * Returns: the result object.
6562 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6563 MonoObject **exc, MonoArray **out_args)
6565 MONO_REQ_GC_UNSAFE_MODE;
6567 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6570 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6573 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6575 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6576 real_proxy->vtable->domain->private_invoke_method = im;
6579 pa [0] = real_proxy;
6584 return mono_runtime_invoke (im, NULL, pa, exc);
6589 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6590 MonoObject **exc, MonoArray **out_args)
6592 MONO_REQ_GC_UNSAFE_MODE;
6594 static MonoClass *object_array_klass;
6598 MonoMethodSignature *sig;
6601 int i, j, outarg_count = 0;
6603 #ifndef DISABLE_REMOTING
6604 if (target && mono_object_is_transparent_proxy (target)) {
6605 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6606 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6607 target = tp->rp->unwrapped_server;
6609 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6614 domain = mono_domain_get ();
6615 method = msg->method->method;
6616 sig = mono_method_signature (method);
6618 for (i = 0; i < sig->param_count; i++) {
6619 if (sig->params [i]->byref)
6623 if (!object_array_klass) {
6626 klass = mono_array_class_get (mono_defaults.object_class, 1);
6629 mono_memory_barrier ();
6630 object_array_klass = klass;
6633 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6634 mono_error_raise_exception (&error); /* FIXME don't raise here */
6636 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6639 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6641 for (i = 0, j = 0; i < sig->param_count; i++) {
6642 if (sig->params [i]->byref) {
6644 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6645 mono_array_setref (*out_args, j, arg);
6654 * mono_object_to_string:
6656 * @exc: Any exception thrown by ToString (). May be NULL.
6658 * Returns: the result of calling ToString () on an object.
6661 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6663 MONO_REQ_GC_UNSAFE_MODE;
6665 static MonoMethod *to_string = NULL;
6672 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6674 method = mono_object_get_virtual_method (obj, to_string);
6676 // Unbox value type if needed
6677 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6678 target = mono_object_unbox (obj);
6681 return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6685 * mono_print_unhandled_exception:
6686 * @exc: The exception
6688 * Prints the unhandled exception.
6691 mono_print_unhandled_exception (MonoObject *exc)
6693 MONO_REQ_GC_UNSAFE_MODE;
6696 char *message = (char*)"";
6697 gboolean free_message = FALSE;
6700 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6701 message = g_strdup ("OutOfMemoryException");
6702 free_message = TRUE;
6703 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6704 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6705 free_message = TRUE;
6708 if (((MonoException*)exc)->native_trace_ips) {
6709 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6710 free_message = TRUE;
6712 MonoObject *other_exc = NULL;
6713 str = mono_object_to_string (exc, &other_exc);
6715 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6716 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6718 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6719 original_backtrace, nested_backtrace);
6721 g_free (original_backtrace);
6722 g_free (nested_backtrace);
6723 free_message = TRUE;
6725 message = mono_string_to_utf8_checked (str, &error);
6726 if (!mono_error_ok (&error)) {
6727 mono_error_cleanup (&error);
6728 message = (char *) "";
6730 free_message = TRUE;
6737 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6738 * exc->vtable->klass->name, message);
6740 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6747 * mono_delegate_ctor:
6748 * @this: pointer to an uninitialized delegate object
6749 * @target: target object
6750 * @addr: pointer to native code
6753 * Initialize a delegate and sets a specific method, not the one
6754 * associated with addr. This is useful when sharing generic code.
6755 * In that case addr will most probably not be associated with the
6756 * correct instantiation of the method.
6759 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6761 MONO_REQ_GC_UNSAFE_MODE;
6763 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6765 g_assert (this_obj);
6768 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6771 delegate->method = method;
6773 mono_stats.delegate_creations++;
6775 #ifndef DISABLE_REMOTING
6776 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6778 method = mono_marshal_get_remoting_invoke (method);
6779 delegate->method_ptr = mono_compile_method (method);
6780 MONO_OBJECT_SETREF (delegate, target, target);
6784 delegate->method_ptr = addr;
6785 MONO_OBJECT_SETREF (delegate, target, target);
6788 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6789 if (callbacks.init_delegate)
6790 callbacks.init_delegate (delegate);
6794 * mono_delegate_ctor:
6795 * @this: pointer to an uninitialized delegate object
6796 * @target: target object
6797 * @addr: pointer to native code
6799 * This is used to initialize a delegate.
6802 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6804 MONO_REQ_GC_UNSAFE_MODE;
6806 MonoDomain *domain = mono_domain_get ();
6808 MonoMethod *method = NULL;
6812 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6814 if (!ji && domain != mono_get_root_domain ())
6815 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6817 method = mono_jit_info_get_method (ji);
6818 g_assert (!method->klass->generic_container);
6821 mono_delegate_ctor_with_method (this_obj, target, addr, method);
6825 * mono_method_call_message_new:
6826 * @method: method to encapsulate
6827 * @params: parameters to the method
6828 * @invoke: optional, delegate invoke.
6829 * @cb: async callback delegate.
6830 * @state: state passed to the async callback.
6832 * Translates arguments pointers into a MonoMethodMessage.
6835 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
6836 MonoDelegate **cb, MonoObject **state)
6838 MONO_REQ_GC_UNSAFE_MODE;
6842 MonoDomain *domain = mono_domain_get ();
6843 MonoMethodSignature *sig = mono_method_signature (method);
6844 MonoMethodMessage *msg;
6847 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
6848 mono_error_raise_exception (&error); /* FIXME don't raise here */
6851 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
6852 mono_error_raise_exception (&error); /* FIXME don't raise here */
6853 mono_message_init (domain, msg, rm, NULL);
6854 count = sig->param_count - 2;
6856 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
6857 mono_error_raise_exception (&error); /* FIXME don't raise here */
6858 mono_message_init (domain, msg, rm, NULL);
6859 count = sig->param_count;
6862 for (i = 0; i < count; i++) {
6867 if (sig->params [i]->byref)
6868 vpos = *((gpointer *)params [i]);
6872 klass = mono_class_from_mono_type (sig->params [i]);
6874 if (klass->valuetype)
6875 arg = mono_value_box (domain, klass, vpos);
6877 arg = *((MonoObject **)vpos);
6879 mono_array_setref (msg->args, i, arg);
6882 if (cb != NULL && state != NULL) {
6883 *cb = *((MonoDelegate **)params [i]);
6885 *state = *((MonoObject **)params [i]);
6892 * mono_method_return_message_restore:
6894 * Restore results from message based processing back to arguments pointers
6897 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6899 MONO_REQ_GC_UNSAFE_MODE;
6901 MonoMethodSignature *sig = mono_method_signature (method);
6902 int i, j, type, size, out_len;
6904 if (out_args == NULL)
6906 out_len = mono_array_length (out_args);
6910 for (i = 0, j = 0; i < sig->param_count; i++) {
6911 MonoType *pt = sig->params [i];
6916 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6918 arg = (char *)mono_array_get (out_args, gpointer, j);
6921 g_assert (type != MONO_TYPE_VOID);
6923 if (MONO_TYPE_IS_REFERENCE (pt)) {
6924 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6927 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6928 size = mono_class_value_size (klass, NULL);
6929 if (klass->has_references)
6930 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6932 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6934 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6935 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6944 #ifndef DISABLE_REMOTING
6947 * mono_load_remote_field:
6948 * @this: pointer to an object
6949 * @klass: klass of the object containing @field
6950 * @field: the field to load
6951 * @res: a storage to store the result
6953 * This method is called by the runtime on attempts to load fields of
6954 * transparent proxy objects. @this points to such TP, @klass is the class of
6955 * the object containing @field. @res is a storage location which can be
6956 * used to store the result.
6958 * Returns: an address pointing to the value of field.
6961 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6963 MONO_REQ_GC_UNSAFE_MODE;
6967 static MonoMethod *getter = NULL;
6968 MonoDomain *domain = mono_domain_get ();
6969 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6970 MonoClass *field_class;
6971 MonoMethodMessage *msg;
6972 MonoArray *out_args;
6976 g_assert (mono_object_is_transparent_proxy (this_obj));
6977 g_assert (res != NULL);
6979 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6980 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6985 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6987 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6990 field_class = mono_class_from_mono_type (field->type);
6992 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
6993 mono_error_raise_exception (&error); /* FIXME don't raise here */
6994 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6995 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
6996 mono_error_raise_exception (&error); /* FIXME don't raise here */
6997 mono_message_init (domain, msg, rm, out_args);
6999 full_name = mono_type_get_full_name (klass);
7000 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7001 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7004 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7006 if (exc) mono_raise_exception ((MonoException *)exc);
7008 if (mono_array_length (out_args) == 0)
7011 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7013 if (field_class->valuetype) {
7014 return ((char *)*res) + sizeof (MonoObject);
7020 * mono_load_remote_field_new:
7025 * Missing documentation.
7028 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7030 MONO_REQ_GC_UNSAFE_MODE;
7034 static MonoMethod *getter = NULL;
7035 MonoDomain *domain = mono_domain_get ();
7036 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7037 MonoClass *field_class;
7038 MonoMethodMessage *msg;
7039 MonoArray *out_args;
7040 MonoObject *exc, *res;
7043 g_assert (mono_object_is_transparent_proxy (this_obj));
7045 field_class = mono_class_from_mono_type (field->type);
7047 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7049 if (field_class->valuetype) {
7050 res = mono_object_new_checked (domain, field_class, &error);
7051 mono_error_raise_exception (&error); /* FIXME don't raise here */
7052 val = ((gchar *) res) + sizeof (MonoObject);
7056 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7061 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7063 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7066 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7067 mono_error_raise_exception (&error); /* FIXME don't raise here */
7068 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7070 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7071 mono_error_raise_exception (&error); /* FIXME don't raise here */
7072 mono_message_init (domain, msg, rm, out_args);
7074 full_name = mono_type_get_full_name (klass);
7075 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7076 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7079 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7081 if (exc) mono_raise_exception ((MonoException *)exc);
7083 if (mono_array_length (out_args) == 0)
7086 res = mono_array_get (out_args, MonoObject *, 0);
7092 * mono_store_remote_field:
7093 * @this_obj: pointer to an object
7094 * @klass: klass of the object containing @field
7095 * @field: the field to load
7096 * @val: the value/object to store
7098 * This method is called by the runtime on attempts to store fields of
7099 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7100 * the object containing @field. @val is the new value to store in @field.
7103 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7105 MONO_REQ_GC_UNSAFE_MODE;
7109 static MonoMethod *setter = NULL;
7110 MonoDomain *domain = mono_domain_get ();
7111 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7112 MonoClass *field_class;
7113 MonoMethodMessage *msg;
7114 MonoArray *out_args;
7119 g_assert (mono_object_is_transparent_proxy (this_obj));
7121 field_class = mono_class_from_mono_type (field->type);
7123 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7124 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7125 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7130 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7132 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7135 if (field_class->valuetype)
7136 arg = mono_value_box (domain, field_class, val);
7138 arg = *((MonoObject **)val);
7141 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7142 mono_error_raise_exception (&error); /* FIXME don't raise here */
7143 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7144 mono_error_raise_exception (&error); /* FIXME don't raise here */
7145 mono_message_init (domain, msg, rm, NULL);
7147 full_name = mono_type_get_full_name (klass);
7148 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7149 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7150 mono_array_setref (msg->args, 2, arg);
7153 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7155 if (exc) mono_raise_exception ((MonoException *)exc);
7159 * mono_store_remote_field_new:
7165 * Missing documentation
7168 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7170 MONO_REQ_GC_UNSAFE_MODE;
7174 static MonoMethod *setter = NULL;
7175 MonoDomain *domain = mono_domain_get ();
7176 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7177 MonoClass *field_class;
7178 MonoMethodMessage *msg;
7179 MonoArray *out_args;
7183 g_assert (mono_object_is_transparent_proxy (this_obj));
7185 field_class = mono_class_from_mono_type (field->type);
7187 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7188 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7189 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7194 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7196 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7199 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7200 mono_error_raise_exception (&error); /* FIXME don't raise here */
7201 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7202 mono_error_raise_exception (&error); /* FIXME don't raise here */
7203 mono_message_init (domain, msg, rm, NULL);
7205 full_name = mono_type_get_full_name (klass);
7206 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7207 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7208 mono_array_setref (msg->args, 2, arg);
7211 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7213 if (exc) mono_raise_exception ((MonoException *)exc);
7218 * mono_create_ftnptr:
7220 * Given a function address, create a function descriptor for it.
7221 * This is only needed on some platforms.
7224 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7226 return callbacks.create_ftnptr (domain, addr);
7230 * mono_get_addr_from_ftnptr:
7232 * Given a pointer to a function descriptor, return the function address.
7233 * This is only needed on some platforms.
7236 mono_get_addr_from_ftnptr (gpointer descr)
7238 return callbacks.get_addr_from_ftnptr (descr);
7242 * mono_string_chars:
7245 * Returns a pointer to the UCS16 characters stored in the MonoString
7248 mono_string_chars (MonoString *s)
7250 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7256 * mono_string_length:
7259 * Returns the lenght in characters of the string
7262 mono_string_length (MonoString *s)
7264 MONO_REQ_GC_UNSAFE_MODE;
7270 * mono_array_length:
7271 * @array: a MonoArray*
7273 * Returns the total number of elements in the array. This works for
7274 * both vectors and multidimensional arrays.
7277 mono_array_length (MonoArray *array)
7279 MONO_REQ_GC_UNSAFE_MODE;
7281 return array->max_length;
7285 * mono_array_addr_with_size:
7286 * @array: a MonoArray*
7287 * @size: size of the array elements
7288 * @idx: index into the array
7290 * Returns the address of the @idx element in the array.
7293 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7295 MONO_REQ_GC_UNSAFE_MODE;
7297 return ((char*)(array)->vector) + size * idx;
7302 mono_glist_to_array (GList *list, MonoClass *eclass)
7304 MonoDomain *domain = mono_domain_get ();
7311 len = g_list_length (list);
7312 res = mono_array_new (domain, eclass, len);
7314 for (i = 0; list; list = list->next, i++)
7315 mono_array_set (res, gpointer, i, list->data);