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;
73 MonoMethod *method = NULL;
74 MonoClass *klass = this_obj->vtable->klass;
76 method = mono_class_get_method_from_name (klass, ".ctor", 0);
78 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
80 if (method->klass->valuetype)
81 this_obj = (MonoObject *)mono_object_unbox (this_obj);
83 mono_runtime_invoke_checked (method, this_obj, NULL, &error);
84 mono_error_raise_exception (&error); /* FIXME don't raise here */
87 /* The pseudo algorithm for type initialization from the spec
88 Note it doesn't say anything about domains - only threads.
90 2. If the type is initialized you are done.
91 2.1. If the type is not yet initialized, try to take an
93 2.2. If successful, record this thread as responsible for
94 initializing the type and proceed to step 2.3.
95 2.2.1. If not, see whether this thread or any thread
96 waiting for this thread to complete already holds the lock.
97 2.2.2. If so, return since blocking would create a deadlock. This thread
98 will now see an incompletely initialized state for the type,
99 but no deadlock will arise.
100 2.2.3 If not, block until the type is initialized then return.
101 2.3 Initialize the parent type and then all interfaces implemented
103 2.4 Execute the type initialization code for this type.
104 2.5 Mark the type as initialized, release the initialization lock,
105 awaken any threads waiting for this type to be initialized,
112 MonoNativeThreadId initializing_tid;
113 guint32 waiting_count;
115 MonoCoopMutex initialization_section;
116 } TypeInitializationLock;
118 /* for locking access to type_initialization_hash and blocked_thread_hash */
119 static MonoCoopMutex type_initialization_section;
122 mono_type_initialization_lock (void)
124 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
125 mono_coop_mutex_lock (&type_initialization_section);
129 mono_type_initialization_unlock (void)
131 mono_coop_mutex_unlock (&type_initialization_section);
135 mono_type_init_lock (TypeInitializationLock *lock)
137 MONO_REQ_GC_NEUTRAL_MODE;
139 mono_coop_mutex_lock (&lock->initialization_section);
143 mono_type_init_unlock (TypeInitializationLock *lock)
145 mono_coop_mutex_unlock (&lock->initialization_section);
148 /* from vtable to lock */
149 static GHashTable *type_initialization_hash;
151 /* from thread id to thread id being waited on */
152 static GHashTable *blocked_thread_hash;
155 static MonoThread *main_thread;
157 /* Functions supplied by the runtime */
158 static MonoRuntimeCallbacks callbacks;
161 * mono_thread_set_main:
162 * @thread: thread to set as the main thread
164 * This function can be used to instruct the runtime to treat @thread
165 * as the main thread, ie, the thread that would normally execute the Main()
166 * method. This basically means that at the end of @thread, the runtime will
167 * wait for the existing foreground threads to quit and other such details.
170 mono_thread_set_main (MonoThread *thread)
172 MONO_REQ_GC_UNSAFE_MODE;
174 static gboolean registered = FALSE;
177 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
181 main_thread = thread;
185 mono_thread_get_main (void)
187 MONO_REQ_GC_UNSAFE_MODE;
193 mono_type_initialization_init (void)
195 mono_coop_mutex_init_recursive (&type_initialization_section);
196 type_initialization_hash = g_hash_table_new (NULL, NULL);
197 blocked_thread_hash = g_hash_table_new (NULL, NULL);
198 mono_os_mutex_init_recursive (&ldstr_section);
202 mono_type_initialization_cleanup (void)
205 /* This is causing race conditions with
206 * mono_release_type_locks
208 mono_coop_mutex_destroy (&type_initialization_section);
209 g_hash_table_destroy (type_initialization_hash);
210 type_initialization_hash = NULL;
212 mono_os_mutex_destroy (&ldstr_section);
213 g_hash_table_destroy (blocked_thread_hash);
214 blocked_thread_hash = NULL;
220 * get_type_init_exception_for_vtable:
222 * Return the stored type initialization exception for VTABLE.
224 static MonoException*
225 get_type_init_exception_for_vtable (MonoVTable *vtable)
227 MONO_REQ_GC_UNSAFE_MODE;
229 MonoDomain *domain = vtable->domain;
230 MonoClass *klass = vtable->klass;
234 if (!vtable->init_failed)
235 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
238 * If the initializing thread was rudely aborted, the exception is not stored
242 mono_domain_lock (domain);
243 if (domain->type_init_exception_hash)
244 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
245 mono_domain_unlock (domain);
248 if (klass->name_space && *klass->name_space)
249 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
251 full_name = g_strdup (klass->name);
252 ex = mono_get_exception_type_initialization (full_name, NULL);
259 * mono_runtime_class_init:
260 * @vtable: vtable that needs to be initialized
262 * This routine calls the class constructor for @vtable.
265 mono_runtime_class_init (MonoVTable *vtable)
267 MONO_REQ_GC_UNSAFE_MODE;
269 mono_runtime_class_init_full (vtable, TRUE);
273 * mono_runtime_class_init_full:
274 * @vtable that neeeds to be initialized
275 * @raise_exception is TRUE, exceptions are raised intead of returned
279 mono_runtime_class_init_full (MonoVTable *vtable, gboolean raise_exception)
281 MONO_REQ_GC_UNSAFE_MODE;
285 MonoException *exc_to_throw;
286 MonoMethod *method = NULL;
289 MonoDomain *domain = vtable->domain;
290 TypeInitializationLock *lock;
291 MonoNativeThreadId tid;
292 int do_initialization = 0;
293 MonoDomain *last_domain = NULL;
295 if (vtable->initialized)
299 klass = vtable->klass;
301 if (!klass->image->checked_module_cctor) {
302 mono_image_check_for_module_cctor (klass->image);
303 if (klass->image->has_module_cctor) {
305 MonoClass *module_klass;
306 MonoVTable *module_vtable;
308 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, &error);
310 exc = mono_error_convert_to_exception (&error);
312 mono_raise_exception (exc);
316 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, raise_exception);
319 exc = mono_runtime_class_init_full (module_vtable, raise_exception);
324 method = mono_class_get_cctor (klass);
326 vtable->initialized = 1;
330 tid = mono_native_thread_id_get ();
332 mono_type_initialization_lock ();
333 /* double check... */
334 if (vtable->initialized) {
335 mono_type_initialization_unlock ();
338 if (vtable->init_failed) {
339 mono_type_initialization_unlock ();
341 /* The type initialization already failed once, rethrow the same exception */
343 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
344 return get_type_init_exception_for_vtable (vtable);
346 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
348 /* This thread will get to do the initialization */
349 if (mono_domain_get () != domain) {
350 /* Transfer into the target domain */
351 last_domain = mono_domain_get ();
352 if (!mono_domain_set (domain, FALSE)) {
353 vtable->initialized = 1;
354 mono_type_initialization_unlock ();
356 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
357 return mono_get_exception_appdomain_unloaded ();
360 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
361 mono_coop_mutex_init_recursive (&lock->initialization_section);
362 lock->initializing_tid = tid;
363 lock->waiting_count = 1;
365 /* grab the vtable lock while this thread still owns type_initialization_section */
366 /* This is why type_initialization_lock needs to enter blocking mode */
367 mono_type_init_lock (lock);
368 g_hash_table_insert (type_initialization_hash, vtable, lock);
369 do_initialization = 1;
372 TypeInitializationLock *pending_lock;
374 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
375 mono_type_initialization_unlock ();
378 /* see if the thread doing the initialization is already blocked on this thread */
379 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
380 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
381 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
382 if (!pending_lock->done) {
383 mono_type_initialization_unlock ();
386 /* the thread doing the initialization is blocked on this thread,
387 but on a lock that has already been freed. It just hasn't got
392 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
394 ++lock->waiting_count;
395 /* record the fact that we are waiting on the initializing thread */
396 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
398 mono_type_initialization_unlock ();
400 if (do_initialization) {
401 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, &error);
402 if (exc == NULL && !mono_error_ok (&error))
403 exc = mono_error_convert_to_exception (&error);
405 /* If the initialization failed, mark the class as unusable. */
406 /* Avoid infinite loops */
408 (klass->image == mono_defaults.corlib &&
409 !strcmp (klass->name_space, "System") &&
410 !strcmp (klass->name, "TypeInitializationException")))) {
411 vtable->init_failed = 1;
413 if (klass->name_space && *klass->name_space)
414 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
416 full_name = g_strdup (klass->name);
417 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
421 * Store the exception object so it could be thrown on subsequent
424 mono_domain_lock (domain);
425 if (!domain->type_init_exception_hash)
426 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");
427 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
428 mono_domain_unlock (domain);
432 mono_domain_set (last_domain, TRUE);
434 mono_type_init_unlock (lock);
436 /* this just blocks until the initializing thread is done */
437 mono_type_init_lock (lock);
438 mono_type_init_unlock (lock);
441 mono_type_initialization_lock ();
442 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
443 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
444 --lock->waiting_count;
445 if (lock->waiting_count == 0) {
446 mono_coop_mutex_destroy (&lock->initialization_section);
447 g_hash_table_remove (type_initialization_hash, vtable);
450 mono_memory_barrier ();
451 if (!vtable->init_failed)
452 vtable->initialized = 1;
453 mono_type_initialization_unlock ();
455 if (vtable->init_failed) {
456 /* Either we were the initializing thread or we waited for the initialization */
458 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
459 return get_type_init_exception_for_vtable (vtable);
465 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
467 MONO_REQ_GC_NEUTRAL_MODE;
469 MonoVTable *vtable = (MonoVTable*)key;
471 TypeInitializationLock *lock = (TypeInitializationLock*) value;
472 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
475 * Have to set this since it cannot be set by the normal code in
476 * mono_runtime_class_init (). In this case, the exception object is not stored,
477 * and get_type_init_exception_for_class () needs to be aware of this.
479 vtable->init_failed = 1;
480 mono_type_init_unlock (lock);
481 --lock->waiting_count;
482 if (lock->waiting_count == 0) {
483 mono_coop_mutex_destroy (&lock->initialization_section);
492 mono_release_type_locks (MonoInternalThread *thread)
494 MONO_REQ_GC_UNSAFE_MODE;
496 mono_type_initialization_lock ();
497 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
498 mono_type_initialization_unlock ();
502 default_trampoline (MonoMethod *method)
508 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
510 g_assert_not_reached ();
515 #ifndef DISABLE_REMOTING
518 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
520 g_error ("remoting not installed");
524 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
528 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
530 g_assert_not_reached ();
534 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
535 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
536 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
537 static MonoImtThunkBuilder imt_thunk_builder;
538 static gboolean always_build_imt_thunks;
540 #if (MONO_IMT_SIZE > 32)
541 #error "MONO_IMT_SIZE cannot be larger than 32"
545 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
547 memcpy (&callbacks, cbs, sizeof (*cbs));
550 MonoRuntimeCallbacks*
551 mono_get_runtime_callbacks (void)
557 mono_install_trampoline (MonoTrampoline func)
559 arch_create_jit_trampoline = func? func: default_trampoline;
563 mono_install_jump_trampoline (MonoJumpTrampoline func)
565 arch_create_jump_trampoline = func? func: default_jump_trampoline;
568 #ifndef DISABLE_REMOTING
570 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
572 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
577 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
579 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
583 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
584 imt_thunk_builder = func;
588 mono_set_always_build_imt_thunks (gboolean value)
590 always_build_imt_thunks = value;
594 * mono_compile_method:
595 * @method: The method to compile.
597 * This JIT-compiles the method, and returns the pointer to the native code
601 mono_compile_method (MonoMethod *method)
606 MONO_REQ_GC_NEUTRAL_MODE
608 if (!callbacks.compile_method) {
609 g_error ("compile method called on uninitialized runtime");
612 res = callbacks.compile_method (method, &error);
613 if (!mono_error_ok (&error))
614 mono_error_raise_exception (&error);
619 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
621 MONO_REQ_GC_NEUTRAL_MODE
623 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
627 mono_runtime_create_delegate_trampoline (MonoClass *klass)
629 MONO_REQ_GC_NEUTRAL_MODE
631 return arch_create_delegate_trampoline (mono_domain_get (), klass);
634 static MonoFreeMethodFunc default_mono_free_method = NULL;
637 * mono_install_free_method:
638 * @func: pointer to the MonoFreeMethodFunc used to release a method
640 * This is an internal VM routine, it is used for the engines to
641 * register a handler to release the resources associated with a method.
643 * Methods are freed when no more references to the delegate that holds
647 mono_install_free_method (MonoFreeMethodFunc func)
649 default_mono_free_method = func;
653 * mono_runtime_free_method:
654 * @domain; domain where the method is hosted
655 * @method: method to release
657 * This routine is invoked to free the resources associated with
658 * a method that has been JIT compiled. This is used to discard
659 * methods that were used only temporarily (for example, used in marshalling)
663 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
665 MONO_REQ_GC_NEUTRAL_MODE
667 if (default_mono_free_method != NULL)
668 default_mono_free_method (domain, method);
670 mono_method_clear_object (domain, method);
672 mono_free_method (method);
676 * The vtables in the root appdomain are assumed to be reachable by other
677 * roots, and we don't use typed allocation in the other domains.
680 /* The sync block is no longer a GC pointer */
681 #define GC_HEADER_BITMAP (0)
683 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
686 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
688 MONO_REQ_GC_NEUTRAL_MODE;
690 MonoClassField *field;
696 max_size = mono_class_data_size (klass) / sizeof (gpointer);
698 max_size = klass->instance_size / sizeof (gpointer);
699 if (max_size > size) {
700 g_assert (offset <= 0);
701 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
706 /*An Ephemeron cannot be marked by sgen*/
707 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
709 memset (bitmap, 0, size / 8);
714 for (p = klass; p != NULL; p = p->parent) {
715 gpointer iter = NULL;
716 while ((field = mono_class_get_fields (p, &iter))) {
720 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
722 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
725 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
728 /* FIXME: should not happen, flag as type load error */
729 if (field->type->byref)
732 if (static_fields && field->offset == -1)
736 pos = field->offset / sizeof (gpointer);
739 type = mono_type_get_underlying_type (field->type);
740 switch (type->type) {
743 case MONO_TYPE_FNPTR:
745 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
750 if (klass->image != mono_defaults.corlib)
753 case MONO_TYPE_STRING:
754 case MONO_TYPE_SZARRAY:
755 case MONO_TYPE_CLASS:
756 case MONO_TYPE_OBJECT:
757 case MONO_TYPE_ARRAY:
758 g_assert ((field->offset % sizeof(gpointer)) == 0);
760 g_assert (pos < size || pos <= max_size);
761 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
762 *max_set = MAX (*max_set, pos);
764 case MONO_TYPE_GENERICINST:
765 if (!mono_type_generic_inst_is_valuetype (type)) {
766 g_assert ((field->offset % sizeof(gpointer)) == 0);
768 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
769 *max_set = MAX (*max_set, pos);
774 case MONO_TYPE_VALUETYPE: {
775 MonoClass *fclass = mono_class_from_mono_type (field->type);
776 if (fclass->has_references) {
777 /* remove the object header */
778 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
792 case MONO_TYPE_BOOLEAN:
796 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
807 * mono_class_compute_bitmap:
809 * Mono internal function to compute a bitmap of reference fields in a class.
812 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
814 MONO_REQ_GC_NEUTRAL_MODE;
816 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
821 * similar to the above, but sets the bits in the bitmap for any non-ref field
822 * and ignores static fields
825 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
827 MonoClassField *field;
832 max_size = class->instance_size / sizeof (gpointer);
833 if (max_size >= size) {
834 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
837 for (p = class; p != NULL; p = p->parent) {
838 gpointer iter = NULL;
839 while ((field = mono_class_get_fields (p, &iter))) {
842 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
844 /* FIXME: should not happen, flag as type load error */
845 if (field->type->byref)
848 pos = field->offset / sizeof (gpointer);
851 type = mono_type_get_underlying_type (field->type);
852 switch (type->type) {
853 #if SIZEOF_VOID_P == 8
857 case MONO_TYPE_FNPTR:
862 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
863 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
864 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
867 #if SIZEOF_VOID_P == 4
871 case MONO_TYPE_FNPTR:
876 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
877 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
878 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
884 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
885 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
886 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
889 case MONO_TYPE_BOOLEAN:
892 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
894 case MONO_TYPE_STRING:
895 case MONO_TYPE_SZARRAY:
896 case MONO_TYPE_CLASS:
897 case MONO_TYPE_OBJECT:
898 case MONO_TYPE_ARRAY:
900 case MONO_TYPE_GENERICINST:
901 if (!mono_type_generic_inst_is_valuetype (type)) {
906 case MONO_TYPE_VALUETYPE: {
907 MonoClass *fclass = mono_class_from_mono_type (field->type);
908 /* remove the object header */
909 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
913 g_assert_not_reached ();
922 * mono_class_insecure_overlapping:
923 * check if a class with explicit layout has references and non-references
924 * fields overlapping.
926 * Returns: TRUE if it is insecure to load the type.
929 mono_class_insecure_overlapping (MonoClass *klass)
933 gsize default_bitmap [4] = {0};
935 gsize default_nrbitmap [4] = {0};
936 int i, insecure = FALSE;
939 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
940 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
942 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
943 int idx = i % (sizeof (bitmap [0]) * 8);
944 if (bitmap [idx] & nrbitmap [idx]) {
949 if (bitmap != default_bitmap)
951 if (nrbitmap != default_nrbitmap)
954 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
962 ves_icall_string_alloc (int length)
965 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
966 mono_error_raise_exception (&error);
972 mono_class_compute_gc_descriptor (MonoClass *klass)
974 MONO_REQ_GC_NEUTRAL_MODE;
978 gsize default_bitmap [4] = {0};
979 static gboolean gcj_inited = FALSE;
984 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
985 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
988 mono_loader_unlock ();
992 mono_class_init (klass);
994 if (klass->gc_descr_inited)
997 klass->gc_descr_inited = TRUE;
998 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1000 bitmap = default_bitmap;
1001 if (klass == mono_defaults.string_class) {
1002 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1003 } else if (klass->rank) {
1004 mono_class_compute_gc_descriptor (klass->element_class);
1005 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1007 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1008 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1009 class->name_space, class->name);*/
1011 /* remove the object header */
1012 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1013 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));
1014 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1015 class->name_space, class->name);*/
1016 if (bitmap != default_bitmap)
1020 /*static int count = 0;
1023 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1024 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1026 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1027 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1029 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1030 if (bitmap != default_bitmap)
1036 * field_is_special_static:
1037 * @fklass: The MonoClass to look up.
1038 * @field: The MonoClassField describing the field.
1040 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1041 * SPECIAL_STATIC_NONE otherwise.
1044 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1046 MONO_REQ_GC_NEUTRAL_MODE;
1048 MonoCustomAttrInfo *ainfo;
1050 ainfo = mono_custom_attrs_from_field (fklass, field);
1053 for (i = 0; i < ainfo->num_attrs; ++i) {
1054 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1055 if (klass->image == mono_defaults.corlib) {
1056 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1057 mono_custom_attrs_free (ainfo);
1058 return SPECIAL_STATIC_THREAD;
1060 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1061 mono_custom_attrs_free (ainfo);
1062 return SPECIAL_STATIC_CONTEXT;
1066 mono_custom_attrs_free (ainfo);
1067 return SPECIAL_STATIC_NONE;
1070 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1071 #define mix(a,b,c) { \
1072 a -= c; a ^= rot(c, 4); c += b; \
1073 b -= a; b ^= rot(a, 6); a += c; \
1074 c -= b; c ^= rot(b, 8); b += a; \
1075 a -= c; a ^= rot(c,16); c += b; \
1076 b -= a; b ^= rot(a,19); a += c; \
1077 c -= b; c ^= rot(b, 4); b += a; \
1079 #define final(a,b,c) { \
1080 c ^= b; c -= rot(b,14); \
1081 a ^= c; a -= rot(c,11); \
1082 b ^= a; b -= rot(a,25); \
1083 c ^= b; c -= rot(b,16); \
1084 a ^= c; a -= rot(c,4); \
1085 b ^= a; b -= rot(a,14); \
1086 c ^= b; c -= rot(b,24); \
1090 * mono_method_get_imt_slot:
1092 * The IMT slot is embedded into AOTed code, so this must return the same value
1093 * for the same method across all executions. This means:
1094 * - pointers shouldn't be used as hash values.
1095 * - mono_metadata_str_hash () should be used for hashing strings.
1098 mono_method_get_imt_slot (MonoMethod *method)
1100 MONO_REQ_GC_NEUTRAL_MODE;
1102 MonoMethodSignature *sig;
1104 guint32 *hashes_start, *hashes;
1108 /* This can be used to stress tests the collision code */
1112 * We do this to simplify generic sharing. It will hurt
1113 * performance in cases where a class implements two different
1114 * instantiations of the same generic interface.
1115 * The code in build_imt_slots () depends on this.
1117 if (method->is_inflated)
1118 method = ((MonoMethodInflated*)method)->declaring;
1120 sig = mono_method_signature (method);
1121 hashes_count = sig->param_count + 4;
1122 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1123 hashes = hashes_start;
1125 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1126 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1127 method->klass->name_space, method->klass->name, method->name);
1130 /* Initialize hashes */
1131 hashes [0] = mono_metadata_str_hash (method->klass->name);
1132 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1133 hashes [2] = mono_metadata_str_hash (method->name);
1134 hashes [3] = mono_metadata_type_hash (sig->ret);
1135 for (i = 0; i < sig->param_count; i++) {
1136 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1139 /* Setup internal state */
1140 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1142 /* Handle most of the hashes */
1143 while (hashes_count > 3) {
1152 /* Handle the last 3 hashes (all the case statements fall through) */
1153 switch (hashes_count) {
1154 case 3 : c += hashes [2];
1155 case 2 : b += hashes [1];
1156 case 1 : a += hashes [0];
1158 case 0: /* nothing left to add */
1162 free (hashes_start);
1163 /* Report the result */
1164 return c % MONO_IMT_SIZE;
1173 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1174 MONO_REQ_GC_NEUTRAL_MODE;
1176 guint32 imt_slot = mono_method_get_imt_slot (method);
1177 MonoImtBuilderEntry *entry;
1179 if (slot_num >= 0 && imt_slot != slot_num) {
1180 /* we build just a single imt slot and this is not it */
1184 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1185 entry->key = method;
1186 entry->value.vtable_slot = vtable_slot;
1187 entry->next = imt_builder [imt_slot];
1188 if (imt_builder [imt_slot] != NULL) {
1189 entry->children = imt_builder [imt_slot]->children + 1;
1190 if (entry->children == 1) {
1191 mono_stats.imt_slots_with_collisions++;
1192 *imt_collisions_bitmap |= (1 << imt_slot);
1195 entry->children = 0;
1196 mono_stats.imt_used_slots++;
1198 imt_builder [imt_slot] = entry;
1201 char *method_name = mono_method_full_name (method, TRUE);
1202 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1203 method, method_name, imt_slot, vtable_slot, entry->children);
1204 g_free (method_name);
1211 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1213 MonoMethod *method = e->key;
1214 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1218 method->klass->name_space,
1219 method->klass->name,
1222 printf (" * %s: NULL\n", message);
1228 compare_imt_builder_entries (const void *p1, const void *p2) {
1229 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1230 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1232 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1236 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1238 MONO_REQ_GC_NEUTRAL_MODE;
1240 int count = end - start;
1241 int chunk_start = out_array->len;
1244 for (i = start; i < end; ++i) {
1245 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1246 item->key = sorted_array [i]->key;
1247 item->value = sorted_array [i]->value;
1248 item->has_target_code = sorted_array [i]->has_target_code;
1249 item->is_equals = TRUE;
1251 item->check_target_idx = out_array->len + 1;
1253 item->check_target_idx = 0;
1254 g_ptr_array_add (out_array, item);
1257 int middle = start + count / 2;
1258 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1260 item->key = sorted_array [middle]->key;
1261 item->is_equals = FALSE;
1262 g_ptr_array_add (out_array, item);
1263 imt_emit_ir (sorted_array, start, middle, out_array);
1264 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1270 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1271 MONO_REQ_GC_NEUTRAL_MODE;
1273 int number_of_entries = entries->children + 1;
1274 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1275 GPtrArray *result = g_ptr_array_new ();
1276 MonoImtBuilderEntry *current_entry;
1279 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1280 sorted_array [i] = current_entry;
1282 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1284 /*for (i = 0; i < number_of_entries; i++) {
1285 print_imt_entry (" sorted array:", sorted_array [i], i);
1288 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1290 free (sorted_array);
1295 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1297 MONO_REQ_GC_NEUTRAL_MODE;
1299 if (imt_builder_entry != NULL) {
1300 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1301 /* No collision, return the vtable slot contents */
1302 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1304 /* Collision, build the thunk */
1305 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1308 result = imt_thunk_builder (vtable, domain,
1309 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1310 for (i = 0; i < imt_ir->len; ++i)
1311 g_free (g_ptr_array_index (imt_ir, i));
1312 g_ptr_array_free (imt_ir, TRUE);
1324 static MonoImtBuilderEntry*
1325 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1328 * LOCKING: requires the loader and domain locks.
1332 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1334 MONO_REQ_GC_NEUTRAL_MODE;
1338 guint32 imt_collisions_bitmap = 0;
1339 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1340 int method_count = 0;
1341 gboolean record_method_count_for_max_collisions = FALSE;
1342 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1345 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1347 for (i = 0; i < klass->interface_offsets_count; ++i) {
1348 MonoClass *iface = klass->interfaces_packed [i];
1349 int interface_offset = klass->interface_offsets_packed [i];
1350 int method_slot_in_interface, vt_slot;
1352 if (mono_class_has_variant_generic_params (iface))
1353 has_variant_iface = TRUE;
1355 mono_class_setup_methods (iface);
1356 vt_slot = interface_offset;
1357 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1360 if (slot_num >= 0 && iface->is_inflated) {
1362 * The imt slot of the method is the same as for its declaring method,
1363 * see the comment in mono_method_get_imt_slot (), so we can
1364 * avoid inflating methods which will be discarded by
1365 * add_imt_builder_entry anyway.
1367 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1368 if (mono_method_get_imt_slot (method) != slot_num) {
1373 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1374 if (method->is_generic) {
1375 has_generic_virtual = TRUE;
1380 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1381 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1386 if (extra_interfaces) {
1387 int interface_offset = klass->vtable_size;
1389 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1390 MonoClass* iface = (MonoClass *)list_item->data;
1391 int method_slot_in_interface;
1392 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1393 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1395 if (method->is_generic)
1396 has_generic_virtual = TRUE;
1397 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1399 interface_offset += iface->method.count;
1402 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1403 /* overwrite the imt slot only if we're building all the entries or if
1404 * we're building this specific one
1406 if (slot_num < 0 || i == slot_num) {
1407 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1410 if (imt_builder [i]) {
1411 MonoImtBuilderEntry *entry;
1413 /* Link entries with imt_builder [i] */
1414 for (entry = entries; entry->next; entry = entry->next) {
1416 MonoMethod *method = (MonoMethod*)entry->key;
1417 char *method_name = mono_method_full_name (method, TRUE);
1418 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1419 g_free (method_name);
1422 entry->next = imt_builder [i];
1423 entries->children += imt_builder [i]->children + 1;
1425 imt_builder [i] = entries;
1428 if (has_generic_virtual || has_variant_iface) {
1430 * There might be collisions later when the the thunk is expanded.
1432 imt_collisions_bitmap |= (1 << i);
1435 * The IMT thunk might be called with an instance of one of the
1436 * generic virtual methods, so has to fallback to the IMT trampoline.
1438 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1440 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1443 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1447 if (imt_builder [i] != NULL) {
1448 int methods_in_slot = imt_builder [i]->children + 1;
1449 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1450 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1451 record_method_count_for_max_collisions = TRUE;
1453 method_count += methods_in_slot;
1457 mono_stats.imt_number_of_methods += method_count;
1458 if (record_method_count_for_max_collisions) {
1459 mono_stats.imt_method_count_when_max_collisions = method_count;
1462 for (i = 0; i < MONO_IMT_SIZE; i++) {
1463 MonoImtBuilderEntry* entry = imt_builder [i];
1464 while (entry != NULL) {
1465 MonoImtBuilderEntry* next = entry->next;
1471 /* we OR the bitmap since we may build just a single imt slot at a time */
1472 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1476 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1477 MONO_REQ_GC_NEUTRAL_MODE;
1479 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1483 * mono_vtable_build_imt_slot:
1484 * @vtable: virtual object table struct
1485 * @imt_slot: slot in the IMT table
1487 * Fill the given @imt_slot in the IMT table of @vtable with
1488 * a trampoline or a thunk for the case of collisions.
1489 * This is part of the internal mono API.
1491 * LOCKING: Take the domain lock.
1494 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1496 MONO_REQ_GC_NEUTRAL_MODE;
1498 gpointer *imt = (gpointer*)vtable;
1499 imt -= MONO_IMT_SIZE;
1500 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1502 /* no support for extra interfaces: the proxy objects will need
1503 * to build the complete IMT
1504 * Update and heck needs to ahppen inside the proper domain lock, as all
1505 * the changes made to a MonoVTable.
1507 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1508 mono_domain_lock (vtable->domain);
1509 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1510 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1511 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1512 mono_domain_unlock (vtable->domain);
1513 mono_loader_unlock ();
1518 * The first two free list entries both belong to the wait list: The
1519 * first entry is the pointer to the head of the list and the second
1520 * entry points to the last element. That way appending and removing
1521 * the first element are both O(1) operations.
1523 #ifdef MONO_SMALL_CONFIG
1524 #define NUM_FREE_LISTS 6
1526 #define NUM_FREE_LISTS 12
1528 #define FIRST_FREE_LIST_SIZE 64
1529 #define MAX_WAIT_LENGTH 50
1530 #define THUNK_THRESHOLD 10
1533 * LOCKING: The domain lock must be held.
1536 init_thunk_free_lists (MonoDomain *domain)
1538 MONO_REQ_GC_NEUTRAL_MODE;
1540 if (domain->thunk_free_lists)
1542 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1546 list_index_for_size (int item_size)
1549 int size = FIRST_FREE_LIST_SIZE;
1551 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1560 * mono_method_alloc_generic_virtual_thunk:
1562 * @size: size in bytes
1564 * Allocs size bytes to be used for the code of a generic virtual
1565 * thunk. It's either allocated from the domain's code manager or
1566 * reused from a previously invalidated piece.
1568 * LOCKING: The domain lock must be held.
1571 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1573 MONO_REQ_GC_NEUTRAL_MODE;
1575 static gboolean inited = FALSE;
1576 static int generic_virtual_thunks_size = 0;
1580 MonoThunkFreeList **l;
1582 init_thunk_free_lists (domain);
1584 size += sizeof (guint32);
1585 if (size < sizeof (MonoThunkFreeList))
1586 size = sizeof (MonoThunkFreeList);
1588 i = list_index_for_size (size);
1589 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1590 if ((*l)->size >= size) {
1591 MonoThunkFreeList *item = *l;
1593 return ((guint32*)item) + 1;
1597 /* no suitable item found - search lists of larger sizes */
1598 while (++i < NUM_FREE_LISTS) {
1599 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1602 g_assert (item->size > size);
1603 domain->thunk_free_lists [i] = item->next;
1604 return ((guint32*)item) + 1;
1607 /* still nothing found - allocate it */
1609 mono_counters_register ("Generic virtual thunk bytes",
1610 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1613 generic_virtual_thunks_size += size;
1615 p = (guint32 *)mono_domain_code_reserve (domain, size);
1618 mono_domain_lock (domain);
1619 if (!domain->generic_virtual_thunks)
1620 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1621 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1622 mono_domain_unlock (domain);
1628 * LOCKING: The domain lock must be held.
1631 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1633 MONO_REQ_GC_NEUTRAL_MODE;
1635 guint32 *p = (guint32 *)code;
1636 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1637 gboolean found = FALSE;
1639 mono_domain_lock (domain);
1640 if (!domain->generic_virtual_thunks)
1641 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1642 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1644 mono_domain_unlock (domain);
1647 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1649 init_thunk_free_lists (domain);
1651 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1652 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1653 int length = item->length;
1656 /* unlink the first item from the wait list */
1657 domain->thunk_free_lists [0] = item->next;
1658 domain->thunk_free_lists [0]->length = length - 1;
1660 i = list_index_for_size (item->size);
1662 /* put it in the free list */
1663 item->next = domain->thunk_free_lists [i];
1664 domain->thunk_free_lists [i] = item;
1668 if (domain->thunk_free_lists [1]) {
1669 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1670 domain->thunk_free_lists [0]->length++;
1672 g_assert (!domain->thunk_free_lists [0]);
1674 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1675 domain->thunk_free_lists [0]->length = 1;
1679 typedef struct _GenericVirtualCase {
1683 struct _GenericVirtualCase *next;
1684 } GenericVirtualCase;
1687 * get_generic_virtual_entries:
1689 * Return IMT entries for the generic virtual method instances and
1690 * variant interface methods for vtable slot
1693 static MonoImtBuilderEntry*
1694 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1696 MONO_REQ_GC_NEUTRAL_MODE;
1698 GenericVirtualCase *list;
1699 MonoImtBuilderEntry *entries;
1701 mono_domain_lock (domain);
1702 if (!domain->generic_virtual_cases)
1703 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1705 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1708 for (; list; list = list->next) {
1709 MonoImtBuilderEntry *entry;
1711 if (list->count < THUNK_THRESHOLD)
1714 entry = g_new0 (MonoImtBuilderEntry, 1);
1715 entry->key = list->method;
1716 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1717 entry->has_target_code = 1;
1719 entry->children = entries->children + 1;
1720 entry->next = entries;
1724 mono_domain_unlock (domain);
1726 /* FIXME: Leaking memory ? */
1731 * mono_method_add_generic_virtual_invocation:
1733 * @vtable_slot: pointer to the vtable slot
1734 * @method: the inflated generic virtual method
1735 * @code: the method's code
1737 * Registers a call via unmanaged code to a generic virtual method
1738 * instantiation or variant interface method. If the number of calls reaches a threshold
1739 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1740 * virtual method thunk.
1743 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1744 gpointer *vtable_slot,
1745 MonoMethod *method, gpointer code)
1747 MONO_REQ_GC_NEUTRAL_MODE;
1749 static gboolean inited = FALSE;
1750 static int num_added = 0;
1752 GenericVirtualCase *gvc, *list;
1753 MonoImtBuilderEntry *entries;
1757 mono_domain_lock (domain);
1758 if (!domain->generic_virtual_cases)
1759 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1761 /* Check whether the case was already added */
1762 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1765 if (gvc->method == method)
1770 /* If not found, make a new one */
1772 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1773 gvc->method = method;
1776 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1778 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1781 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1787 if (++gvc->count == THUNK_THRESHOLD) {
1788 gpointer *old_thunk = (void **)*vtable_slot;
1789 gpointer vtable_trampoline = NULL;
1790 gpointer imt_trampoline = NULL;
1792 if ((gpointer)vtable_slot < (gpointer)vtable) {
1793 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1794 int imt_slot = MONO_IMT_SIZE + displacement;
1796 /* Force the rebuild of the thunk at the next call */
1797 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1798 *vtable_slot = imt_trampoline;
1800 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1802 entries = get_generic_virtual_entries (domain, vtable_slot);
1804 sorted = imt_sort_slot_entries (entries);
1806 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1810 MonoImtBuilderEntry *next = entries->next;
1815 for (i = 0; i < sorted->len; ++i)
1816 g_free (g_ptr_array_index (sorted, i));
1817 g_ptr_array_free (sorted, TRUE);
1820 #ifndef __native_client__
1821 /* We don't re-use any thunks as there is a lot of overhead */
1822 /* to deleting and re-using code in Native Client. */
1823 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1824 invalidate_generic_virtual_thunk (domain, old_thunk);
1828 mono_domain_unlock (domain);
1831 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1834 * mono_class_vtable:
1835 * @domain: the application domain
1836 * @class: the class to initialize
1838 * VTables are domain specific because we create domain specific code, and
1839 * they contain the domain specific static class data.
1840 * On failure, NULL is returned, and class->exception_type is set.
1843 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1845 return mono_class_vtable_full (domain, klass, FALSE);
1849 * mono_class_vtable_full:
1850 * @domain: the application domain
1851 * @class: the class to initialize
1852 * @raise_on_error if an exception should be raised on failure or not
1854 * VTables are domain specific because we create domain specific code, and
1855 * they contain the domain specific static class data.
1858 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1860 MONO_REQ_GC_UNSAFE_MODE;
1862 MonoClassRuntimeInfo *runtime_info;
1866 if (klass->exception_type) {
1868 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1872 /* this check can be inlined in jitted code, too */
1873 runtime_info = klass->runtime_info;
1874 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1875 return runtime_info->domain_vtables [domain->domain_id];
1876 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1880 * mono_class_try_get_vtable:
1881 * @domain: the application domain
1882 * @class: the class to initialize
1884 * This function tries to get the associated vtable from @class if
1885 * it was already created.
1888 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1890 MONO_REQ_GC_NEUTRAL_MODE;
1892 MonoClassRuntimeInfo *runtime_info;
1896 runtime_info = klass->runtime_info;
1897 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1898 return runtime_info->domain_vtables [domain->domain_id];
1903 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1905 MONO_REQ_GC_NEUTRAL_MODE;
1907 size_t alloc_offset;
1910 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1911 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1912 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1914 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1915 g_assert ((imt_table_bytes & 7) == 4);
1922 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1926 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1928 MONO_REQ_GC_UNSAFE_MODE;
1932 MonoClassRuntimeInfo *runtime_info, *old_info;
1933 MonoClassField *field;
1935 int i, vtable_slots;
1936 size_t imt_table_bytes;
1938 guint32 vtable_size, class_size;
1940 gpointer *interface_offsets;
1942 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1943 mono_domain_lock (domain);
1944 runtime_info = klass->runtime_info;
1945 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1946 mono_domain_unlock (domain);
1947 mono_loader_unlock ();
1948 return runtime_info->domain_vtables [domain->domain_id];
1950 if (!klass->inited || klass->exception_type) {
1951 if (!mono_class_init (klass) || klass->exception_type) {
1952 mono_domain_unlock (domain);
1953 mono_loader_unlock ();
1955 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1960 /* Array types require that their element type be valid*/
1961 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1962 MonoClass *element_class = klass->element_class;
1963 if (!element_class->inited)
1964 mono_class_init (element_class);
1966 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1967 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1968 mono_class_setup_vtable (element_class);
1970 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1971 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1972 if (klass->exception_type == MONO_EXCEPTION_NONE)
1973 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1974 mono_domain_unlock (domain);
1975 mono_loader_unlock ();
1977 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1983 * For some classes, mono_class_init () already computed klass->vtable_size, and
1984 * that is all that is needed because of the vtable trampolines.
1986 if (!klass->vtable_size)
1987 mono_class_setup_vtable (klass);
1989 if (klass->generic_class && !klass->vtable)
1990 mono_class_check_vtable_constraints (klass, NULL);
1992 /* Initialize klass->has_finalize */
1993 mono_class_has_finalizer (klass);
1995 if (klass->exception_type) {
1996 mono_domain_unlock (domain);
1997 mono_loader_unlock ();
1999 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2003 vtable_slots = klass->vtable_size;
2004 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2005 class_size = mono_class_data_size (klass);
2009 if (klass->interface_offsets_count) {
2010 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2011 mono_stats.imt_number_of_tables++;
2012 mono_stats.imt_tables_size += imt_table_bytes;
2014 imt_table_bytes = 0;
2017 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2019 mono_stats.used_class_count++;
2020 mono_stats.class_vtable_size += vtable_size;
2022 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2023 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2024 g_assert (!((gsize)vt & 7));
2027 vt->rank = klass->rank;
2028 vt->domain = domain;
2030 mono_class_compute_gc_descriptor (klass);
2032 * We can't use typed allocation in the non-root domains, since the
2033 * collector needs the GC descriptor stored in the vtable even after
2034 * the mempool containing the vtable is destroyed when the domain is
2035 * unloaded. An alternative might be to allocate vtables in the GC
2036 * heap, but this does not seem to work (it leads to crashes inside
2037 * libgc). If that approach is tried, two gc descriptors need to be
2038 * allocated for each class: one for the root domain, and one for all
2039 * other domains. The second descriptor should contain a bit for the
2040 * vtable field in MonoObject, since we can no longer assume the
2041 * vtable is reachable by other roots after the appdomain is unloaded.
2043 #ifdef HAVE_BOEHM_GC
2044 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2045 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2048 vt->gc_descr = klass->gc_descr;
2050 gc_bits = mono_gc_get_vtable_bits (klass);
2051 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2053 vt->gc_bits = gc_bits;
2056 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2057 if (klass->has_static_refs) {
2058 MonoGCDescriptor statics_gc_descr;
2060 gsize default_bitmap [4] = {0};
2063 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2064 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2065 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2066 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2067 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2068 if (bitmap != default_bitmap)
2071 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2073 vt->has_static_fields = TRUE;
2074 mono_stats.class_static_data_size += class_size;
2078 while ((field = mono_class_get_fields (klass, &iter))) {
2079 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2081 if (mono_field_is_deleted (field))
2083 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2084 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2085 if (special_static != SPECIAL_STATIC_NONE) {
2086 guint32 size, offset;
2088 gsize default_bitmap [4] = {0};
2093 if (mono_type_is_reference (field->type)) {
2094 default_bitmap [0] = 1;
2096 bitmap = default_bitmap;
2097 } else if (mono_type_is_struct (field->type)) {
2098 fclass = mono_class_from_mono_type (field->type);
2099 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2100 numbits = max_set + 1;
2102 default_bitmap [0] = 0;
2104 bitmap = default_bitmap;
2106 size = mono_type_size (field->type, &align);
2107 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2108 if (!domain->special_static_fields)
2109 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2110 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2111 if (bitmap != default_bitmap)
2114 * This marks the field as special static to speed up the
2115 * checks in mono_field_static_get/set_value ().
2121 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2122 MonoClass *fklass = mono_class_from_mono_type (field->type);
2123 const char *data = mono_field_get_data (field);
2125 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2126 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2127 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2130 if (fklass->valuetype) {
2131 memcpy (t, data, mono_class_value_size (fklass, NULL));
2133 /* it's a pointer type: add check */
2134 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2141 vt->max_interface_id = klass->max_interface_id;
2142 vt->interface_bitmap = klass->interface_bitmap;
2144 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2145 // class->name, klass->interface_offsets_count);
2147 /* Initialize vtable */
2148 if (callbacks.get_vtable_trampoline) {
2149 // This also covers the AOT case
2150 for (i = 0; i < klass->vtable_size; ++i) {
2151 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2154 mono_class_setup_vtable (klass);
2156 for (i = 0; i < klass->vtable_size; ++i) {
2159 if ((cm = klass->vtable [i]))
2160 vt->vtable [i] = arch_create_jit_trampoline (cm);
2164 if (imt_table_bytes) {
2165 /* Now that the vtable is full, we can actually fill up the IMT */
2166 for (i = 0; i < MONO_IMT_SIZE; ++i)
2167 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2171 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2172 * re-acquire them and check if another thread has created the vtable in the meantime.
2174 /* Special case System.MonoType to avoid infinite recursion */
2175 if (klass != mono_defaults.monotype_class) {
2176 /*FIXME check for OOM*/
2177 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2178 mono_error_raise_exception (&error); /* FIXME don't raise here */
2180 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2181 /* This is unregistered in
2182 unregister_vtable_reflection_type() in
2184 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2187 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2189 /* class_vtable_array keeps an array of created vtables
2191 g_ptr_array_add (domain->class_vtable_array, vt);
2192 /* klass->runtime_info is protected by the loader lock, both when
2193 * it it enlarged and when it is stored info.
2197 * Store the vtable in klass->runtime_info.
2198 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2200 mono_memory_barrier ();
2202 old_info = klass->runtime_info;
2203 if (old_info && old_info->max_domain >= domain->domain_id) {
2204 /* someone already created a large enough runtime info */
2205 old_info->domain_vtables [domain->domain_id] = vt;
2207 int new_size = domain->domain_id;
2209 new_size = MAX (new_size, old_info->max_domain);
2211 /* make the new size a power of two */
2213 while (new_size > i)
2216 /* this is a bounded memory retention issue: may want to
2217 * handle it differently when we'll have a rcu-like system.
2219 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2220 runtime_info->max_domain = new_size - 1;
2221 /* copy the stuff from the older info */
2223 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2225 runtime_info->domain_vtables [domain->domain_id] = vt;
2227 mono_memory_barrier ();
2228 klass->runtime_info = runtime_info;
2231 if (klass == mono_defaults.monotype_class) {
2232 /*FIXME check for OOM*/
2233 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2234 mono_error_raise_exception (&error); /* FIXME don't raise here */
2236 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2237 /* This is unregistered in
2238 unregister_vtable_reflection_type() in
2240 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2243 mono_domain_unlock (domain);
2244 mono_loader_unlock ();
2246 /* make sure the parent is initialized */
2247 /*FIXME shouldn't this fail the current type?*/
2249 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2254 #ifndef DISABLE_REMOTING
2256 * mono_class_proxy_vtable:
2257 * @domain: the application domain
2258 * @remove_class: the remote class
2260 * Creates a vtable for transparent proxies. It is basically
2261 * a copy of the real vtable of the class wrapped in @remote_class,
2262 * but all function pointers invoke the remoting functions, and
2263 * vtable->klass points to the transparent proxy class, and not to @class.
2266 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2268 MONO_REQ_GC_UNSAFE_MODE;
2271 MonoVTable *vt, *pvt;
2272 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2274 GSList *extra_interfaces = NULL;
2275 MonoClass *klass = remote_class->proxy_class;
2276 gpointer *interface_offsets;
2279 size_t imt_table_bytes;
2281 #ifdef COMPRESSED_INTERFACE_BITMAP
2285 vt = mono_class_vtable (domain, klass);
2286 g_assert (vt); /*FIXME property handle failure*/
2287 max_interface_id = vt->max_interface_id;
2289 /* Calculate vtable space for extra interfaces */
2290 for (j = 0; j < remote_class->interface_count; j++) {
2291 MonoClass* iclass = remote_class->interfaces[j];
2295 /*FIXME test for interfaces with variant generic arguments*/
2296 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2297 continue; /* interface implemented by the class */
2298 if (g_slist_find (extra_interfaces, iclass))
2301 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2303 method_count = mono_class_num_methods (iclass);
2305 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2306 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2308 for (i = 0; i < ifaces->len; ++i) {
2309 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2310 /*FIXME test for interfaces with variant generic arguments*/
2311 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2312 continue; /* interface implemented by the class */
2313 if (g_slist_find (extra_interfaces, ic))
2315 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2316 method_count += mono_class_num_methods (ic);
2318 g_ptr_array_free (ifaces, TRUE);
2321 extra_interface_vtsize += method_count * sizeof (gpointer);
2322 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2325 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2326 mono_stats.imt_number_of_tables++;
2327 mono_stats.imt_tables_size += imt_table_bytes;
2329 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2331 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2333 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2334 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2335 g_assert (!((gsize)pvt & 7));
2337 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2339 pvt->klass = mono_defaults.transparent_proxy_class;
2340 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2341 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2343 /* initialize vtable */
2344 mono_class_setup_vtable (klass);
2345 for (i = 0; i < klass->vtable_size; ++i) {
2348 if ((cm = klass->vtable [i]))
2349 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2351 pvt->vtable [i] = NULL;
2354 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2355 /* create trampolines for abstract methods */
2356 for (k = klass; k; k = k->parent) {
2358 gpointer iter = NULL;
2359 while ((m = mono_class_get_methods (k, &iter)))
2360 if (!pvt->vtable [m->slot])
2361 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2365 pvt->max_interface_id = max_interface_id;
2366 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2367 #ifdef COMPRESSED_INTERFACE_BITMAP
2368 bitmap = (uint8_t *)g_malloc0 (bsize);
2370 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2373 for (i = 0; i < klass->interface_offsets_count; ++i) {
2374 int interface_id = klass->interfaces_packed [i]->interface_id;
2375 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2378 if (extra_interfaces) {
2379 int slot = klass->vtable_size;
2385 /* Create trampolines for the methods of the interfaces */
2386 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2387 interf = (MonoClass *)list_item->data;
2389 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2393 while ((cm = mono_class_get_methods (interf, &iter)))
2394 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2396 slot += mono_class_num_methods (interf);
2400 /* Now that the vtable is full, we can actually fill up the IMT */
2401 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2402 if (extra_interfaces) {
2403 g_slist_free (extra_interfaces);
2406 #ifdef COMPRESSED_INTERFACE_BITMAP
2407 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2408 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2409 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2412 pvt->interface_bitmap = bitmap;
2417 #endif /* DISABLE_REMOTING */
2420 * mono_class_field_is_special_static:
2422 * Returns whether @field is a thread/context static field.
2425 mono_class_field_is_special_static (MonoClassField *field)
2427 MONO_REQ_GC_NEUTRAL_MODE
2429 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2431 if (mono_field_is_deleted (field))
2433 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2434 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2441 * mono_class_field_get_special_static_type:
2442 * @field: The MonoClassField describing the field.
2444 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2445 * SPECIAL_STATIC_NONE otherwise.
2448 mono_class_field_get_special_static_type (MonoClassField *field)
2450 MONO_REQ_GC_NEUTRAL_MODE
2452 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2453 return SPECIAL_STATIC_NONE;
2454 if (mono_field_is_deleted (field))
2455 return SPECIAL_STATIC_NONE;
2456 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2457 return field_is_special_static (field->parent, field);
2458 return SPECIAL_STATIC_NONE;
2462 * mono_class_has_special_static_fields:
2464 * Returns whenever @klass has any thread/context static fields.
2467 mono_class_has_special_static_fields (MonoClass *klass)
2469 MONO_REQ_GC_NEUTRAL_MODE
2471 MonoClassField *field;
2475 while ((field = mono_class_get_fields (klass, &iter))) {
2476 g_assert (field->parent == klass);
2477 if (mono_class_field_is_special_static (field))
2484 #ifndef DISABLE_REMOTING
2486 * create_remote_class_key:
2487 * Creates an array of pointers that can be used as a hash key for a remote class.
2488 * The first element of the array is the number of pointers.
2491 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2493 MONO_REQ_GC_NEUTRAL_MODE;
2498 if (remote_class == NULL) {
2499 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2500 key = (void **)g_malloc (sizeof(gpointer) * 3);
2501 key [0] = GINT_TO_POINTER (2);
2502 key [1] = mono_defaults.marshalbyrefobject_class;
2503 key [2] = extra_class;
2505 key = (void **)g_malloc (sizeof(gpointer) * 2);
2506 key [0] = GINT_TO_POINTER (1);
2507 key [1] = extra_class;
2510 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2511 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2512 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2513 key [1] = remote_class->proxy_class;
2515 // Keep the list of interfaces sorted
2516 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2517 if (extra_class && remote_class->interfaces [i] > extra_class) {
2518 key [j++] = extra_class;
2521 key [j] = remote_class->interfaces [i];
2524 key [j] = extra_class;
2526 // Replace the old class. The interface list is the same
2527 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2528 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2529 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2530 for (i = 0; i < remote_class->interface_count; i++)
2531 key [2 + i] = remote_class->interfaces [i];
2539 * copy_remote_class_key:
2541 * Make a copy of KEY in the domain and return the copy.
2544 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2546 MONO_REQ_GC_NEUTRAL_MODE
2548 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2549 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2551 memcpy (mp_key, key, key_size);
2557 * mono_remote_class:
2558 * @domain: the application domain
2559 * @class_name: name of the remote class
2561 * Creates and initializes a MonoRemoteClass object for a remote type.
2563 * Can raise an exception on failure.
2566 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2568 MONO_REQ_GC_UNSAFE_MODE;
2571 MonoRemoteClass *rc;
2572 gpointer* key, *mp_key;
2575 key = create_remote_class_key (NULL, proxy_class);
2577 mono_domain_lock (domain);
2578 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2582 mono_domain_unlock (domain);
2586 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2587 if (!mono_error_ok (&error)) {
2589 mono_domain_unlock (domain);
2590 mono_error_raise_exception (&error);
2593 mp_key = copy_remote_class_key (domain, key);
2597 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2598 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2599 rc->interface_count = 1;
2600 rc->interfaces [0] = proxy_class;
2601 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2603 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2604 rc->interface_count = 0;
2605 rc->proxy_class = proxy_class;
2608 rc->default_vtable = NULL;
2609 rc->xdomain_vtable = NULL;
2610 rc->proxy_class_name = name;
2611 #ifndef DISABLE_PERFCOUNTERS
2612 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2615 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2617 mono_domain_unlock (domain);
2622 * clone_remote_class:
2623 * Creates a copy of the remote_class, adding the provided class or interface
2625 static MonoRemoteClass*
2626 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2628 MONO_REQ_GC_NEUTRAL_MODE;
2630 MonoRemoteClass *rc;
2631 gpointer* key, *mp_key;
2633 key = create_remote_class_key (remote_class, extra_class);
2634 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2640 mp_key = copy_remote_class_key (domain, key);
2644 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2646 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2647 rc->proxy_class = remote_class->proxy_class;
2648 rc->interface_count = remote_class->interface_count + 1;
2650 // Keep the list of interfaces sorted, since the hash key of
2651 // the remote class depends on this
2652 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2653 if (remote_class->interfaces [i] > extra_class && i == j)
2654 rc->interfaces [j++] = extra_class;
2655 rc->interfaces [j] = remote_class->interfaces [i];
2658 rc->interfaces [j] = extra_class;
2660 // Replace the old class. The interface array is the same
2661 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2662 rc->proxy_class = extra_class;
2663 rc->interface_count = remote_class->interface_count;
2664 if (rc->interface_count > 0)
2665 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2668 rc->default_vtable = NULL;
2669 rc->xdomain_vtable = NULL;
2670 rc->proxy_class_name = remote_class->proxy_class_name;
2672 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2678 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2680 MONO_REQ_GC_UNSAFE_MODE;
2682 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2683 mono_domain_lock (domain);
2684 if (rp->target_domain_id != -1) {
2685 if (remote_class->xdomain_vtable == NULL)
2686 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2687 mono_domain_unlock (domain);
2688 mono_loader_unlock ();
2689 return remote_class->xdomain_vtable;
2691 if (remote_class->default_vtable == NULL) {
2694 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2695 klass = mono_class_from_mono_type (type);
2697 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)))
2698 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2701 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2704 mono_domain_unlock (domain);
2705 mono_loader_unlock ();
2706 return remote_class->default_vtable;
2710 * mono_upgrade_remote_class:
2711 * @domain: the application domain
2712 * @tproxy: the proxy whose remote class has to be upgraded.
2713 * @klass: class to which the remote class can be casted.
2715 * Updates the vtable of the remote class by adding the necessary method slots
2716 * and interface offsets so it can be safely casted to klass. klass can be a
2717 * class or an interface.
2720 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2722 MONO_REQ_GC_UNSAFE_MODE;
2724 MonoTransparentProxy *tproxy;
2725 MonoRemoteClass *remote_class;
2726 gboolean redo_vtable;
2728 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2729 mono_domain_lock (domain);
2731 tproxy = (MonoTransparentProxy*) proxy_object;
2732 remote_class = tproxy->remote_class;
2734 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2737 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2738 if (remote_class->interfaces [i] == klass)
2739 redo_vtable = FALSE;
2742 redo_vtable = (remote_class->proxy_class != klass);
2746 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2747 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2750 mono_domain_unlock (domain);
2751 mono_loader_unlock ();
2753 #endif /* DISABLE_REMOTING */
2757 * mono_object_get_virtual_method:
2758 * @obj: object to operate on.
2761 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2762 * the instance of a callvirt of method.
2765 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2767 MONO_REQ_GC_UNSAFE_MODE;
2770 MonoMethod **vtable;
2771 gboolean is_proxy = FALSE;
2772 MonoMethod *res = NULL;
2774 klass = mono_object_class (obj);
2775 #ifndef DISABLE_REMOTING
2776 if (klass == mono_defaults.transparent_proxy_class) {
2777 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2782 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2785 mono_class_setup_vtable (klass);
2786 vtable = klass->vtable;
2788 if (method->slot == -1) {
2789 /* method->slot might not be set for instances of generic methods */
2790 if (method->is_inflated) {
2791 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2792 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2795 g_assert_not_reached ();
2799 /* check method->slot is a valid index: perform isinstance? */
2800 if (method->slot != -1) {
2801 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2803 gboolean variance_used = FALSE;
2804 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2805 g_assert (iface_offset > 0);
2806 res = vtable [iface_offset + method->slot];
2809 res = vtable [method->slot];
2813 #ifndef DISABLE_REMOTING
2815 /* It may be an interface, abstract class method or generic method */
2816 if (!res || mono_method_signature (res)->generic_param_count)
2819 /* generic methods demand invoke_with_check */
2820 if (mono_method_signature (res)->generic_param_count)
2821 res = mono_marshal_get_remoting_invoke_with_check (res);
2824 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2825 res = mono_cominterop_get_invoke (res);
2828 res = mono_marshal_get_remoting_invoke (res);
2833 if (method->is_inflated) {
2835 /* Have to inflate the result */
2836 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2837 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2847 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2849 MONO_REQ_GC_UNSAFE_MODE;
2851 MonoObject *result = NULL;
2853 g_assert (callbacks.runtime_invoke);
2855 mono_error_init (error);
2857 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2858 mono_profiler_method_start_invoke (method);
2860 MONO_PREPARE_RESET_BLOCKING;
2862 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2864 MONO_FINISH_RESET_BLOCKING;
2866 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2867 mono_profiler_method_end_invoke (method);
2869 if (!mono_error_ok (error))
2876 * mono_runtime_invoke:
2877 * @method: method to invoke
2878 * @obJ: object instance
2879 * @params: arguments to the method
2880 * @exc: exception information.
2882 * Invokes the method represented by @method on the object @obj.
2884 * obj is the 'this' pointer, it should be NULL for static
2885 * methods, a MonoObject* for object instances and a pointer to
2886 * the value type for value types.
2888 * The params array contains the arguments to the method with the
2889 * same convention: MonoObject* pointers for object instances and
2890 * pointers to the value type otherwise.
2892 * From unmanaged code you'll usually use the
2893 * mono_runtime_invoke() variant.
2895 * Note that this function doesn't handle virtual methods for
2896 * you, it will exec the exact method you pass: we still need to
2897 * expose a function to lookup the derived class implementation
2898 * of a virtual method (there are examples of this in the code,
2901 * You can pass NULL as the exc argument if you don't want to
2902 * catch exceptions, otherwise, *exc will be set to the exception
2903 * thrown, if any. if an exception is thrown, you can't use the
2904 * MonoObject* result from the function.
2906 * If the method returns a value type, it is boxed in an object
2910 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2915 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2916 if (*exc == NULL && !mono_error_ok(&error)) {
2917 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2920 res = mono_runtime_invoke_checked (method, obj, params, &error);
2921 mono_error_raise_exception (&error);
2927 * mono_runtime_try_invoke:
2928 * @method: method to invoke
2929 * @obJ: object instance
2930 * @params: arguments to the method
2931 * @exc: exception information.
2932 * @error: set on error
2934 * Invokes the method represented by @method on the object @obj.
2936 * obj is the 'this' pointer, it should be NULL for static
2937 * methods, a MonoObject* for object instances and a pointer to
2938 * the value type for value types.
2940 * The params array contains the arguments to the method with the
2941 * same convention: MonoObject* pointers for object instances and
2942 * pointers to the value type otherwise.
2944 * From unmanaged code you'll usually use the
2945 * mono_runtime_invoke() variant.
2947 * Note that this function doesn't handle virtual methods for
2948 * you, it will exec the exact method you pass: we still need to
2949 * expose a function to lookup the derived class implementation
2950 * of a virtual method (there are examples of this in the code,
2953 * For this function, you must not pass NULL as the exc argument if
2954 * you don't want to catch exceptions, use
2955 * mono_runtime_invoke_checked(). If an exception is thrown, you
2956 * can't use the MonoObject* result from the function.
2958 * If this method cannot be invoked, @error will be set and @exc and
2959 * the return value must not be used.
2961 * If the method returns a value type, it is boxed in an object
2965 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2967 MONO_REQ_GC_UNSAFE_MODE;
2969 g_assert (exc != NULL);
2971 if (mono_runtime_get_no_exec ())
2972 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2974 return do_runtime_invoke (method, obj, params, exc, error);
2978 * mono_runtime_invoke_checked:
2979 * @method: method to invoke
2980 * @obJ: object instance
2981 * @params: arguments to the method
2982 * @error: set on error
2984 * Invokes the method represented by @method on the object @obj.
2986 * obj is the 'this' pointer, it should be NULL for static
2987 * methods, a MonoObject* for object instances and a pointer to
2988 * the value type for value types.
2990 * The params array contains the arguments to the method with the
2991 * same convention: MonoObject* pointers for object instances and
2992 * pointers to the value type otherwise.
2994 * From unmanaged code you'll usually use the
2995 * mono_runtime_invoke() variant.
2997 * Note that this function doesn't handle virtual methods for
2998 * you, it will exec the exact method you pass: we still need to
2999 * expose a function to lookup the derived class implementation
3000 * of a virtual method (there are examples of this in the code,
3003 * If an exception is thrown, you can't use the MonoObject* result
3004 * from the function.
3006 * If this method cannot be invoked, @error will be set. If the
3007 * method throws an exception (and we're in coop mode) the exception
3008 * will be set in @error.
3010 * If the method returns a value type, it is boxed in an object
3014 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3016 MONO_REQ_GC_UNSAFE_MODE;
3018 if (mono_runtime_get_no_exec ())
3019 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3021 return do_runtime_invoke (method, obj, params, NULL, error);
3025 * mono_method_get_unmanaged_thunk:
3026 * @method: method to generate a thunk for.
3028 * Returns an unmanaged->managed thunk that can be used to call
3029 * a managed method directly from C.
3031 * The thunk's C signature closely matches the managed signature:
3033 * C#: public bool Equals (object obj);
3034 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3035 * MonoObject*, MonoException**);
3037 * The 1st ("this") parameter must not be used with static methods:
3039 * C#: public static bool ReferenceEquals (object a, object b);
3040 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3043 * The last argument must be a non-null pointer of a MonoException* pointer.
3044 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3045 * exception has been thrown in managed code. Otherwise it will point
3046 * to the MonoException* caught by the thunk. In this case, the result of
3047 * the thunk is undefined:
3049 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3050 * MonoException *ex = NULL;
3051 * Equals func = mono_method_get_unmanaged_thunk (method);
3052 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3054 * // handle exception
3057 * The calling convention of the thunk matches the platform's default
3058 * convention. This means that under Windows, C declarations must
3059 * contain the __stdcall attribute:
3061 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3062 * MonoObject*, MonoException**);
3066 * Value type arguments and return values are treated as they were objects:
3068 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3069 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3071 * Arguments must be properly boxed upon trunk's invocation, while return
3072 * values must be unboxed.
3075 mono_method_get_unmanaged_thunk (MonoMethod *method)
3077 MONO_REQ_GC_NEUTRAL_MODE;
3078 MONO_REQ_API_ENTRYPOINT;
3082 MONO_PREPARE_RESET_BLOCKING;
3083 method = mono_marshal_get_thunk_invoke_wrapper (method);
3084 res = mono_compile_method (method);
3085 MONO_FINISH_RESET_BLOCKING;
3091 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3093 MONO_REQ_GC_UNSAFE_MODE;
3097 /* object fields cannot be byref, so we don't need a
3099 gpointer *p = (gpointer*)dest;
3106 case MONO_TYPE_BOOLEAN:
3108 case MONO_TYPE_U1: {
3109 guint8 *p = (guint8*)dest;
3110 *p = value ? *(guint8*)value : 0;
3115 case MONO_TYPE_CHAR: {
3116 guint16 *p = (guint16*)dest;
3117 *p = value ? *(guint16*)value : 0;
3120 #if SIZEOF_VOID_P == 4
3125 case MONO_TYPE_U4: {
3126 gint32 *p = (gint32*)dest;
3127 *p = value ? *(gint32*)value : 0;
3130 #if SIZEOF_VOID_P == 8
3135 case MONO_TYPE_U8: {
3136 gint64 *p = (gint64*)dest;
3137 *p = value ? *(gint64*)value : 0;
3140 case MONO_TYPE_R4: {
3141 float *p = (float*)dest;
3142 *p = value ? *(float*)value : 0;
3145 case MONO_TYPE_R8: {
3146 double *p = (double*)dest;
3147 *p = value ? *(double*)value : 0;
3150 case MONO_TYPE_STRING:
3151 case MONO_TYPE_SZARRAY:
3152 case MONO_TYPE_CLASS:
3153 case MONO_TYPE_OBJECT:
3154 case MONO_TYPE_ARRAY:
3155 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3157 case MONO_TYPE_FNPTR:
3158 case MONO_TYPE_PTR: {
3159 gpointer *p = (gpointer*)dest;
3160 *p = deref_pointer? *(gpointer*)value: value;
3163 case MONO_TYPE_VALUETYPE:
3164 /* note that 't' and 'type->type' can be different */
3165 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3166 t = mono_class_enum_basetype (type->data.klass)->type;
3169 MonoClass *klass = mono_class_from_mono_type (type);
3170 int size = mono_class_value_size (klass, NULL);
3172 mono_gc_bzero_atomic (dest, size);
3174 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3177 case MONO_TYPE_GENERICINST:
3178 t = type->data.generic_class->container_class->byval_arg.type;
3181 g_error ("got type %x", type->type);
3186 * mono_field_set_value:
3187 * @obj: Instance object
3188 * @field: MonoClassField describing the field to set
3189 * @value: The value to be set
3191 * Sets the value of the field described by @field in the object instance @obj
3192 * to the value passed in @value. This method should only be used for instance
3193 * fields. For static fields, use mono_field_static_set_value.
3195 * The value must be on the native format of the field type.
3198 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3200 MONO_REQ_GC_UNSAFE_MODE;
3204 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3206 dest = (char*)obj + field->offset;
3207 mono_copy_value (field->type, dest, value, FALSE);
3211 * mono_field_static_set_value:
3212 * @field: MonoClassField describing the field to set
3213 * @value: The value to be set
3215 * Sets the value of the static field described by @field
3216 * to the value passed in @value.
3218 * The value must be on the native format of the field type.
3221 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3223 MONO_REQ_GC_UNSAFE_MODE;
3227 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3228 /* you cant set a constant! */
3229 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3231 if (field->offset == -1) {
3232 /* Special static */
3235 mono_domain_lock (vt->domain);
3236 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3237 mono_domain_unlock (vt->domain);
3238 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3240 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3242 mono_copy_value (field->type, dest, value, FALSE);
3246 * mono_vtable_get_static_field_data:
3248 * Internal use function: return a pointer to the memory holding the static fields
3249 * for a class or NULL if there are no static fields.
3250 * This is exported only for use by the debugger.
3253 mono_vtable_get_static_field_data (MonoVTable *vt)
3255 MONO_REQ_GC_NEUTRAL_MODE
3257 if (!vt->has_static_fields)
3259 return vt->vtable [vt->klass->vtable_size];
3263 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3265 MONO_REQ_GC_UNSAFE_MODE;
3269 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3270 if (field->offset == -1) {
3271 /* Special static */
3274 mono_domain_lock (vt->domain);
3275 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3276 mono_domain_unlock (vt->domain);
3277 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3279 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3282 src = (guint8*)obj + field->offset;
3289 * mono_field_get_value:
3290 * @obj: Object instance
3291 * @field: MonoClassField describing the field to fetch information from
3292 * @value: pointer to the location where the value will be stored
3294 * Use this routine to get the value of the field @field in the object
3297 * The pointer provided by value must be of the field type, for reference
3298 * types this is a MonoObject*, for value types its the actual pointer to
3303 * mono_field_get_value (obj, int_field, &i);
3306 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3308 MONO_REQ_GC_UNSAFE_MODE;
3314 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3316 src = (char*)obj + field->offset;
3317 mono_copy_value (field->type, value, src, TRUE);
3321 * mono_field_get_value_object:
3322 * @domain: domain where the object will be created (if boxing)
3323 * @field: MonoClassField describing the field to fetch information from
3324 * @obj: The object instance for the field.
3326 * Returns: a new MonoObject with the value from the given field. If the
3327 * field represents a value type, the value is boxed.
3331 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3333 MONO_REQ_GC_UNSAFE_MODE;
3338 MonoVTable *vtable = NULL;
3340 gboolean is_static = FALSE;
3341 gboolean is_ref = FALSE;
3342 gboolean is_literal = FALSE;
3343 gboolean is_ptr = FALSE;
3344 MonoType *type = mono_field_get_type_checked (field, &error);
3346 if (!mono_error_ok (&error))
3347 mono_error_raise_exception (&error);
3349 switch (type->type) {
3350 case MONO_TYPE_STRING:
3351 case MONO_TYPE_OBJECT:
3352 case MONO_TYPE_CLASS:
3353 case MONO_TYPE_ARRAY:
3354 case MONO_TYPE_SZARRAY:
3359 case MONO_TYPE_BOOLEAN:
3362 case MONO_TYPE_CHAR:
3371 case MONO_TYPE_VALUETYPE:
3372 is_ref = type->byref;
3374 case MONO_TYPE_GENERICINST:
3375 is_ref = !mono_type_generic_inst_is_valuetype (type);
3381 g_error ("type 0x%x not handled in "
3382 "mono_field_get_value_object", type->type);
3386 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3389 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3393 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3394 if (!vtable->initialized)
3395 mono_runtime_class_init (vtable);
3403 get_default_field_value (domain, field, &o);
3404 } else if (is_static) {
3405 mono_field_static_get_value (vtable, field, &o);
3407 mono_field_get_value (obj, field, &o);
3413 static MonoMethod *m;
3419 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3420 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3426 get_default_field_value (domain, field, v);
3427 } else if (is_static) {
3428 mono_field_static_get_value (vtable, field, v);
3430 mono_field_get_value (obj, field, v);
3433 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3434 args [0] = ptr ? *ptr : NULL;
3435 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3436 mono_error_raise_exception (&error); /* FIXME don't raise here */
3438 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3439 mono_error_raise_exception (&error); /* FIXME don't raise here */
3444 /* boxed value type */
3445 klass = mono_class_from_mono_type (type);
3447 if (mono_class_is_nullable (klass))
3448 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3450 o = mono_object_new_checked (domain, klass, &error);
3451 mono_error_raise_exception (&error); /* FIXME don't raise here */
3452 v = ((gchar *) o) + sizeof (MonoObject);
3455 get_default_field_value (domain, field, v);
3456 } else if (is_static) {
3457 mono_field_static_get_value (vtable, field, v);
3459 mono_field_get_value (obj, field, v);
3466 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3468 MONO_REQ_GC_UNSAFE_MODE;
3471 const char *p = blob;
3472 mono_metadata_decode_blob_size (p, &p);
3475 case MONO_TYPE_BOOLEAN:
3478 *(guint8 *) value = *p;
3480 case MONO_TYPE_CHAR:
3483 *(guint16*) value = read16 (p);
3487 *(guint32*) value = read32 (p);
3491 *(guint64*) value = read64 (p);
3494 readr4 (p, (float*) value);
3497 readr8 (p, (double*) value);
3499 case MONO_TYPE_STRING:
3500 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3502 case MONO_TYPE_CLASS:
3503 *(gpointer*) value = NULL;
3507 g_warning ("type 0x%02x should not be in constant table", type);
3513 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3515 MONO_REQ_GC_NEUTRAL_MODE;
3517 MonoTypeEnum def_type;
3520 data = mono_class_get_field_default_value (field, &def_type);
3521 mono_get_constant_value_from_blob (domain, def_type, data, value);
3525 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3527 MONO_REQ_GC_UNSAFE_MODE;
3531 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3533 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3534 get_default_field_value (vt->domain, field, value);
3538 if (field->offset == -1) {
3539 /* Special static */
3540 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3541 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3543 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3545 mono_copy_value (field->type, value, src, TRUE);
3549 * mono_field_static_get_value:
3550 * @vt: vtable to the object
3551 * @field: MonoClassField describing the field to fetch information from
3552 * @value: where the value is returned
3554 * Use this routine to get the value of the static field @field value.
3556 * The pointer provided by value must be of the field type, for reference
3557 * types this is a MonoObject*, for value types its the actual pointer to
3562 * mono_field_static_get_value (vt, int_field, &i);
3565 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3567 MONO_REQ_GC_NEUTRAL_MODE;
3569 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3573 * mono_property_set_value:
3574 * @prop: MonoProperty to set
3575 * @obj: instance object on which to act
3576 * @params: parameters to pass to the propery
3577 * @exc: optional exception
3579 * Invokes the property's set method with the given arguments on the
3580 * object instance obj (or NULL for static properties).
3582 * You can pass NULL as the exc argument if you don't want to
3583 * catch exceptions, otherwise, *exc will be set to the exception
3584 * thrown, if any. if an exception is thrown, you can't use the
3585 * MonoObject* result from the function.
3588 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3590 MONO_REQ_GC_UNSAFE_MODE;
3593 do_runtime_invoke (prop->set, obj, params, exc, &error);
3594 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3595 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3597 mono_error_raise_exception (&error); /* FIXME don't raise here */
3602 * mono_property_get_value:
3603 * @prop: MonoProperty to fetch
3604 * @obj: instance object on which to act
3605 * @params: parameters to pass to the propery
3606 * @exc: optional exception
3608 * Invokes the property's get method with the given arguments on the
3609 * object instance obj (or NULL for static properties).
3611 * You can pass NULL as the exc argument if you don't want to
3612 * catch exceptions, otherwise, *exc will be set to the exception
3613 * thrown, if any. if an exception is thrown, you can't use the
3614 * MonoObject* result from the function.
3616 * Returns: the value from invoking the get method on the property.
3619 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3621 MONO_REQ_GC_UNSAFE_MODE;
3624 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3625 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3626 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3628 mono_error_raise_exception (&error); /* FIXME don't raise here */
3635 * mono_nullable_init:
3636 * @buf: The nullable structure to initialize.
3637 * @value: the value to initialize from
3638 * @klass: the type for the object
3640 * Initialize the nullable structure pointed to by @buf from @value which
3641 * should be a boxed value type. The size of @buf should be able to hold
3642 * as much data as the @klass->instance_size (which is the number of bytes
3643 * that will be copies).
3645 * Since Nullables have variable structure, we can not define a C
3646 * structure for them.
3649 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3651 MONO_REQ_GC_UNSAFE_MODE;
3653 MonoClass *param_class = klass->cast_class;
3655 mono_class_setup_fields_locking (klass);
3656 g_assert (klass->fields_inited);
3658 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3659 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3661 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3663 if (param_class->has_references)
3664 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3666 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3668 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3673 * mono_nullable_box:
3674 * @buf: The buffer representing the data to be boxed
3675 * @klass: the type to box it as.
3677 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3681 mono_nullable_box (guint8 *buf, MonoClass *klass)
3683 MONO_REQ_GC_UNSAFE_MODE;
3687 MonoClass *param_class = klass->cast_class;
3689 mono_class_setup_fields_locking (klass);
3690 g_assert (klass->fields_inited);
3692 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3693 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3695 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3696 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3697 mono_error_raise_exception (&error); /* FIXME don't raise here */
3698 if (param_class->has_references)
3699 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3701 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3709 * mono_get_delegate_invoke:
3710 * @klass: The delegate class
3712 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3715 mono_get_delegate_invoke (MonoClass *klass)
3717 MONO_REQ_GC_NEUTRAL_MODE;
3721 /* This is called at runtime, so avoid the slower search in metadata */
3722 mono_class_setup_methods (klass);
3723 if (klass->exception_type)
3725 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3730 * mono_get_delegate_begin_invoke:
3731 * @klass: The delegate class
3733 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3736 mono_get_delegate_begin_invoke (MonoClass *klass)
3738 MONO_REQ_GC_NEUTRAL_MODE;
3742 /* This is called at runtime, so avoid the slower search in metadata */
3743 mono_class_setup_methods (klass);
3744 if (klass->exception_type)
3746 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3751 * mono_get_delegate_end_invoke:
3752 * @klass: The delegate class
3754 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3757 mono_get_delegate_end_invoke (MonoClass *klass)
3759 MONO_REQ_GC_NEUTRAL_MODE;
3763 /* This is called at runtime, so avoid the slower search in metadata */
3764 mono_class_setup_methods (klass);
3765 if (klass->exception_type)
3767 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3772 * mono_runtime_delegate_invoke:
3773 * @delegate: pointer to a delegate object.
3774 * @params: parameters for the delegate.
3775 * @exc: Pointer to the exception result.
3777 * Invokes the delegate method @delegate with the parameters provided.
3779 * You can pass NULL as the exc argument if you don't want to
3780 * catch exceptions, otherwise, *exc will be set to the exception
3781 * thrown, if any. if an exception is thrown, you can't use the
3782 * MonoObject* result from the function.
3785 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3787 MONO_REQ_GC_UNSAFE_MODE;
3791 MonoClass *klass = delegate->vtable->klass;
3794 im = mono_get_delegate_invoke (klass);
3796 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3799 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3800 if (*exc == NULL && !mono_error_ok (&error))
3801 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3803 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3804 mono_error_raise_exception (&error); /* FIXME don't raise here */
3810 static char **main_args = NULL;
3811 static int num_main_args = 0;
3814 * mono_runtime_get_main_args:
3816 * Returns: a MonoArray with the arguments passed to the main program
3819 mono_runtime_get_main_args (void)
3821 MONO_REQ_GC_UNSAFE_MODE;
3825 MonoDomain *domain = mono_domain_get ();
3827 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3829 for (i = 0; i < num_main_args; ++i)
3830 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3836 free_main_args (void)
3838 MONO_REQ_GC_NEUTRAL_MODE;
3842 for (i = 0; i < num_main_args; ++i)
3843 g_free (main_args [i]);
3850 * mono_runtime_set_main_args:
3851 * @argc: number of arguments from the command line
3852 * @argv: array of strings from the command line
3854 * Set the command line arguments from an embedding application that doesn't otherwise call
3855 * mono_runtime_run_main ().
3858 mono_runtime_set_main_args (int argc, char* argv[])
3860 MONO_REQ_GC_NEUTRAL_MODE;
3865 main_args = g_new0 (char*, argc);
3866 num_main_args = argc;
3868 for (i = 0; i < argc; ++i) {
3871 utf8_arg = mono_utf8_from_external (argv[i]);
3872 if (utf8_arg == NULL) {
3873 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3874 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3878 main_args [i] = utf8_arg;
3885 * mono_runtime_run_main:
3886 * @method: the method to start the application with (usually Main)
3887 * @argc: number of arguments from the command line
3888 * @argv: array of strings from the command line
3889 * @exc: excetption results
3891 * Execute a standard Main() method (argc/argv contains the
3892 * executable name). This method also sets the command line argument value
3893 * needed by System.Environment.
3898 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3901 MONO_REQ_GC_UNSAFE_MODE;
3904 MonoArray *args = NULL;
3905 MonoDomain *domain = mono_domain_get ();
3906 gchar *utf8_fullpath;
3907 MonoMethodSignature *sig;
3909 g_assert (method != NULL);
3911 mono_thread_set_main (mono_thread_current ());
3913 main_args = g_new0 (char*, argc);
3914 num_main_args = argc;
3916 if (!g_path_is_absolute (argv [0])) {
3917 gchar *basename = g_path_get_basename (argv [0]);
3918 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3922 utf8_fullpath = mono_utf8_from_external (fullpath);
3923 if(utf8_fullpath == NULL) {
3924 /* Printing the arg text will cause glib to
3925 * whinge about "Invalid UTF-8", but at least
3926 * its relevant, and shows the problem text
3929 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3930 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3937 utf8_fullpath = mono_utf8_from_external (argv[0]);
3938 if(utf8_fullpath == NULL) {
3939 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3940 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3945 main_args [0] = utf8_fullpath;
3947 for (i = 1; i < argc; ++i) {
3950 utf8_arg=mono_utf8_from_external (argv[i]);
3951 if(utf8_arg==NULL) {
3952 /* Ditto the comment about Invalid UTF-8 here */
3953 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3954 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3958 main_args [i] = utf8_arg;
3963 sig = mono_method_signature (method);
3965 g_print ("Unable to load Main method.\n");
3969 if (sig->param_count) {
3970 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3971 for (i = 0; i < argc; ++i) {
3972 /* The encodings should all work, given that
3973 * we've checked all these args for the
3976 gchar *str = mono_utf8_from_external (argv [i]);
3977 MonoString *arg = mono_string_new (domain, str);
3978 mono_array_setref (args, i, arg);
3982 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3985 mono_assembly_set_main (method->klass->image->assembly);
3987 return mono_runtime_exec_main (method, args, exc);
3991 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3993 static MonoMethod *serialize_method;
3999 if (!serialize_method) {
4000 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
4001 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4004 if (!serialize_method) {
4009 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4014 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4015 if (*exc == NULL && !mono_error_ok (&error))
4016 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4025 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4027 MONO_REQ_GC_UNSAFE_MODE;
4029 static MonoMethod *deserialize_method;
4035 if (!deserialize_method) {
4036 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
4037 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4039 if (!deserialize_method) {
4047 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4048 if (*exc == NULL && !mono_error_ok (&error))
4049 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4057 #ifndef DISABLE_REMOTING
4059 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4061 MONO_REQ_GC_UNSAFE_MODE;
4063 static MonoMethod *get_proxy_method;
4066 MonoDomain *domain = mono_domain_get ();
4067 MonoRealProxy *real_proxy;
4068 MonoReflectionType *reflection_type;
4069 MonoTransparentProxy *transparent_proxy;
4071 if (!get_proxy_method)
4072 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4074 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4076 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4077 mono_error_raise_exception (&error); /* FIXME don't raise here */
4078 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4079 mono_error_raise_exception (&error); /* FIXME don't raise here */
4081 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4082 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4086 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4087 if (*exc == NULL && !mono_error_ok (&error))
4088 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4092 return (MonoObject*) transparent_proxy;
4094 #endif /* DISABLE_REMOTING */
4097 * mono_object_xdomain_representation
4099 * @target_domain: a domain
4100 * @exc: pointer to a MonoObject*
4102 * Creates a representation of obj in the domain target_domain. This
4103 * is either a copy of obj arrived through via serialization and
4104 * deserialization or a proxy, depending on whether the object is
4105 * serializable or marshal by ref. obj must not be in target_domain.
4107 * If the object cannot be represented in target_domain, NULL is
4108 * returned and *exc is set to an appropriate exception.
4111 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4113 MONO_REQ_GC_UNSAFE_MODE;
4115 MonoObject *deserialized = NULL;
4116 gboolean failure = FALSE;
4118 g_assert (exc != NULL);
4121 #ifndef DISABLE_REMOTING
4122 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4123 deserialized = make_transparent_proxy (obj, &failure, exc);
4128 MonoDomain *domain = mono_domain_get ();
4129 MonoObject *serialized;
4131 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4132 serialized = serialize_object (obj, &failure, exc);
4133 mono_domain_set_internal_with_options (target_domain, FALSE);
4135 deserialized = deserialize_object (serialized, &failure, exc);
4136 if (domain != target_domain)
4137 mono_domain_set_internal_with_options (domain, FALSE);
4140 return deserialized;
4143 /* Used in call_unhandled_exception_delegate */
4145 create_unhandled_exception_eventargs (MonoObject *exc)
4147 MONO_REQ_GC_UNSAFE_MODE;
4152 MonoMethod *method = NULL;
4153 MonoBoolean is_terminating = TRUE;
4156 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
4159 mono_class_init (klass);
4161 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4162 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4166 args [1] = &is_terminating;
4168 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4169 mono_error_raise_exception (&error); /* FIXME don't raise here */
4171 mono_runtime_invoke_checked (method, obj, args, &error);
4172 mono_error_raise_exception (&error); /* FIXME don't raise here */
4177 /* Used in mono_unhandled_exception */
4179 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4180 MONO_REQ_GC_UNSAFE_MODE;
4182 MonoObject *e = NULL;
4184 MonoDomain *current_domain = mono_domain_get ();
4186 if (domain != current_domain)
4187 mono_domain_set_internal_with_options (domain, FALSE);
4189 g_assert (domain == mono_object_domain (domain->domain));
4191 if (mono_object_domain (exc) != domain) {
4192 MonoObject *serialization_exc;
4194 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4196 if (serialization_exc) {
4198 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4201 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4202 "System.Runtime.Serialization", "SerializationException",
4203 "Could not serialize unhandled exception.");
4207 g_assert (mono_object_domain (exc) == domain);
4209 pa [0] = domain->domain;
4210 pa [1] = create_unhandled_exception_eventargs (exc);
4211 mono_runtime_delegate_invoke (delegate, pa, &e);
4213 if (domain != current_domain)
4214 mono_domain_set_internal_with_options (current_domain, FALSE);
4218 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4219 if (!mono_error_ok (&error)) {
4220 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4221 mono_error_cleanup (&error);
4223 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4229 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4232 * mono_runtime_unhandled_exception_policy_set:
4233 * @policy: the new policy
4235 * This is a VM internal routine.
4237 * Sets the runtime policy for handling unhandled exceptions.
4240 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4241 runtime_unhandled_exception_policy = policy;
4245 * mono_runtime_unhandled_exception_policy_get:
4247 * This is a VM internal routine.
4249 * Gets the runtime policy for handling unhandled exceptions.
4251 MonoRuntimeUnhandledExceptionPolicy
4252 mono_runtime_unhandled_exception_policy_get (void) {
4253 return runtime_unhandled_exception_policy;
4257 * mono_unhandled_exception:
4258 * @exc: exception thrown
4260 * This is a VM internal routine.
4262 * We call this function when we detect an unhandled exception
4263 * in the default domain.
4265 * It invokes the * UnhandledException event in AppDomain or prints
4266 * a warning to the console
4269 mono_unhandled_exception (MonoObject *exc)
4271 MONO_REQ_GC_UNSAFE_MODE;
4273 MonoClassField *field;
4274 MonoDomain *current_domain, *root_domain;
4275 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4277 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4280 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4283 current_domain = mono_domain_get ();
4284 root_domain = mono_get_root_domain ();
4286 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4287 if (current_domain != root_domain)
4288 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4290 /* set exitcode only if we will abort the process */
4291 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4292 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4293 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4295 mono_environment_exitcode_set (1);
4298 mono_print_unhandled_exception (exc);
4300 if (root_appdomain_delegate)
4301 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4302 if (current_appdomain_delegate)
4303 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4308 * mono_runtime_exec_managed_code:
4309 * @domain: Application domain
4310 * @main_func: function to invoke from the execution thread
4311 * @main_args: parameter to the main_func
4313 * Launch a new thread to execute a function
4315 * main_func is called back from the thread with main_args as the
4316 * parameter. The callback function is expected to start Main()
4317 * eventually. This function then waits for all managed threads to
4319 * It is not necesseray anymore to execute managed code in a subthread,
4320 * so this function should not be used anymore by default: just
4321 * execute the code and then call mono_thread_manage ().
4324 mono_runtime_exec_managed_code (MonoDomain *domain,
4325 MonoMainThreadFunc main_func,
4328 mono_thread_create (domain, main_func, main_args);
4330 mono_thread_manage ();
4334 * Execute a standard Main() method (args doesn't contain the
4338 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4340 MONO_REQ_GC_UNSAFE_MODE;
4346 MonoCustomAttrInfo* cinfo;
4347 gboolean has_stathread_attribute;
4348 MonoInternalThread* thread = mono_thread_internal_current ();
4354 domain = mono_object_domain (args);
4355 if (!domain->entry_assembly) {
4357 MonoAssembly *assembly;
4359 assembly = method->klass->image->assembly;
4360 domain->entry_assembly = assembly;
4361 /* Domains created from another domain already have application_base and configuration_file set */
4362 if (domain->setup->application_base == NULL) {
4363 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4366 if (domain->setup->configuration_file == NULL) {
4367 str = g_strconcat (assembly->image->name, ".config", NULL);
4368 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4370 mono_domain_set_options_from_config (domain);
4374 cinfo = mono_custom_attrs_from_method (method);
4376 static MonoClass *stathread_attribute = NULL;
4377 if (!stathread_attribute)
4378 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4379 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4381 mono_custom_attrs_free (cinfo);
4383 has_stathread_attribute = FALSE;
4385 if (has_stathread_attribute) {
4386 thread->apartment_state = ThreadApartmentState_STA;
4388 thread->apartment_state = ThreadApartmentState_MTA;
4390 mono_thread_init_apartment_state ();
4392 /* FIXME: check signature of method */
4393 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4396 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4397 if (*exc == NULL && !mono_error_ok (&error))
4398 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4400 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4401 mono_error_raise_exception (&error); /* FIXME don't raise here */
4405 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4409 mono_environment_exitcode_set (rval);
4412 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4413 if (*exc == NULL && !mono_error_ok (&error))
4414 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4416 mono_runtime_invoke_checked (method, NULL, pa, &error);
4417 mono_error_raise_exception (&error); /* FIXME don't raise here */
4423 /* If the return type of Main is void, only
4424 * set the exitcode if an exception was thrown
4425 * (we don't want to blow away an
4426 * explicitly-set exit code)
4429 mono_environment_exitcode_set (rval);
4437 * mono_runtime_invoke_array:
4438 * @method: method to invoke
4439 * @obJ: object instance
4440 * @params: arguments to the method
4441 * @exc: exception information.
4443 * Invokes the method represented by @method on the object @obj.
4445 * obj is the 'this' pointer, it should be NULL for static
4446 * methods, a MonoObject* for object instances and a pointer to
4447 * the value type for value types.
4449 * The params array contains the arguments to the method with the
4450 * same convention: MonoObject* pointers for object instances and
4451 * pointers to the value type otherwise. The _invoke_array
4452 * variant takes a C# object[] as the params argument (MonoArray
4453 * *params): in this case the value types are boxed inside the
4454 * respective reference representation.
4456 * From unmanaged code you'll usually use the
4457 * mono_runtime_invoke_checked() variant.
4459 * Note that this function doesn't handle virtual methods for
4460 * you, it will exec the exact method you pass: we still need to
4461 * expose a function to lookup the derived class implementation
4462 * of a virtual method (there are examples of this in the code,
4465 * You can pass NULL as the exc argument if you don't want to
4466 * catch exceptions, otherwise, *exc will be set to the exception
4467 * thrown, if any. if an exception is thrown, you can't use the
4468 * MonoObject* result from the function.
4470 * If the method returns a value type, it is boxed in an object
4474 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4477 MONO_REQ_GC_UNSAFE_MODE;
4480 MonoMethodSignature *sig = mono_method_signature (method);
4481 gpointer *pa = NULL;
4484 gboolean has_byref_nullables = FALSE;
4486 if (NULL != params) {
4487 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4488 for (i = 0; i < mono_array_length (params); i++) {
4489 MonoType *t = sig->params [i];
4495 case MONO_TYPE_BOOLEAN:
4498 case MONO_TYPE_CHAR:
4507 case MONO_TYPE_VALUETYPE:
4508 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4509 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4510 pa [i] = mono_array_get (params, MonoObject*, i);
4512 has_byref_nullables = TRUE;
4514 /* MS seems to create the objects if a null is passed in */
4515 if (!mono_array_get (params, MonoObject*, i)) {
4516 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4517 mono_error_raise_exception (&error); /* FIXME don't raise here */
4518 mono_array_setref (params, i, o);
4523 * We can't pass the unboxed vtype byref to the callee, since
4524 * that would mean the callee would be able to modify boxed
4525 * primitive types. So we (and MS) make a copy of the boxed
4526 * object, pass that to the callee, and replace the original
4527 * boxed object in the arg array with the copy.
4529 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4530 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4531 mono_array_setref (params, i, copy);
4534 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4537 case MONO_TYPE_STRING:
4538 case MONO_TYPE_OBJECT:
4539 case MONO_TYPE_CLASS:
4540 case MONO_TYPE_ARRAY:
4541 case MONO_TYPE_SZARRAY:
4543 pa [i] = mono_array_addr (params, MonoObject*, i);
4544 // FIXME: I need to check this code path
4546 pa [i] = mono_array_get (params, MonoObject*, i);
4548 case MONO_TYPE_GENERICINST:
4550 t = &t->data.generic_class->container_class->this_arg;
4552 t = &t->data.generic_class->container_class->byval_arg;
4554 case MONO_TYPE_PTR: {
4557 /* The argument should be an IntPtr */
4558 arg = mono_array_get (params, MonoObject*, i);
4562 g_assert (arg->vtable->klass == mono_defaults.int_class);
4563 pa [i] = ((MonoIntPtr*)arg)->m_value;
4568 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4573 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4576 if (mono_class_is_nullable (method->klass)) {
4577 /* Need to create a boxed vtype instead */
4583 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4587 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4588 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4589 #ifndef DISABLE_REMOTING
4590 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4591 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4594 if (method->klass->valuetype)
4595 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4598 } else if (method->klass->valuetype) {
4599 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4603 mono_runtime_try_invoke (method, o, pa, exc, &error);
4604 if (*exc == NULL && !mono_error_ok (&error))
4605 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4607 mono_runtime_invoke_checked (method, o, pa, &error);
4608 mono_error_raise_exception (&error); /* FIXME don't raise here */
4611 return (MonoObject *)obj;
4613 if (mono_class_is_nullable (method->klass)) {
4614 MonoObject *nullable;
4616 /* Convert the unboxed vtype into a Nullable structure */
4617 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4618 mono_error_raise_exception (&error); /* FIXME don't raise here */
4620 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4621 obj = mono_object_unbox (nullable);
4624 /* obj must be already unboxed if needed */
4626 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4627 if (*exc == NULL && !mono_error_ok (&error))
4628 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4630 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4631 mono_error_raise_exception (&error); /* FIXME don't raise here */
4634 if (sig->ret->type == MONO_TYPE_PTR) {
4635 MonoClass *pointer_class;
4636 static MonoMethod *box_method;
4638 MonoObject *box_exc;
4641 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4642 * convert it to a Pointer object.
4644 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4646 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4648 g_assert (res->vtable->klass == mono_defaults.int_class);
4649 box_args [0] = ((MonoIntPtr*)res)->m_value;
4650 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4651 mono_error_raise_exception (&error); /* FIXME don't raise here */
4653 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4654 g_assert (box_exc == NULL);
4655 mono_error_assert_ok (&error);
4658 if (has_byref_nullables) {
4660 * The runtime invoke wrapper already converted byref nullables back,
4661 * and stored them in pa, we just need to copy them back to the
4664 for (i = 0; i < mono_array_length (params); i++) {
4665 MonoType *t = sig->params [i];
4667 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4668 mono_array_setref (params, i, pa [i]);
4678 * @klass: the class of the object that we want to create
4680 * Returns: a newly created object whose definition is
4681 * looked up using @klass. This will not invoke any constructors,
4682 * so the consumer of this routine has to invoke any constructors on
4683 * its own to initialize the object.
4685 * It returns NULL on failure.
4688 mono_object_new (MonoDomain *domain, MonoClass *klass)
4690 MONO_REQ_GC_UNSAFE_MODE;
4694 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4696 mono_error_raise_exception (&error);
4701 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4703 MONO_REQ_GC_UNSAFE_MODE;
4707 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4709 mono_error_raise_exception (&error);
4714 * mono_object_new_checked:
4715 * @klass: the class of the object that we want to create
4716 * @error: set on error
4718 * Returns: a newly created object whose definition is
4719 * looked up using @klass. This will not invoke any constructors,
4720 * so the consumer of this routine has to invoke any constructors on
4721 * its own to initialize the object.
4723 * It returns NULL on failure and sets @error.
4726 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4728 MONO_REQ_GC_UNSAFE_MODE;
4732 vtable = mono_class_vtable (domain, klass);
4733 g_assert (vtable); /* FIXME don't swallow the error */
4735 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4740 * mono_object_new_pinned:
4742 * Same as mono_object_new, but the returned object will be pinned.
4743 * For SGEN, these objects will only be freed at appdomain unload.
4746 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4748 MONO_REQ_GC_UNSAFE_MODE;
4752 mono_error_init (error);
4754 vtable = mono_class_vtable (domain, klass);
4755 g_assert (vtable); /* FIXME don't swallow the error */
4757 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4759 if (G_UNLIKELY (!o))
4760 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4761 else if (G_UNLIKELY (vtable->klass->has_finalize))
4762 mono_object_register_finalizer (o);
4768 * mono_object_new_specific:
4769 * @vtable: the vtable of the object that we want to create
4771 * Returns: A newly created object with class and domain specified
4775 mono_object_new_specific (MonoVTable *vtable)
4778 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4779 mono_error_raise_exception (&error);
4785 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4787 MONO_REQ_GC_UNSAFE_MODE;
4791 mono_error_init (error);
4793 /* check for is_com_object for COM Interop */
4794 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4797 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4800 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4803 mono_class_init (klass);
4805 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4807 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4810 vtable->domain->create_proxy_for_type_method = im;
4813 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4814 if (!mono_error_ok (error))
4817 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4818 if (!mono_error_ok (error))
4825 return mono_object_new_alloc_specific_checked (vtable, error);
4829 ves_icall_object_new_specific (MonoVTable *vtable)
4832 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4833 mono_error_raise_exception (&error);
4839 mono_object_new_alloc_specific (MonoVTable *vtable)
4842 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4843 mono_error_raise_exception (&error);
4849 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4851 MONO_REQ_GC_UNSAFE_MODE;
4855 mono_error_init (error);
4857 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4859 if (G_UNLIKELY (!o))
4860 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4861 else if (G_UNLIKELY (vtable->klass->has_finalize))
4862 mono_object_register_finalizer (o);
4868 mono_object_new_fast (MonoVTable *vtable)
4871 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4872 mono_error_raise_exception (&error);
4878 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4880 MONO_REQ_GC_UNSAFE_MODE;
4884 mono_error_init (error);
4886 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4888 if (G_UNLIKELY (!o))
4889 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4895 ves_icall_object_new_fast (MonoVTable *vtable)
4898 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4899 mono_error_raise_exception (&error);
4905 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4907 MONO_REQ_GC_UNSAFE_MODE;
4911 mono_error_init (error);
4913 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4915 if (G_UNLIKELY (!o))
4916 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4917 else if (G_UNLIKELY (vtable->klass->has_finalize))
4918 mono_object_register_finalizer (o);
4924 * mono_class_get_allocation_ftn:
4926 * @for_box: the object will be used for boxing
4927 * @pass_size_in_words:
4929 * Return the allocation function appropriate for the given class.
4933 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4935 MONO_REQ_GC_NEUTRAL_MODE;
4937 *pass_size_in_words = FALSE;
4939 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4940 return ves_icall_object_new_specific;
4942 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4944 return ves_icall_object_new_fast;
4947 * FIXME: This is actually slower than ves_icall_object_new_fast, because
4948 * of the overhead of parameter passing.
4951 *pass_size_in_words = TRUE;
4952 #ifdef GC_REDIRECT_TO_LOCAL
4953 return GC_local_gcj_fast_malloc;
4955 return GC_gcj_fast_malloc;
4960 return ves_icall_object_new_specific;
4964 * mono_object_new_from_token:
4965 * @image: Context where the type_token is hosted
4966 * @token: a token of the type that we want to create
4968 * Returns: A newly created object whose definition is
4969 * looked up using @token in the @image image
4972 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4974 MONO_REQ_GC_UNSAFE_MODE;
4980 klass = mono_class_get_checked (image, token, &error);
4981 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
4983 result = mono_object_new_checked (domain, klass, &error);
4985 mono_error_raise_exception (&error); /* FIXME don't raise here */
4992 * mono_object_clone:
4993 * @obj: the object to clone
4995 * Returns: A newly created object who is a shallow copy of @obj
4998 mono_object_clone (MonoObject *obj)
5001 MonoObject *o = mono_object_clone_checked (obj, &error);
5002 mono_error_raise_exception (&error);
5008 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5010 MONO_REQ_GC_UNSAFE_MODE;
5015 mono_error_init (error);
5017 size = obj->vtable->klass->instance_size;
5019 if (obj->vtable->klass->rank)
5020 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5022 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5024 if (G_UNLIKELY (!o)) {
5025 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5029 /* If the object doesn't contain references this will do a simple memmove. */
5030 mono_gc_wbarrier_object_copy (o, obj);
5032 if (obj->vtable->klass->has_finalize)
5033 mono_object_register_finalizer (o);
5038 * mono_array_full_copy:
5039 * @src: source array to copy
5040 * @dest: destination array
5042 * Copies the content of one array to another with exactly the same type and size.
5045 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5047 MONO_REQ_GC_UNSAFE_MODE;
5050 MonoClass *klass = src->obj.vtable->klass;
5052 g_assert (klass == dest->obj.vtable->klass);
5054 size = mono_array_length (src);
5055 g_assert (size == mono_array_length (dest));
5056 size *= mono_array_element_size (klass);
5058 if (klass->element_class->valuetype) {
5059 if (klass->element_class->has_references)
5060 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5062 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5064 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5067 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5072 * mono_array_clone_in_domain:
5073 * @domain: the domain in which the array will be cloned into
5074 * @array: the array to clone
5076 * This routine returns a copy of the array that is hosted on the
5077 * specified MonoDomain.
5080 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5082 MONO_REQ_GC_UNSAFE_MODE;
5088 MonoClass *klass = array->obj.vtable->klass;
5090 if (array->bounds == NULL) {
5091 size = mono_array_length (array);
5092 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5093 mono_error_raise_exception (&error); /* FIXME don't raise here */
5095 size *= mono_array_element_size (klass);
5097 if (klass->element_class->valuetype) {
5098 if (klass->element_class->has_references)
5099 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5101 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5103 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5106 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5111 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5112 size = mono_array_element_size (klass);
5113 for (i = 0; i < klass->rank; ++i) {
5114 sizes [i] = array->bounds [i].length;
5115 size *= array->bounds [i].length;
5116 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5118 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5119 mono_error_raise_exception (&error); /* FIXME don't raise here */
5121 if (klass->element_class->valuetype) {
5122 if (klass->element_class->has_references)
5123 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5125 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5127 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5130 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5138 * @array: the array to clone
5140 * Returns: A newly created array who is a shallow copy of @array
5143 mono_array_clone (MonoArray *array)
5145 MONO_REQ_GC_UNSAFE_MODE;
5147 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5150 /* helper macros to check for overflow when calculating the size of arrays */
5151 #ifdef MONO_BIG_ARRAYS
5152 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5153 #define MYGUINT_MAX MYGUINT64_MAX
5154 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5155 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5156 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5157 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5158 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5160 #define MYGUINT32_MAX 4294967295U
5161 #define MYGUINT_MAX MYGUINT32_MAX
5162 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5163 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5164 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5165 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5166 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5170 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5172 MONO_REQ_GC_NEUTRAL_MODE;
5176 byte_len = mono_array_element_size (klass);
5177 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5180 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5182 byte_len += MONO_SIZEOF_MONO_ARRAY;
5190 * mono_array_new_full:
5191 * @domain: domain where the object is created
5192 * @array_class: array class
5193 * @lengths: lengths for each dimension in the array
5194 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5196 * This routine creates a new array objects with the given dimensions,
5197 * lower bounds and type.
5200 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5203 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5204 mono_error_raise_exception (&error);
5210 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5212 MONO_REQ_GC_UNSAFE_MODE;
5214 uintptr_t byte_len = 0, len, bounds_size;
5217 MonoArrayBounds *bounds;
5221 mono_error_init (error);
5223 if (!array_class->inited)
5224 mono_class_init (array_class);
5228 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5229 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5231 if (len > MONO_ARRAY_MAX_INDEX) {
5232 mono_error_set_generic_error (error, "System", "OverflowException", "");
5237 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5239 for (i = 0; i < array_class->rank; ++i) {
5240 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5241 mono_error_set_generic_error (error, "System", "OverflowException", "");
5244 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5245 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5252 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5253 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5259 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5260 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5263 byte_len = (byte_len + 3) & ~3;
5264 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5265 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5268 byte_len += bounds_size;
5271 * Following three lines almost taken from mono_object_new ():
5272 * they need to be kept in sync.
5274 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5276 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5278 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5280 if (G_UNLIKELY (!o)) {
5281 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5285 array = (MonoArray*)o;
5287 bounds = array->bounds;
5290 for (i = 0; i < array_class->rank; ++i) {
5291 bounds [i].length = lengths [i];
5293 bounds [i].lower_bound = lower_bounds [i];
5302 * @domain: domain where the object is created
5303 * @eclass: element class
5304 * @n: number of array elements
5306 * This routine creates a new szarray with @n elements of type @eclass.
5309 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5311 MONO_REQ_GC_UNSAFE_MODE;
5317 ac = mono_array_class_get (eclass, 1);
5320 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5321 mono_error_raise_exception (&error); /* FIXME don't raise here */
5327 * mono_array_new_specific:
5328 * @vtable: a vtable in the appropriate domain for an initialized class
5329 * @n: number of array elements
5331 * This routine is a fast alternative to mono_array_new() for code which
5332 * can be sure about the domain it operates in.
5335 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5338 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5339 mono_error_raise_exception (&error); /* FIXME don't raise here */
5345 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5347 MONO_REQ_GC_UNSAFE_MODE;
5352 mono_error_init (error);
5354 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5355 mono_error_set_generic_error (error, "System", "OverflowException", "");
5359 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5360 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5363 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5365 if (G_UNLIKELY (!o)) {
5366 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5370 return (MonoArray*)o;
5374 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5377 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5378 mono_error_raise_exception (&error);
5384 * mono_string_new_utf16:
5385 * @text: a pointer to an utf16 string
5386 * @len: the length of the string
5388 * Returns: A newly created string object which contains @text.
5391 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5393 MONO_REQ_GC_UNSAFE_MODE;
5396 MonoString *res = NULL;
5397 res = mono_string_new_utf16_checked (domain, text, len, &error);
5398 mono_error_raise_exception (&error);
5404 * mono_string_new_utf16_checked:
5405 * @text: a pointer to an utf16 string
5406 * @len: the length of the string
5407 * @error: written on error.
5409 * Returns: A newly created string object which contains @text.
5410 * On error, returns NULL and sets @error.
5413 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5415 MONO_REQ_GC_UNSAFE_MODE;
5419 mono_error_init (error);
5421 s = mono_string_new_size_checked (domain, len, error);
5423 memcpy (mono_string_chars (s), text, len * 2);
5429 * mono_string_new_utf32:
5430 * @text: a pointer to an utf32 string
5431 * @len: the length of the string
5433 * Returns: A newly created string object which contains @text.
5436 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5438 MONO_REQ_GC_UNSAFE_MODE;
5442 mono_unichar2 *utf16_output = NULL;
5443 gint32 utf16_len = 0;
5444 GError *gerror = NULL;
5445 glong items_written;
5447 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5450 g_error_free (gerror);
5452 while (utf16_output [utf16_len]) utf16_len++;
5454 s = mono_string_new_size_checked (domain, utf16_len, &error);
5455 mono_error_raise_exception (&error); /* FIXME don't raise here */
5457 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5459 g_free (utf16_output);
5465 * mono_string_new_size:
5466 * @text: a pointer to an utf16 string
5467 * @len: the length of the string
5469 * Returns: A newly created string object of @len
5472 mono_string_new_size (MonoDomain *domain, gint32 len)
5475 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5476 mono_error_raise_exception (&error);
5482 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5484 MONO_REQ_GC_UNSAFE_MODE;
5490 mono_error_init (error);
5492 /* check for overflow */
5493 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5494 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5498 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5499 g_assert (size > 0);
5501 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5504 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5506 if (G_UNLIKELY (!s)) {
5507 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5515 * mono_string_new_len:
5516 * @text: a pointer to an utf8 string
5517 * @length: number of bytes in @text to consider
5519 * Returns: A newly created string object which contains @text.
5522 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5524 MONO_REQ_GC_UNSAFE_MODE;
5527 GError *eg_error = NULL;
5528 MonoString *o = NULL;
5530 glong items_written;
5532 mono_error_init (&error);
5534 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5537 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5539 g_error_free (eg_error);
5543 mono_error_raise_exception (&error); /* FIXME don't raise here */
5549 * @text: a pointer to an utf8 string
5551 * Returns: A newly created string object which contains @text.
5553 * This function asserts if it cannot allocate a new string.
5555 * @deprecated Use mono_string_new_checked in new code.
5558 mono_string_new (MonoDomain *domain, const char *text)
5561 MonoString *res = NULL;
5562 res = mono_string_new_checked (domain, text, &error);
5563 mono_error_assert_ok (&error);
5568 * mono_string_new_checked:
5569 * @text: a pointer to an utf8 string
5570 * @merror: set on error
5572 * Returns: A newly created string object which contains @text.
5573 * On error returns NULL and sets @merror.
5576 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5578 MONO_REQ_GC_UNSAFE_MODE;
5580 GError *eg_error = NULL;
5581 MonoString *o = NULL;
5583 glong items_written;
5586 mono_error_init (error);
5590 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5593 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5595 g_error_free (eg_error);
5598 mono_error_raise_exception (error);
5600 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5605 MonoString *o = NULL;
5607 if (!g_utf8_validate (text, -1, &end)) {
5608 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5612 len = g_utf8_strlen (text, -1);
5613 o = mono_string_new_size_checked (domain, len, error);
5616 str = mono_string_chars (o);
5618 while (text < end) {
5619 *str++ = g_utf8_get_char (text);
5620 text = g_utf8_next_char (text);
5629 * mono_string_new_wrapper:
5630 * @text: pointer to utf8 characters.
5632 * Helper function to create a string object from @text in the current domain.
5635 mono_string_new_wrapper (const char *text)
5637 MONO_REQ_GC_UNSAFE_MODE;
5639 MonoDomain *domain = mono_domain_get ();
5642 return mono_string_new (domain, text);
5649 * @class: the class of the value
5650 * @value: a pointer to the unboxed data
5652 * Returns: A newly created object which contains @value.
5655 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5657 MONO_REQ_GC_UNSAFE_MODE;
5664 g_assert (klass->valuetype);
5665 if (mono_class_is_nullable (klass))
5666 return mono_nullable_box ((guint8 *)value, klass);
5668 vtable = mono_class_vtable (domain, klass);
5671 size = mono_class_instance_size (klass);
5672 res = mono_object_new_alloc_specific_checked (vtable, &error);
5673 mono_error_raise_exception (&error); /* FIXME don't raise here */
5675 size = size - sizeof (MonoObject);
5678 g_assert (size == mono_class_value_size (klass, NULL));
5679 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5681 #if NO_UNALIGNED_ACCESS
5682 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5686 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5689 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5692 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5695 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5698 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5702 if (klass->has_finalize)
5703 mono_object_register_finalizer (res);
5709 * @dest: destination pointer
5710 * @src: source pointer
5711 * @klass: a valuetype class
5713 * Copy a valuetype from @src to @dest. This function must be used
5714 * when @klass contains references fields.
5717 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5719 MONO_REQ_GC_UNSAFE_MODE;
5721 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5725 * mono_value_copy_array:
5726 * @dest: destination array
5727 * @dest_idx: index in the @dest array
5728 * @src: source pointer
5729 * @count: number of items
5731 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5732 * This function must be used when @klass contains references fields.
5733 * Overlap is handled.
5736 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5738 MONO_REQ_GC_UNSAFE_MODE;
5740 int size = mono_array_element_size (dest->obj.vtable->klass);
5741 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5742 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5743 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5747 * mono_object_get_domain:
5748 * @obj: object to query
5750 * Returns: the MonoDomain where the object is hosted
5753 mono_object_get_domain (MonoObject *obj)
5755 MONO_REQ_GC_UNSAFE_MODE;
5757 return mono_object_domain (obj);
5761 * mono_object_get_class:
5762 * @obj: object to query
5764 * Returns: the MonOClass of the object.
5767 mono_object_get_class (MonoObject *obj)
5769 MONO_REQ_GC_UNSAFE_MODE;
5771 return mono_object_class (obj);
5774 * mono_object_get_size:
5775 * @o: object to query
5777 * Returns: the size, in bytes, of @o
5780 mono_object_get_size (MonoObject* o)
5782 MONO_REQ_GC_UNSAFE_MODE;
5784 MonoClass* klass = mono_object_class (o);
5785 if (klass == mono_defaults.string_class) {
5786 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5787 } else if (o->vtable->rank) {
5788 MonoArray *array = (MonoArray*)o;
5789 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5790 if (array->bounds) {
5793 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5797 return mono_class_instance_size (klass);
5802 * mono_object_unbox:
5803 * @obj: object to unbox
5805 * Returns: a pointer to the start of the valuetype boxed in this
5808 * This method will assert if the object passed is not a valuetype.
5811 mono_object_unbox (MonoObject *obj)
5813 MONO_REQ_GC_UNSAFE_MODE;
5815 /* add assert for valuetypes? */
5816 g_assert (obj->vtable->klass->valuetype);
5817 return ((char*)obj) + sizeof (MonoObject);
5821 * mono_object_isinst:
5823 * @klass: a pointer to a class
5825 * Returns: @obj if @obj is derived from @klass
5828 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5830 MONO_REQ_GC_UNSAFE_MODE;
5833 mono_class_init (klass);
5835 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5836 return mono_object_isinst_mbyref (obj, klass);
5841 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5845 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5847 MONO_REQ_GC_UNSAFE_MODE;
5857 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5858 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5862 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5863 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5866 MonoClass *oklass = vt->klass;
5867 if (mono_class_is_transparent_proxy (oklass))
5868 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5870 mono_class_setup_supertypes (klass);
5871 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5874 #ifndef DISABLE_REMOTING
5875 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5877 MonoDomain *domain = mono_domain_get ();
5879 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5880 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5881 MonoMethod *im = NULL;
5884 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5886 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5887 im = mono_object_get_virtual_method (rp, im);
5890 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5891 mono_error_raise_exception (&error); /* FIXME don't raise here */
5894 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5895 mono_error_raise_exception (&error); /* FIXME don't raise here */
5897 if (*(MonoBoolean *) mono_object_unbox(res)) {
5898 /* Update the vtable of the remote type, so it can safely cast to this new type */
5899 mono_upgrade_remote_class (domain, obj, klass);
5903 #endif /* DISABLE_REMOTING */
5908 * mono_object_castclass_mbyref:
5910 * @klass: a pointer to a class
5912 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5915 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5917 MONO_REQ_GC_UNSAFE_MODE;
5919 if (!obj) return NULL;
5920 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5922 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5924 "InvalidCastException"));
5929 MonoDomain *orig_domain;
5935 str_lookup (MonoDomain *domain, gpointer user_data)
5937 MONO_REQ_GC_UNSAFE_MODE;
5939 LDStrInfo *info = (LDStrInfo *)user_data;
5940 if (info->res || domain == info->orig_domain)
5942 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5946 mono_string_get_pinned (MonoString *str, MonoError *error)
5948 MONO_REQ_GC_UNSAFE_MODE;
5950 mono_error_init (error);
5952 /* We only need to make a pinned version of a string if this is a moving GC */
5953 if (!mono_gc_is_moving ())
5957 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5958 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5960 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5961 news->length = mono_string_length (str);
5963 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5969 mono_string_is_interned_lookup (MonoString *str, int insert)
5971 MONO_REQ_GC_UNSAFE_MODE;
5974 MonoGHashTable *ldstr_table;
5975 MonoString *s, *res;
5978 domain = ((MonoObject *)str)->vtable->domain;
5979 ldstr_table = domain->ldstr_table;
5981 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5987 /* Allocate outside the lock */
5989 s = mono_string_get_pinned (str, &error);
5990 mono_error_raise_exception (&error); /* FIXME don't raise here */
5993 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5998 mono_g_hash_table_insert (ldstr_table, s, s);
6003 LDStrInfo ldstr_info;
6004 ldstr_info.orig_domain = domain;
6005 ldstr_info.ins = str;
6006 ldstr_info.res = NULL;
6008 mono_domain_foreach (str_lookup, &ldstr_info);
6009 if (ldstr_info.res) {
6011 * the string was already interned in some other domain:
6012 * intern it in the current one as well.
6014 mono_g_hash_table_insert (ldstr_table, str, str);
6024 * mono_string_is_interned:
6025 * @o: String to probe
6027 * Returns whether the string has been interned.
6030 mono_string_is_interned (MonoString *o)
6032 MONO_REQ_GC_UNSAFE_MODE;
6034 return mono_string_is_interned_lookup (o, FALSE);
6038 * mono_string_intern:
6039 * @o: String to intern
6041 * Interns the string passed.
6042 * Returns: The interned string.
6045 mono_string_intern (MonoString *str)
6047 MONO_REQ_GC_UNSAFE_MODE;
6049 return mono_string_is_interned_lookup (str, TRUE);
6054 * @domain: the domain where the string will be used.
6055 * @image: a metadata context
6056 * @idx: index into the user string table.
6058 * Implementation for the ldstr opcode.
6059 * Returns: a loaded string from the @image/@idx combination.
6062 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6064 MONO_REQ_GC_UNSAFE_MODE;
6066 if (image->dynamic) {
6067 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6070 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6071 return NULL; /*FIXME we should probably be raising an exception here*/
6072 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6077 * mono_ldstr_metadata_sig
6078 * @domain: the domain for the string
6079 * @sig: the signature of a metadata string
6081 * Returns: a MonoString for a string stored in the metadata
6084 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6086 MONO_REQ_GC_UNSAFE_MODE;
6089 const char *str = sig;
6090 MonoString *o, *interned;
6093 len2 = mono_metadata_decode_blob_size (str, &str);
6096 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6097 mono_error_raise_exception (&error); /* FIXME don't raise here */
6098 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6101 guint16 *p2 = (guint16*)mono_string_chars (o);
6102 for (i = 0; i < len2; ++i) {
6103 *p2 = GUINT16_FROM_LE (*p2);
6109 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6112 return interned; /* o will get garbage collected */
6114 o = mono_string_get_pinned (o, &error);
6115 mono_error_raise_exception (&error); /* FIXME don't raise here */
6118 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6120 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6130 * mono_string_to_utf8:
6131 * @s: a System.String
6133 * Returns the UTF8 representation for @s.
6134 * The resulting buffer needs to be freed with mono_free().
6136 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6139 mono_string_to_utf8 (MonoString *s)
6141 MONO_REQ_GC_UNSAFE_MODE;
6144 char *result = mono_string_to_utf8_checked (s, &error);
6146 if (!mono_error_ok (&error))
6147 mono_error_raise_exception (&error);
6152 * mono_string_to_utf8_checked:
6153 * @s: a System.String
6154 * @error: a MonoError.
6156 * Converts a MonoString to its UTF8 representation. May fail; check
6157 * @error to determine whether the conversion was successful.
6158 * The resulting buffer should be freed with mono_free().
6161 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6163 MONO_REQ_GC_UNSAFE_MODE;
6167 GError *gerror = NULL;
6169 mono_error_init (error);
6175 return g_strdup ("");
6177 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6179 mono_error_set_argument (error, "string", "%s", gerror->message);
6180 g_error_free (gerror);
6183 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6184 if (s->length > written) {
6185 /* allocate the total length and copy the part of the string that has been converted */
6186 char *as2 = (char *)g_malloc0 (s->length);
6187 memcpy (as2, as, written);
6196 * mono_string_to_utf8_ignore:
6199 * Converts a MonoString to its UTF8 representation. Will ignore
6200 * invalid surrogate pairs.
6201 * The resulting buffer should be freed with mono_free().
6205 mono_string_to_utf8_ignore (MonoString *s)
6207 MONO_REQ_GC_UNSAFE_MODE;
6216 return g_strdup ("");
6218 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6220 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6221 if (s->length > written) {
6222 /* allocate the total length and copy the part of the string that has been converted */
6223 char *as2 = (char *)g_malloc0 (s->length);
6224 memcpy (as2, as, written);
6233 * mono_string_to_utf8_image_ignore:
6234 * @s: a System.String
6236 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6239 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6241 MONO_REQ_GC_UNSAFE_MODE;
6243 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6247 * mono_string_to_utf8_mp_ignore:
6248 * @s: a System.String
6250 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6253 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6255 MONO_REQ_GC_UNSAFE_MODE;
6257 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6262 * mono_string_to_utf16:
6265 * Return an null-terminated array of the utf-16 chars
6266 * contained in @s. The result must be freed with g_free().
6267 * This is a temporary helper until our string implementation
6268 * is reworked to always include the null terminating char.
6271 mono_string_to_utf16 (MonoString *s)
6273 MONO_REQ_GC_UNSAFE_MODE;
6280 as = (char *)g_malloc ((s->length * 2) + 2);
6281 as [(s->length * 2)] = '\0';
6282 as [(s->length * 2) + 1] = '\0';
6285 return (gunichar2 *)(as);
6288 memcpy (as, mono_string_chars(s), s->length * 2);
6289 return (gunichar2 *)(as);
6293 * mono_string_to_utf32:
6296 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6297 * contained in @s. The result must be freed with g_free().
6300 mono_string_to_utf32 (MonoString *s)
6302 MONO_REQ_GC_UNSAFE_MODE;
6304 mono_unichar4 *utf32_output = NULL;
6305 GError *error = NULL;
6306 glong items_written;
6311 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6314 g_error_free (error);
6316 return utf32_output;
6320 * mono_string_from_utf16:
6321 * @data: the UTF16 string (LPWSTR) to convert
6323 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6325 * Returns: a MonoString.
6328 mono_string_from_utf16 (gunichar2 *data)
6330 MONO_REQ_GC_UNSAFE_MODE;
6333 MonoString *res = NULL;
6334 MonoDomain *domain = mono_domain_get ();
6340 while (data [len]) len++;
6342 res = mono_string_new_utf16_checked (domain, data, len, &error);
6343 mono_error_raise_exception (&error); /* FIXME don't raise here */
6348 * mono_string_from_utf32:
6349 * @data: the UTF32 string (LPWSTR) to convert
6351 * Converts a UTF32 (UCS-4)to a MonoString.
6353 * Returns: a MonoString.
6356 mono_string_from_utf32 (mono_unichar4 *data)
6358 MONO_REQ_GC_UNSAFE_MODE;
6360 MonoString* result = NULL;
6361 mono_unichar2 *utf16_output = NULL;
6362 GError *error = NULL;
6363 glong items_written;
6369 while (data [len]) len++;
6371 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6374 g_error_free (error);
6376 result = mono_string_from_utf16 (utf16_output);
6377 g_free (utf16_output);
6382 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6384 MONO_REQ_GC_UNSAFE_MODE;
6391 r = mono_string_to_utf8_ignore (s);
6393 r = mono_string_to_utf8_checked (s, error);
6394 if (!mono_error_ok (error))
6401 len = strlen (r) + 1;
6403 mp_s = (char *)mono_mempool_alloc (mp, len);
6405 mp_s = (char *)mono_image_alloc (image, len);
6407 memcpy (mp_s, r, len);
6415 * mono_string_to_utf8_image:
6416 * @s: a System.String
6418 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6421 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6423 MONO_REQ_GC_UNSAFE_MODE;
6425 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6429 * mono_string_to_utf8_mp:
6430 * @s: a System.String
6432 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6435 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6437 MONO_REQ_GC_UNSAFE_MODE;
6439 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6443 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6446 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6448 eh_callbacks = *cbs;
6451 MonoRuntimeExceptionHandlingCallbacks *
6452 mono_get_eh_callbacks (void)
6454 return &eh_callbacks;
6458 * mono_raise_exception:
6459 * @ex: exception object
6461 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6464 mono_raise_exception (MonoException *ex)
6466 MONO_REQ_GC_UNSAFE_MODE;
6469 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6470 * that will cause gcc to omit the function epilog, causing problems when
6471 * the JIT tries to walk the stack, since the return address on the stack
6472 * will point into the next function in the executable, not this one.
6474 eh_callbacks.mono_raise_exception (ex);
6478 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6480 MONO_REQ_GC_UNSAFE_MODE;
6482 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6486 * mono_wait_handle_new:
6487 * @domain: Domain where the object will be created
6488 * @handle: Handle for the wait handle
6490 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6493 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6495 MONO_REQ_GC_UNSAFE_MODE;
6498 MonoWaitHandle *res;
6499 gpointer params [1];
6500 static MonoMethod *handle_set;
6502 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6503 mono_error_raise_exception (&error); /* FIXME don't raise here */
6505 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6507 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6509 params [0] = &handle;
6511 mono_runtime_invoke_checked (handle_set, res, params, &error);
6512 mono_error_raise_exception (&error); /* FIXME don't raise here */
6518 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6520 MONO_REQ_GC_UNSAFE_MODE;
6522 static MonoClassField *f_os_handle;
6523 static MonoClassField *f_safe_handle;
6525 if (!f_os_handle && !f_safe_handle) {
6526 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6527 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6532 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6536 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6543 mono_runtime_capture_context (MonoDomain *domain)
6545 MONO_REQ_GC_UNSAFE_MODE;
6547 RuntimeInvokeFunction runtime_invoke;
6549 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6550 MonoMethod *method = mono_get_context_capture_method ();
6551 MonoMethod *wrapper;
6554 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6555 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6556 domain->capture_context_method = mono_compile_method (method);
6559 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6561 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6564 * mono_async_result_new:
6565 * @domain:domain where the object will be created.
6566 * @handle: wait handle.
6567 * @state: state to pass to AsyncResult
6568 * @data: C closure data.
6570 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6571 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6575 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6577 MONO_REQ_GC_UNSAFE_MODE;
6580 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6581 mono_error_raise_exception (&error); /* FIXME don't raise here */
6582 MonoObject *context = mono_runtime_capture_context (domain);
6583 /* we must capture the execution context from the original thread */
6585 MONO_OBJECT_SETREF (res, execution_context, context);
6586 /* note: result may be null if the flow is suppressed */
6589 res->data = (void **)data;
6590 MONO_OBJECT_SETREF (res, object_data, object_data);
6591 MONO_OBJECT_SETREF (res, async_state, state);
6593 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6595 res->sync_completed = FALSE;
6596 res->completed = FALSE;
6602 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6604 MONO_REQ_GC_UNSAFE_MODE;
6611 g_assert (ares->async_delegate);
6613 ac = (MonoAsyncCall*) ares->object_data;
6615 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6617 gpointer wait_event = NULL;
6619 ac->msg->exc = NULL;
6620 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6621 MONO_OBJECT_SETREF (ac, res, res);
6623 mono_monitor_enter ((MonoObject*) ares);
6624 ares->completed = 1;
6626 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6627 mono_monitor_exit ((MonoObject*) ares);
6629 if (wait_event != NULL)
6630 SetEvent (wait_event);
6632 if (ac->cb_method) {
6633 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6634 mono_error_raise_exception (&error);
6642 mono_message_init (MonoDomain *domain,
6643 MonoMethodMessage *this_obj,
6644 MonoReflectionMethod *method,
6645 MonoArray *out_args)
6647 MONO_REQ_GC_UNSAFE_MODE;
6649 static MonoClass *object_array_klass;
6650 static MonoClass *byte_array_klass;
6651 static MonoClass *string_array_klass;
6653 MonoMethodSignature *sig = mono_method_signature (method->method);
6660 if (!object_array_klass) {
6663 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6665 byte_array_klass = klass;
6667 klass = mono_array_class_get (mono_defaults.string_class, 1);
6669 string_array_klass = klass;
6671 klass = mono_array_class_get (mono_defaults.object_class, 1);
6674 mono_atomic_store_release (&object_array_klass, klass);
6677 MONO_OBJECT_SETREF (this_obj, method, method);
6679 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6680 mono_error_raise_exception (&error); /* FIXME don't raise here */
6682 MONO_OBJECT_SETREF (this_obj, args, arr);
6684 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6685 mono_error_raise_exception (&error); /* FIXME don't raise here */
6687 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6689 this_obj->async_result = NULL;
6690 this_obj->call_type = CallType_Sync;
6692 names = g_new (char *, sig->param_count);
6693 mono_method_get_param_names (method->method, (const char **) names);
6695 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6696 mono_error_raise_exception (&error); /* FIXME don't raise here */
6698 MONO_OBJECT_SETREF (this_obj, names, arr);
6700 for (i = 0; i < sig->param_count; i++) {
6701 name = mono_string_new (domain, names [i]);
6702 mono_array_setref (this_obj->names, i, name);
6706 for (i = 0, j = 0; i < sig->param_count; i++) {
6707 if (sig->params [i]->byref) {
6709 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6710 mono_array_setref (this_obj->args, i, arg);
6714 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6718 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6721 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6725 #ifndef DISABLE_REMOTING
6727 * mono_remoting_invoke:
6728 * @real_proxy: pointer to a RealProxy object
6729 * @msg: The MonoMethodMessage to execute
6730 * @exc: used to store exceptions
6731 * @out_args: used to store output arguments
6733 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6734 * IMessage interface and it is not trivial to extract results from there. So
6735 * we call an helper method PrivateInvoke instead of calling
6736 * RealProxy::Invoke() directly.
6738 * Returns: the result object.
6741 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6742 MonoObject **exc, MonoArray **out_args)
6744 MONO_REQ_GC_UNSAFE_MODE;
6748 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6751 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6754 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6756 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6757 real_proxy->vtable->domain->private_invoke_method = im;
6760 pa [0] = real_proxy;
6766 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6768 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6770 mono_error_raise_exception (&error); /* FIXME don't raise here */
6777 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6778 MonoObject **exc, MonoArray **out_args)
6780 MONO_REQ_GC_UNSAFE_MODE;
6782 static MonoClass *object_array_klass;
6786 MonoMethodSignature *sig;
6789 int i, j, outarg_count = 0;
6791 #ifndef DISABLE_REMOTING
6792 if (target && mono_object_is_transparent_proxy (target)) {
6793 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6794 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6795 target = tp->rp->unwrapped_server;
6797 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6802 domain = mono_domain_get ();
6803 method = msg->method->method;
6804 sig = mono_method_signature (method);
6806 for (i = 0; i < sig->param_count; i++) {
6807 if (sig->params [i]->byref)
6811 if (!object_array_klass) {
6814 klass = mono_array_class_get (mono_defaults.object_class, 1);
6817 mono_memory_barrier ();
6818 object_array_klass = klass;
6821 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6822 mono_error_raise_exception (&error); /* FIXME don't raise here */
6824 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6827 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6829 for (i = 0, j = 0; i < sig->param_count; i++) {
6830 if (sig->params [i]->byref) {
6832 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6833 mono_array_setref (*out_args, j, arg);
6842 * mono_object_to_string:
6844 * @exc: Any exception thrown by ToString (). May be NULL.
6846 * Returns: the result of calling ToString () on an object.
6849 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6851 MONO_REQ_GC_UNSAFE_MODE;
6853 static MonoMethod *to_string = NULL;
6862 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6864 method = mono_object_get_virtual_method (obj, to_string);
6866 // Unbox value type if needed
6867 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6868 target = mono_object_unbox (obj);
6872 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6873 if (*exc == NULL && !mono_error_ok (&error))
6874 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6876 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6877 mono_error_raise_exception (&error); /* FIXME don't raise here */
6884 * mono_print_unhandled_exception:
6885 * @exc: The exception
6887 * Prints the unhandled exception.
6890 mono_print_unhandled_exception (MonoObject *exc)
6892 MONO_REQ_GC_UNSAFE_MODE;
6895 char *message = (char*)"";
6896 gboolean free_message = FALSE;
6899 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6900 message = g_strdup ("OutOfMemoryException");
6901 free_message = TRUE;
6902 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6903 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6904 free_message = TRUE;
6907 if (((MonoException*)exc)->native_trace_ips) {
6908 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6909 free_message = TRUE;
6911 MonoObject *other_exc = NULL;
6912 str = mono_object_to_string (exc, &other_exc);
6914 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6915 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6917 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6918 original_backtrace, nested_backtrace);
6920 g_free (original_backtrace);
6921 g_free (nested_backtrace);
6922 free_message = TRUE;
6924 message = mono_string_to_utf8_checked (str, &error);
6925 if (!mono_error_ok (&error)) {
6926 mono_error_cleanup (&error);
6927 message = (char *) "";
6929 free_message = TRUE;
6936 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6937 * exc->vtable->klass->name, message);
6939 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6946 * mono_delegate_ctor:
6947 * @this: pointer to an uninitialized delegate object
6948 * @target: target object
6949 * @addr: pointer to native code
6952 * Initialize a delegate and sets a specific method, not the one
6953 * associated with addr. This is useful when sharing generic code.
6954 * In that case addr will most probably not be associated with the
6955 * correct instantiation of the method.
6958 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6960 MONO_REQ_GC_UNSAFE_MODE;
6962 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6964 g_assert (this_obj);
6967 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6970 delegate->method = method;
6972 mono_stats.delegate_creations++;
6974 #ifndef DISABLE_REMOTING
6975 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6977 method = mono_marshal_get_remoting_invoke (method);
6978 delegate->method_ptr = mono_compile_method (method);
6979 MONO_OBJECT_SETREF (delegate, target, target);
6983 delegate->method_ptr = addr;
6984 MONO_OBJECT_SETREF (delegate, target, target);
6987 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6988 if (callbacks.init_delegate)
6989 callbacks.init_delegate (delegate);
6993 * mono_delegate_ctor:
6994 * @this: pointer to an uninitialized delegate object
6995 * @target: target object
6996 * @addr: pointer to native code
6998 * This is used to initialize a delegate.
7001 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7003 MONO_REQ_GC_UNSAFE_MODE;
7005 MonoDomain *domain = mono_domain_get ();
7007 MonoMethod *method = NULL;
7011 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7013 if (!ji && domain != mono_get_root_domain ())
7014 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7016 method = mono_jit_info_get_method (ji);
7017 g_assert (!method->klass->generic_container);
7020 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7024 * mono_method_call_message_new:
7025 * @method: method to encapsulate
7026 * @params: parameters to the method
7027 * @invoke: optional, delegate invoke.
7028 * @cb: async callback delegate.
7029 * @state: state passed to the async callback.
7031 * Translates arguments pointers into a MonoMethodMessage.
7034 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7035 MonoDelegate **cb, MonoObject **state)
7037 MONO_REQ_GC_UNSAFE_MODE;
7041 MonoDomain *domain = mono_domain_get ();
7042 MonoMethodSignature *sig = mono_method_signature (method);
7043 MonoMethodMessage *msg;
7046 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7047 mono_error_raise_exception (&error); /* FIXME don't raise here */
7050 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7051 mono_error_raise_exception (&error); /* FIXME don't raise here */
7052 mono_message_init (domain, msg, rm, NULL);
7053 count = sig->param_count - 2;
7055 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7056 mono_error_raise_exception (&error); /* FIXME don't raise here */
7057 mono_message_init (domain, msg, rm, NULL);
7058 count = sig->param_count;
7061 for (i = 0; i < count; i++) {
7066 if (sig->params [i]->byref)
7067 vpos = *((gpointer *)params [i]);
7071 klass = mono_class_from_mono_type (sig->params [i]);
7073 if (klass->valuetype)
7074 arg = mono_value_box (domain, klass, vpos);
7076 arg = *((MonoObject **)vpos);
7078 mono_array_setref (msg->args, i, arg);
7081 if (cb != NULL && state != NULL) {
7082 *cb = *((MonoDelegate **)params [i]);
7084 *state = *((MonoObject **)params [i]);
7091 * mono_method_return_message_restore:
7093 * Restore results from message based processing back to arguments pointers
7096 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7098 MONO_REQ_GC_UNSAFE_MODE;
7100 MonoMethodSignature *sig = mono_method_signature (method);
7101 int i, j, type, size, out_len;
7103 if (out_args == NULL)
7105 out_len = mono_array_length (out_args);
7109 for (i = 0, j = 0; i < sig->param_count; i++) {
7110 MonoType *pt = sig->params [i];
7115 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7117 arg = (char *)mono_array_get (out_args, gpointer, j);
7120 g_assert (type != MONO_TYPE_VOID);
7122 if (MONO_TYPE_IS_REFERENCE (pt)) {
7123 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7126 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7127 size = mono_class_value_size (klass, NULL);
7128 if (klass->has_references)
7129 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7131 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7133 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7134 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7143 #ifndef DISABLE_REMOTING
7146 * mono_load_remote_field:
7147 * @this: pointer to an object
7148 * @klass: klass of the object containing @field
7149 * @field: the field to load
7150 * @res: a storage to store the result
7152 * This method is called by the runtime on attempts to load fields of
7153 * transparent proxy objects. @this points to such TP, @klass is the class of
7154 * the object containing @field. @res is a storage location which can be
7155 * used to store the result.
7157 * Returns: an address pointing to the value of field.
7160 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7162 MONO_REQ_GC_UNSAFE_MODE;
7166 static MonoMethod *getter = NULL;
7167 MonoDomain *domain = mono_domain_get ();
7168 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7169 MonoClass *field_class;
7170 MonoMethodMessage *msg;
7171 MonoArray *out_args;
7175 g_assert (mono_object_is_transparent_proxy (this_obj));
7176 g_assert (res != NULL);
7178 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7179 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7184 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7186 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7189 field_class = mono_class_from_mono_type (field->type);
7191 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7192 mono_error_raise_exception (&error); /* FIXME don't raise here */
7193 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7194 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7195 mono_error_raise_exception (&error); /* FIXME don't raise here */
7196 mono_message_init (domain, msg, rm, out_args);
7198 full_name = mono_type_get_full_name (klass);
7199 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7200 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7203 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7205 if (exc) mono_raise_exception ((MonoException *)exc);
7207 if (mono_array_length (out_args) == 0)
7210 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7212 if (field_class->valuetype) {
7213 return ((char *)*res) + sizeof (MonoObject);
7219 * mono_load_remote_field_new:
7224 * Missing documentation.
7227 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7229 MONO_REQ_GC_UNSAFE_MODE;
7233 static MonoMethod *getter = NULL;
7234 MonoDomain *domain = mono_domain_get ();
7235 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7236 MonoClass *field_class;
7237 MonoMethodMessage *msg;
7238 MonoArray *out_args;
7239 MonoObject *exc, *res;
7242 g_assert (mono_object_is_transparent_proxy (this_obj));
7244 field_class = mono_class_from_mono_type (field->type);
7246 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7248 if (field_class->valuetype) {
7249 res = mono_object_new_checked (domain, field_class, &error);
7250 mono_error_raise_exception (&error); /* FIXME don't raise here */
7251 val = ((gchar *) res) + sizeof (MonoObject);
7255 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7260 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7262 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7265 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7266 mono_error_raise_exception (&error); /* FIXME don't raise here */
7267 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7269 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7270 mono_error_raise_exception (&error); /* FIXME don't raise here */
7271 mono_message_init (domain, msg, rm, out_args);
7273 full_name = mono_type_get_full_name (klass);
7274 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7275 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7278 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7280 if (exc) mono_raise_exception ((MonoException *)exc);
7282 if (mono_array_length (out_args) == 0)
7285 res = mono_array_get (out_args, MonoObject *, 0);
7291 * mono_store_remote_field:
7292 * @this_obj: pointer to an object
7293 * @klass: klass of the object containing @field
7294 * @field: the field to load
7295 * @val: the value/object to store
7297 * This method is called by the runtime on attempts to store fields of
7298 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7299 * the object containing @field. @val is the new value to store in @field.
7302 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7304 MONO_REQ_GC_UNSAFE_MODE;
7308 static MonoMethod *setter = NULL;
7309 MonoDomain *domain = mono_domain_get ();
7310 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7311 MonoClass *field_class;
7312 MonoMethodMessage *msg;
7313 MonoArray *out_args;
7318 g_assert (mono_object_is_transparent_proxy (this_obj));
7320 field_class = mono_class_from_mono_type (field->type);
7322 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7323 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7324 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7329 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7331 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7334 if (field_class->valuetype)
7335 arg = mono_value_box (domain, field_class, val);
7337 arg = *((MonoObject **)val);
7340 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7341 mono_error_raise_exception (&error); /* FIXME don't raise here */
7342 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7343 mono_error_raise_exception (&error); /* FIXME don't raise here */
7344 mono_message_init (domain, msg, rm, NULL);
7346 full_name = mono_type_get_full_name (klass);
7347 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7348 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7349 mono_array_setref (msg->args, 2, arg);
7352 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7354 if (exc) mono_raise_exception ((MonoException *)exc);
7358 * mono_store_remote_field_new:
7364 * Missing documentation
7367 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7369 MONO_REQ_GC_UNSAFE_MODE;
7373 static MonoMethod *setter = NULL;
7374 MonoDomain *domain = mono_domain_get ();
7375 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7376 MonoClass *field_class;
7377 MonoMethodMessage *msg;
7378 MonoArray *out_args;
7382 g_assert (mono_object_is_transparent_proxy (this_obj));
7384 field_class = mono_class_from_mono_type (field->type);
7386 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7387 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7388 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7393 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7395 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7398 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7399 mono_error_raise_exception (&error); /* FIXME don't raise here */
7400 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7401 mono_error_raise_exception (&error); /* FIXME don't raise here */
7402 mono_message_init (domain, msg, rm, NULL);
7404 full_name = mono_type_get_full_name (klass);
7405 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7406 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7407 mono_array_setref (msg->args, 2, arg);
7410 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7412 if (exc) mono_raise_exception ((MonoException *)exc);
7417 * mono_create_ftnptr:
7419 * Given a function address, create a function descriptor for it.
7420 * This is only needed on some platforms.
7423 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7425 return callbacks.create_ftnptr (domain, addr);
7429 * mono_get_addr_from_ftnptr:
7431 * Given a pointer to a function descriptor, return the function address.
7432 * This is only needed on some platforms.
7435 mono_get_addr_from_ftnptr (gpointer descr)
7437 return callbacks.get_addr_from_ftnptr (descr);
7441 * mono_string_chars:
7444 * Returns a pointer to the UCS16 characters stored in the MonoString
7447 mono_string_chars (MonoString *s)
7449 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7455 * mono_string_length:
7458 * Returns the lenght in characters of the string
7461 mono_string_length (MonoString *s)
7463 MONO_REQ_GC_UNSAFE_MODE;
7469 * mono_array_length:
7470 * @array: a MonoArray*
7472 * Returns the total number of elements in the array. This works for
7473 * both vectors and multidimensional arrays.
7476 mono_array_length (MonoArray *array)
7478 MONO_REQ_GC_UNSAFE_MODE;
7480 return array->max_length;
7484 * mono_array_addr_with_size:
7485 * @array: a MonoArray*
7486 * @size: size of the array elements
7487 * @idx: index into the array
7489 * Returns the address of the @idx element in the array.
7492 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7494 MONO_REQ_GC_UNSAFE_MODE;
7496 return ((char*)(array)->vector) + size * idx;
7501 mono_glist_to_array (GList *list, MonoClass *eclass)
7503 MonoDomain *domain = mono_domain_get ();
7510 len = g_list_length (list);
7511 res = mono_array_new (domain, eclass, len);
7513 for (i = 0; list; list = list->next, i++)
7514 mono_array_set (res, gpointer, i, list->data);