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 mono_error_cleanup (&error);
407 /* If the initialization failed, mark the class as unusable. */
408 /* Avoid infinite loops */
410 (klass->image == mono_defaults.corlib &&
411 !strcmp (klass->name_space, "System") &&
412 !strcmp (klass->name, "TypeInitializationException")))) {
413 vtable->init_failed = 1;
415 if (klass->name_space && *klass->name_space)
416 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
418 full_name = g_strdup (klass->name);
419 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
423 * Store the exception object so it could be thrown on subsequent
426 mono_domain_lock (domain);
427 if (!domain->type_init_exception_hash)
428 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");
429 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
430 mono_domain_unlock (domain);
434 mono_domain_set (last_domain, TRUE);
436 mono_type_init_unlock (lock);
438 /* this just blocks until the initializing thread is done */
439 mono_type_init_lock (lock);
440 mono_type_init_unlock (lock);
443 mono_type_initialization_lock ();
444 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
445 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
446 --lock->waiting_count;
447 if (lock->waiting_count == 0) {
448 mono_coop_mutex_destroy (&lock->initialization_section);
449 g_hash_table_remove (type_initialization_hash, vtable);
452 mono_memory_barrier ();
453 if (!vtable->init_failed)
454 vtable->initialized = 1;
455 mono_type_initialization_unlock ();
457 if (vtable->init_failed) {
458 /* Either we were the initializing thread or we waited for the initialization */
460 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
461 return get_type_init_exception_for_vtable (vtable);
467 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
469 MONO_REQ_GC_NEUTRAL_MODE;
471 MonoVTable *vtable = (MonoVTable*)key;
473 TypeInitializationLock *lock = (TypeInitializationLock*) value;
474 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
477 * Have to set this since it cannot be set by the normal code in
478 * mono_runtime_class_init (). In this case, the exception object is not stored,
479 * and get_type_init_exception_for_class () needs to be aware of this.
481 vtable->init_failed = 1;
482 mono_type_init_unlock (lock);
483 --lock->waiting_count;
484 if (lock->waiting_count == 0) {
485 mono_coop_mutex_destroy (&lock->initialization_section);
494 mono_release_type_locks (MonoInternalThread *thread)
496 MONO_REQ_GC_UNSAFE_MODE;
498 mono_type_initialization_lock ();
499 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
500 mono_type_initialization_unlock ();
504 default_trampoline (MonoMethod *method)
510 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
512 g_assert_not_reached ();
517 #ifndef DISABLE_REMOTING
520 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
522 g_error ("remoting not installed");
526 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
530 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
532 g_assert_not_reached ();
536 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
537 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
538 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
539 static MonoImtThunkBuilder imt_thunk_builder;
540 static gboolean always_build_imt_thunks;
542 #if (MONO_IMT_SIZE > 32)
543 #error "MONO_IMT_SIZE cannot be larger than 32"
547 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
549 memcpy (&callbacks, cbs, sizeof (*cbs));
552 MonoRuntimeCallbacks*
553 mono_get_runtime_callbacks (void)
559 mono_install_trampoline (MonoTrampoline func)
561 arch_create_jit_trampoline = func? func: default_trampoline;
565 mono_install_jump_trampoline (MonoJumpTrampoline func)
567 arch_create_jump_trampoline = func? func: default_jump_trampoline;
570 #ifndef DISABLE_REMOTING
572 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
574 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
579 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
581 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
585 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
586 imt_thunk_builder = func;
590 mono_set_always_build_imt_thunks (gboolean value)
592 always_build_imt_thunks = value;
596 * mono_compile_method:
597 * @method: The method to compile.
599 * This JIT-compiles the method, and returns the pointer to the native code
603 mono_compile_method (MonoMethod *method)
608 MONO_REQ_GC_NEUTRAL_MODE
610 if (!callbacks.compile_method) {
611 g_error ("compile method called on uninitialized runtime");
614 res = callbacks.compile_method (method, &error);
615 if (!mono_error_ok (&error))
616 mono_error_raise_exception (&error);
621 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
623 MONO_REQ_GC_NEUTRAL_MODE
625 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
629 mono_runtime_create_delegate_trampoline (MonoClass *klass)
631 MONO_REQ_GC_NEUTRAL_MODE
633 return arch_create_delegate_trampoline (mono_domain_get (), klass);
636 static MonoFreeMethodFunc default_mono_free_method = NULL;
639 * mono_install_free_method:
640 * @func: pointer to the MonoFreeMethodFunc used to release a method
642 * This is an internal VM routine, it is used for the engines to
643 * register a handler to release the resources associated with a method.
645 * Methods are freed when no more references to the delegate that holds
649 mono_install_free_method (MonoFreeMethodFunc func)
651 default_mono_free_method = func;
655 * mono_runtime_free_method:
656 * @domain; domain where the method is hosted
657 * @method: method to release
659 * This routine is invoked to free the resources associated with
660 * a method that has been JIT compiled. This is used to discard
661 * methods that were used only temporarily (for example, used in marshalling)
665 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
667 MONO_REQ_GC_NEUTRAL_MODE
669 if (default_mono_free_method != NULL)
670 default_mono_free_method (domain, method);
672 mono_method_clear_object (domain, method);
674 mono_free_method (method);
678 * The vtables in the root appdomain are assumed to be reachable by other
679 * roots, and we don't use typed allocation in the other domains.
682 /* The sync block is no longer a GC pointer */
683 #define GC_HEADER_BITMAP (0)
685 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
688 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
690 MONO_REQ_GC_NEUTRAL_MODE;
692 MonoClassField *field;
698 max_size = mono_class_data_size (klass) / sizeof (gpointer);
700 max_size = klass->instance_size / sizeof (gpointer);
701 if (max_size > size) {
702 g_assert (offset <= 0);
703 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
708 /*An Ephemeron cannot be marked by sgen*/
709 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
711 memset (bitmap, 0, size / 8);
716 for (p = klass; p != NULL; p = p->parent) {
717 gpointer iter = NULL;
718 while ((field = mono_class_get_fields (p, &iter))) {
722 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
724 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
727 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
730 /* FIXME: should not happen, flag as type load error */
731 if (field->type->byref)
734 if (static_fields && field->offset == -1)
738 pos = field->offset / sizeof (gpointer);
741 type = mono_type_get_underlying_type (field->type);
742 switch (type->type) {
745 case MONO_TYPE_FNPTR:
747 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
752 if (klass->image != mono_defaults.corlib)
755 case MONO_TYPE_STRING:
756 case MONO_TYPE_SZARRAY:
757 case MONO_TYPE_CLASS:
758 case MONO_TYPE_OBJECT:
759 case MONO_TYPE_ARRAY:
760 g_assert ((field->offset % sizeof(gpointer)) == 0);
762 g_assert (pos < size || pos <= max_size);
763 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
764 *max_set = MAX (*max_set, pos);
766 case MONO_TYPE_GENERICINST:
767 if (!mono_type_generic_inst_is_valuetype (type)) {
768 g_assert ((field->offset % sizeof(gpointer)) == 0);
770 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
771 *max_set = MAX (*max_set, pos);
776 case MONO_TYPE_VALUETYPE: {
777 MonoClass *fclass = mono_class_from_mono_type (field->type);
778 if (fclass->has_references) {
779 /* remove the object header */
780 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
794 case MONO_TYPE_BOOLEAN:
798 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
809 * mono_class_compute_bitmap:
811 * Mono internal function to compute a bitmap of reference fields in a class.
814 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
816 MONO_REQ_GC_NEUTRAL_MODE;
818 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
823 * similar to the above, but sets the bits in the bitmap for any non-ref field
824 * and ignores static fields
827 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
829 MonoClassField *field;
834 max_size = class->instance_size / sizeof (gpointer);
835 if (max_size >= size) {
836 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
839 for (p = class; p != NULL; p = p->parent) {
840 gpointer iter = NULL;
841 while ((field = mono_class_get_fields (p, &iter))) {
844 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
846 /* FIXME: should not happen, flag as type load error */
847 if (field->type->byref)
850 pos = field->offset / sizeof (gpointer);
853 type = mono_type_get_underlying_type (field->type);
854 switch (type->type) {
855 #if SIZEOF_VOID_P == 8
859 case MONO_TYPE_FNPTR:
864 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
865 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
866 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
869 #if SIZEOF_VOID_P == 4
873 case MONO_TYPE_FNPTR:
878 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
879 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
880 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
886 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
887 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
888 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
891 case MONO_TYPE_BOOLEAN:
894 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
896 case MONO_TYPE_STRING:
897 case MONO_TYPE_SZARRAY:
898 case MONO_TYPE_CLASS:
899 case MONO_TYPE_OBJECT:
900 case MONO_TYPE_ARRAY:
902 case MONO_TYPE_GENERICINST:
903 if (!mono_type_generic_inst_is_valuetype (type)) {
908 case MONO_TYPE_VALUETYPE: {
909 MonoClass *fclass = mono_class_from_mono_type (field->type);
910 /* remove the object header */
911 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
915 g_assert_not_reached ();
924 * mono_class_insecure_overlapping:
925 * check if a class with explicit layout has references and non-references
926 * fields overlapping.
928 * Returns: TRUE if it is insecure to load the type.
931 mono_class_insecure_overlapping (MonoClass *klass)
935 gsize default_bitmap [4] = {0};
937 gsize default_nrbitmap [4] = {0};
938 int i, insecure = FALSE;
941 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
942 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
944 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
945 int idx = i % (sizeof (bitmap [0]) * 8);
946 if (bitmap [idx] & nrbitmap [idx]) {
951 if (bitmap != default_bitmap)
953 if (nrbitmap != default_nrbitmap)
956 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
964 ves_icall_string_alloc (int length)
967 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
968 mono_error_raise_exception (&error);
974 mono_class_compute_gc_descriptor (MonoClass *klass)
976 MONO_REQ_GC_NEUTRAL_MODE;
980 gsize default_bitmap [4] = {0};
981 static gboolean gcj_inited = FALSE;
986 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
987 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
990 mono_loader_unlock ();
994 mono_class_init (klass);
996 if (klass->gc_descr_inited)
999 klass->gc_descr_inited = TRUE;
1000 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1002 bitmap = default_bitmap;
1003 if (klass == mono_defaults.string_class) {
1004 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1005 } else if (klass->rank) {
1006 mono_class_compute_gc_descriptor (klass->element_class);
1007 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1009 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1010 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1011 class->name_space, class->name);*/
1013 /* remove the object header */
1014 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1015 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));
1016 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1017 class->name_space, class->name);*/
1018 if (bitmap != default_bitmap)
1022 /*static int count = 0;
1025 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1026 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1028 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1029 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1031 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1032 if (bitmap != default_bitmap)
1038 * field_is_special_static:
1039 * @fklass: The MonoClass to look up.
1040 * @field: The MonoClassField describing the field.
1042 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1043 * SPECIAL_STATIC_NONE otherwise.
1046 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1048 MONO_REQ_GC_NEUTRAL_MODE;
1050 MonoCustomAttrInfo *ainfo;
1052 ainfo = mono_custom_attrs_from_field (fklass, field);
1055 for (i = 0; i < ainfo->num_attrs; ++i) {
1056 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1057 if (klass->image == mono_defaults.corlib) {
1058 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1059 mono_custom_attrs_free (ainfo);
1060 return SPECIAL_STATIC_THREAD;
1062 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1063 mono_custom_attrs_free (ainfo);
1064 return SPECIAL_STATIC_CONTEXT;
1068 mono_custom_attrs_free (ainfo);
1069 return SPECIAL_STATIC_NONE;
1072 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1073 #define mix(a,b,c) { \
1074 a -= c; a ^= rot(c, 4); c += b; \
1075 b -= a; b ^= rot(a, 6); a += c; \
1076 c -= b; c ^= rot(b, 8); b += a; \
1077 a -= c; a ^= rot(c,16); c += b; \
1078 b -= a; b ^= rot(a,19); a += c; \
1079 c -= b; c ^= rot(b, 4); b += a; \
1081 #define final(a,b,c) { \
1082 c ^= b; c -= rot(b,14); \
1083 a ^= c; a -= rot(c,11); \
1084 b ^= a; b -= rot(a,25); \
1085 c ^= b; c -= rot(b,16); \
1086 a ^= c; a -= rot(c,4); \
1087 b ^= a; b -= rot(a,14); \
1088 c ^= b; c -= rot(b,24); \
1092 * mono_method_get_imt_slot:
1094 * The IMT slot is embedded into AOTed code, so this must return the same value
1095 * for the same method across all executions. This means:
1096 * - pointers shouldn't be used as hash values.
1097 * - mono_metadata_str_hash () should be used for hashing strings.
1100 mono_method_get_imt_slot (MonoMethod *method)
1102 MONO_REQ_GC_NEUTRAL_MODE;
1104 MonoMethodSignature *sig;
1106 guint32 *hashes_start, *hashes;
1110 /* This can be used to stress tests the collision code */
1114 * We do this to simplify generic sharing. It will hurt
1115 * performance in cases where a class implements two different
1116 * instantiations of the same generic interface.
1117 * The code in build_imt_slots () depends on this.
1119 if (method->is_inflated)
1120 method = ((MonoMethodInflated*)method)->declaring;
1122 sig = mono_method_signature (method);
1123 hashes_count = sig->param_count + 4;
1124 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1125 hashes = hashes_start;
1127 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1128 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1129 method->klass->name_space, method->klass->name, method->name);
1132 /* Initialize hashes */
1133 hashes [0] = mono_metadata_str_hash (method->klass->name);
1134 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1135 hashes [2] = mono_metadata_str_hash (method->name);
1136 hashes [3] = mono_metadata_type_hash (sig->ret);
1137 for (i = 0; i < sig->param_count; i++) {
1138 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1141 /* Setup internal state */
1142 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1144 /* Handle most of the hashes */
1145 while (hashes_count > 3) {
1154 /* Handle the last 3 hashes (all the case statements fall through) */
1155 switch (hashes_count) {
1156 case 3 : c += hashes [2];
1157 case 2 : b += hashes [1];
1158 case 1 : a += hashes [0];
1160 case 0: /* nothing left to add */
1164 free (hashes_start);
1165 /* Report the result */
1166 return c % MONO_IMT_SIZE;
1175 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1176 MONO_REQ_GC_NEUTRAL_MODE;
1178 guint32 imt_slot = mono_method_get_imt_slot (method);
1179 MonoImtBuilderEntry *entry;
1181 if (slot_num >= 0 && imt_slot != slot_num) {
1182 /* we build just a single imt slot and this is not it */
1186 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1187 entry->key = method;
1188 entry->value.vtable_slot = vtable_slot;
1189 entry->next = imt_builder [imt_slot];
1190 if (imt_builder [imt_slot] != NULL) {
1191 entry->children = imt_builder [imt_slot]->children + 1;
1192 if (entry->children == 1) {
1193 mono_stats.imt_slots_with_collisions++;
1194 *imt_collisions_bitmap |= (1 << imt_slot);
1197 entry->children = 0;
1198 mono_stats.imt_used_slots++;
1200 imt_builder [imt_slot] = entry;
1203 char *method_name = mono_method_full_name (method, TRUE);
1204 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1205 method, method_name, imt_slot, vtable_slot, entry->children);
1206 g_free (method_name);
1213 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1215 MonoMethod *method = e->key;
1216 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1220 method->klass->name_space,
1221 method->klass->name,
1224 printf (" * %s: NULL\n", message);
1230 compare_imt_builder_entries (const void *p1, const void *p2) {
1231 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1232 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1234 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1238 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1240 MONO_REQ_GC_NEUTRAL_MODE;
1242 int count = end - start;
1243 int chunk_start = out_array->len;
1246 for (i = start; i < end; ++i) {
1247 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1248 item->key = sorted_array [i]->key;
1249 item->value = sorted_array [i]->value;
1250 item->has_target_code = sorted_array [i]->has_target_code;
1251 item->is_equals = TRUE;
1253 item->check_target_idx = out_array->len + 1;
1255 item->check_target_idx = 0;
1256 g_ptr_array_add (out_array, item);
1259 int middle = start + count / 2;
1260 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1262 item->key = sorted_array [middle]->key;
1263 item->is_equals = FALSE;
1264 g_ptr_array_add (out_array, item);
1265 imt_emit_ir (sorted_array, start, middle, out_array);
1266 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1272 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1273 MONO_REQ_GC_NEUTRAL_MODE;
1275 int number_of_entries = entries->children + 1;
1276 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1277 GPtrArray *result = g_ptr_array_new ();
1278 MonoImtBuilderEntry *current_entry;
1281 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1282 sorted_array [i] = current_entry;
1284 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1286 /*for (i = 0; i < number_of_entries; i++) {
1287 print_imt_entry (" sorted array:", sorted_array [i], i);
1290 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1292 free (sorted_array);
1297 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1299 MONO_REQ_GC_NEUTRAL_MODE;
1301 if (imt_builder_entry != NULL) {
1302 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1303 /* No collision, return the vtable slot contents */
1304 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1306 /* Collision, build the thunk */
1307 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1310 result = imt_thunk_builder (vtable, domain,
1311 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1312 for (i = 0; i < imt_ir->len; ++i)
1313 g_free (g_ptr_array_index (imt_ir, i));
1314 g_ptr_array_free (imt_ir, TRUE);
1326 static MonoImtBuilderEntry*
1327 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1330 * LOCKING: requires the loader and domain locks.
1334 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1336 MONO_REQ_GC_NEUTRAL_MODE;
1340 guint32 imt_collisions_bitmap = 0;
1341 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1342 int method_count = 0;
1343 gboolean record_method_count_for_max_collisions = FALSE;
1344 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1347 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1349 for (i = 0; i < klass->interface_offsets_count; ++i) {
1350 MonoClass *iface = klass->interfaces_packed [i];
1351 int interface_offset = klass->interface_offsets_packed [i];
1352 int method_slot_in_interface, vt_slot;
1354 if (mono_class_has_variant_generic_params (iface))
1355 has_variant_iface = TRUE;
1357 mono_class_setup_methods (iface);
1358 vt_slot = interface_offset;
1359 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1362 if (slot_num >= 0 && iface->is_inflated) {
1364 * The imt slot of the method is the same as for its declaring method,
1365 * see the comment in mono_method_get_imt_slot (), so we can
1366 * avoid inflating methods which will be discarded by
1367 * add_imt_builder_entry anyway.
1369 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1370 if (mono_method_get_imt_slot (method) != slot_num) {
1375 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1376 if (method->is_generic) {
1377 has_generic_virtual = TRUE;
1382 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1383 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1388 if (extra_interfaces) {
1389 int interface_offset = klass->vtable_size;
1391 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1392 MonoClass* iface = (MonoClass *)list_item->data;
1393 int method_slot_in_interface;
1394 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1395 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1397 if (method->is_generic)
1398 has_generic_virtual = TRUE;
1399 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1401 interface_offset += iface->method.count;
1404 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1405 /* overwrite the imt slot only if we're building all the entries or if
1406 * we're building this specific one
1408 if (slot_num < 0 || i == slot_num) {
1409 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1412 if (imt_builder [i]) {
1413 MonoImtBuilderEntry *entry;
1415 /* Link entries with imt_builder [i] */
1416 for (entry = entries; entry->next; entry = entry->next) {
1418 MonoMethod *method = (MonoMethod*)entry->key;
1419 char *method_name = mono_method_full_name (method, TRUE);
1420 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1421 g_free (method_name);
1424 entry->next = imt_builder [i];
1425 entries->children += imt_builder [i]->children + 1;
1427 imt_builder [i] = entries;
1430 if (has_generic_virtual || has_variant_iface) {
1432 * There might be collisions later when the the thunk is expanded.
1434 imt_collisions_bitmap |= (1 << i);
1437 * The IMT thunk might be called with an instance of one of the
1438 * generic virtual methods, so has to fallback to the IMT trampoline.
1440 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1442 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1445 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1449 if (imt_builder [i] != NULL) {
1450 int methods_in_slot = imt_builder [i]->children + 1;
1451 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1452 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1453 record_method_count_for_max_collisions = TRUE;
1455 method_count += methods_in_slot;
1459 mono_stats.imt_number_of_methods += method_count;
1460 if (record_method_count_for_max_collisions) {
1461 mono_stats.imt_method_count_when_max_collisions = method_count;
1464 for (i = 0; i < MONO_IMT_SIZE; i++) {
1465 MonoImtBuilderEntry* entry = imt_builder [i];
1466 while (entry != NULL) {
1467 MonoImtBuilderEntry* next = entry->next;
1473 /* we OR the bitmap since we may build just a single imt slot at a time */
1474 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1478 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1479 MONO_REQ_GC_NEUTRAL_MODE;
1481 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1485 * mono_vtable_build_imt_slot:
1486 * @vtable: virtual object table struct
1487 * @imt_slot: slot in the IMT table
1489 * Fill the given @imt_slot in the IMT table of @vtable with
1490 * a trampoline or a thunk for the case of collisions.
1491 * This is part of the internal mono API.
1493 * LOCKING: Take the domain lock.
1496 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1498 MONO_REQ_GC_NEUTRAL_MODE;
1500 gpointer *imt = (gpointer*)vtable;
1501 imt -= MONO_IMT_SIZE;
1502 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1504 /* no support for extra interfaces: the proxy objects will need
1505 * to build the complete IMT
1506 * Update and heck needs to ahppen inside the proper domain lock, as all
1507 * the changes made to a MonoVTable.
1509 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1510 mono_domain_lock (vtable->domain);
1511 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1512 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1513 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1514 mono_domain_unlock (vtable->domain);
1515 mono_loader_unlock ();
1520 * The first two free list entries both belong to the wait list: The
1521 * first entry is the pointer to the head of the list and the second
1522 * entry points to the last element. That way appending and removing
1523 * the first element are both O(1) operations.
1525 #ifdef MONO_SMALL_CONFIG
1526 #define NUM_FREE_LISTS 6
1528 #define NUM_FREE_LISTS 12
1530 #define FIRST_FREE_LIST_SIZE 64
1531 #define MAX_WAIT_LENGTH 50
1532 #define THUNK_THRESHOLD 10
1535 * LOCKING: The domain lock must be held.
1538 init_thunk_free_lists (MonoDomain *domain)
1540 MONO_REQ_GC_NEUTRAL_MODE;
1542 if (domain->thunk_free_lists)
1544 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1548 list_index_for_size (int item_size)
1551 int size = FIRST_FREE_LIST_SIZE;
1553 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1562 * mono_method_alloc_generic_virtual_thunk:
1564 * @size: size in bytes
1566 * Allocs size bytes to be used for the code of a generic virtual
1567 * thunk. It's either allocated from the domain's code manager or
1568 * reused from a previously invalidated piece.
1570 * LOCKING: The domain lock must be held.
1573 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1575 MONO_REQ_GC_NEUTRAL_MODE;
1577 static gboolean inited = FALSE;
1578 static int generic_virtual_thunks_size = 0;
1582 MonoThunkFreeList **l;
1584 init_thunk_free_lists (domain);
1586 size += sizeof (guint32);
1587 if (size < sizeof (MonoThunkFreeList))
1588 size = sizeof (MonoThunkFreeList);
1590 i = list_index_for_size (size);
1591 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1592 if ((*l)->size >= size) {
1593 MonoThunkFreeList *item = *l;
1595 return ((guint32*)item) + 1;
1599 /* no suitable item found - search lists of larger sizes */
1600 while (++i < NUM_FREE_LISTS) {
1601 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1604 g_assert (item->size > size);
1605 domain->thunk_free_lists [i] = item->next;
1606 return ((guint32*)item) + 1;
1609 /* still nothing found - allocate it */
1611 mono_counters_register ("Generic virtual thunk bytes",
1612 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1615 generic_virtual_thunks_size += size;
1617 p = (guint32 *)mono_domain_code_reserve (domain, size);
1620 mono_domain_lock (domain);
1621 if (!domain->generic_virtual_thunks)
1622 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1623 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1624 mono_domain_unlock (domain);
1630 * LOCKING: The domain lock must be held.
1633 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1635 MONO_REQ_GC_NEUTRAL_MODE;
1637 guint32 *p = (guint32 *)code;
1638 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1639 gboolean found = FALSE;
1641 mono_domain_lock (domain);
1642 if (!domain->generic_virtual_thunks)
1643 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1644 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1646 mono_domain_unlock (domain);
1649 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1651 init_thunk_free_lists (domain);
1653 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1654 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1655 int length = item->length;
1658 /* unlink the first item from the wait list */
1659 domain->thunk_free_lists [0] = item->next;
1660 domain->thunk_free_lists [0]->length = length - 1;
1662 i = list_index_for_size (item->size);
1664 /* put it in the free list */
1665 item->next = domain->thunk_free_lists [i];
1666 domain->thunk_free_lists [i] = item;
1670 if (domain->thunk_free_lists [1]) {
1671 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1672 domain->thunk_free_lists [0]->length++;
1674 g_assert (!domain->thunk_free_lists [0]);
1676 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1677 domain->thunk_free_lists [0]->length = 1;
1681 typedef struct _GenericVirtualCase {
1685 struct _GenericVirtualCase *next;
1686 } GenericVirtualCase;
1689 * get_generic_virtual_entries:
1691 * Return IMT entries for the generic virtual method instances and
1692 * variant interface methods for vtable slot
1695 static MonoImtBuilderEntry*
1696 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1698 MONO_REQ_GC_NEUTRAL_MODE;
1700 GenericVirtualCase *list;
1701 MonoImtBuilderEntry *entries;
1703 mono_domain_lock (domain);
1704 if (!domain->generic_virtual_cases)
1705 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1707 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 for (; list; list = list->next) {
1711 MonoImtBuilderEntry *entry;
1713 if (list->count < THUNK_THRESHOLD)
1716 entry = g_new0 (MonoImtBuilderEntry, 1);
1717 entry->key = list->method;
1718 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1719 entry->has_target_code = 1;
1721 entry->children = entries->children + 1;
1722 entry->next = entries;
1726 mono_domain_unlock (domain);
1728 /* FIXME: Leaking memory ? */
1733 * mono_method_add_generic_virtual_invocation:
1735 * @vtable_slot: pointer to the vtable slot
1736 * @method: the inflated generic virtual method
1737 * @code: the method's code
1739 * Registers a call via unmanaged code to a generic virtual method
1740 * instantiation or variant interface method. If the number of calls reaches a threshold
1741 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1742 * virtual method thunk.
1745 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1746 gpointer *vtable_slot,
1747 MonoMethod *method, gpointer code)
1749 MONO_REQ_GC_NEUTRAL_MODE;
1751 static gboolean inited = FALSE;
1752 static int num_added = 0;
1754 GenericVirtualCase *gvc, *list;
1755 MonoImtBuilderEntry *entries;
1759 mono_domain_lock (domain);
1760 if (!domain->generic_virtual_cases)
1761 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1763 /* Check whether the case was already added */
1764 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1767 if (gvc->method == method)
1772 /* If not found, make a new one */
1774 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1775 gvc->method = method;
1778 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1780 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1783 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1789 if (++gvc->count == THUNK_THRESHOLD) {
1790 gpointer *old_thunk = (void **)*vtable_slot;
1791 gpointer vtable_trampoline = NULL;
1792 gpointer imt_trampoline = NULL;
1794 if ((gpointer)vtable_slot < (gpointer)vtable) {
1795 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1796 int imt_slot = MONO_IMT_SIZE + displacement;
1798 /* Force the rebuild of the thunk at the next call */
1799 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1800 *vtable_slot = imt_trampoline;
1802 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1804 entries = get_generic_virtual_entries (domain, vtable_slot);
1806 sorted = imt_sort_slot_entries (entries);
1808 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1812 MonoImtBuilderEntry *next = entries->next;
1817 for (i = 0; i < sorted->len; ++i)
1818 g_free (g_ptr_array_index (sorted, i));
1819 g_ptr_array_free (sorted, TRUE);
1822 #ifndef __native_client__
1823 /* We don't re-use any thunks as there is a lot of overhead */
1824 /* to deleting and re-using code in Native Client. */
1825 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1826 invalidate_generic_virtual_thunk (domain, old_thunk);
1830 mono_domain_unlock (domain);
1833 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error);
1836 * mono_class_vtable:
1837 * @domain: the application domain
1838 * @class: the class to initialize
1840 * VTables are domain specific because we create domain specific code, and
1841 * they contain the domain specific static class data.
1842 * On failure, NULL is returned, and class->exception_type is set.
1845 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1847 return mono_class_vtable_full (domain, klass, FALSE);
1851 * mono_class_vtable_full:
1852 * @domain: the application domain
1853 * @class: the class to initialize
1854 * @raise_on_error if an exception should be raised on failure or not
1856 * VTables are domain specific because we create domain specific code, and
1857 * they contain the domain specific static class data.
1860 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1862 MONO_REQ_GC_UNSAFE_MODE;
1864 MonoClassRuntimeInfo *runtime_info;
1868 if (klass->exception_type) {
1870 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1874 /* this check can be inlined in jitted code, too */
1875 runtime_info = klass->runtime_info;
1876 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1877 return runtime_info->domain_vtables [domain->domain_id];
1878 return mono_class_create_runtime_vtable (domain, klass, raise_on_error);
1882 * mono_class_try_get_vtable:
1883 * @domain: the application domain
1884 * @class: the class to initialize
1886 * This function tries to get the associated vtable from @class if
1887 * it was already created.
1890 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1892 MONO_REQ_GC_NEUTRAL_MODE;
1894 MonoClassRuntimeInfo *runtime_info;
1898 runtime_info = klass->runtime_info;
1899 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1900 return runtime_info->domain_vtables [domain->domain_id];
1905 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1907 MONO_REQ_GC_NEUTRAL_MODE;
1909 size_t alloc_offset;
1912 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1913 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1914 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1916 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1917 g_assert ((imt_table_bytes & 7) == 4);
1924 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1928 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, gboolean raise_on_error)
1930 MONO_REQ_GC_UNSAFE_MODE;
1934 MonoClassRuntimeInfo *runtime_info, *old_info;
1935 MonoClassField *field;
1937 int i, vtable_slots;
1938 size_t imt_table_bytes;
1940 guint32 vtable_size, class_size;
1942 gpointer *interface_offsets;
1944 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1945 mono_domain_lock (domain);
1946 runtime_info = klass->runtime_info;
1947 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1948 mono_domain_unlock (domain);
1949 mono_loader_unlock ();
1950 return runtime_info->domain_vtables [domain->domain_id];
1952 if (!klass->inited || klass->exception_type) {
1953 if (!mono_class_init (klass) || klass->exception_type) {
1954 mono_domain_unlock (domain);
1955 mono_loader_unlock ();
1957 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1962 /* Array types require that their element type be valid*/
1963 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1964 MonoClass *element_class = klass->element_class;
1965 if (!element_class->inited)
1966 mono_class_init (element_class);
1968 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1969 if (element_class->exception_type == MONO_EXCEPTION_NONE && !element_class->vtable_size)
1970 mono_class_setup_vtable (element_class);
1972 if (element_class->exception_type != MONO_EXCEPTION_NONE) {
1973 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1974 if (klass->exception_type == MONO_EXCEPTION_NONE)
1975 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1976 mono_domain_unlock (domain);
1977 mono_loader_unlock ();
1979 mono_raise_exception (mono_class_get_exception_for_failure (klass));
1985 * For some classes, mono_class_init () already computed klass->vtable_size, and
1986 * that is all that is needed because of the vtable trampolines.
1988 if (!klass->vtable_size)
1989 mono_class_setup_vtable (klass);
1991 if (klass->generic_class && !klass->vtable)
1992 mono_class_check_vtable_constraints (klass, NULL);
1994 /* Initialize klass->has_finalize */
1995 mono_class_has_finalizer (klass);
1997 if (klass->exception_type) {
1998 mono_domain_unlock (domain);
1999 mono_loader_unlock ();
2001 mono_raise_exception (mono_class_get_exception_for_failure (klass));
2005 vtable_slots = klass->vtable_size;
2006 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2007 class_size = mono_class_data_size (klass);
2011 if (klass->interface_offsets_count) {
2012 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2013 mono_stats.imt_number_of_tables++;
2014 mono_stats.imt_tables_size += imt_table_bytes;
2016 imt_table_bytes = 0;
2019 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2021 mono_stats.used_class_count++;
2022 mono_stats.class_vtable_size += vtable_size;
2024 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2025 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2026 g_assert (!((gsize)vt & 7));
2029 vt->rank = klass->rank;
2030 vt->domain = domain;
2032 mono_class_compute_gc_descriptor (klass);
2034 * We can't use typed allocation in the non-root domains, since the
2035 * collector needs the GC descriptor stored in the vtable even after
2036 * the mempool containing the vtable is destroyed when the domain is
2037 * unloaded. An alternative might be to allocate vtables in the GC
2038 * heap, but this does not seem to work (it leads to crashes inside
2039 * libgc). If that approach is tried, two gc descriptors need to be
2040 * allocated for each class: one for the root domain, and one for all
2041 * other domains. The second descriptor should contain a bit for the
2042 * vtable field in MonoObject, since we can no longer assume the
2043 * vtable is reachable by other roots after the appdomain is unloaded.
2045 #ifdef HAVE_BOEHM_GC
2046 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2047 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2050 vt->gc_descr = klass->gc_descr;
2052 gc_bits = mono_gc_get_vtable_bits (klass);
2053 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2055 vt->gc_bits = gc_bits;
2058 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2059 if (klass->has_static_refs) {
2060 MonoGCDescriptor statics_gc_descr;
2062 gsize default_bitmap [4] = {0};
2065 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2066 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2067 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2068 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2069 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2070 if (bitmap != default_bitmap)
2073 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2075 vt->has_static_fields = TRUE;
2076 mono_stats.class_static_data_size += class_size;
2080 while ((field = mono_class_get_fields (klass, &iter))) {
2081 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2083 if (mono_field_is_deleted (field))
2085 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2086 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2087 if (special_static != SPECIAL_STATIC_NONE) {
2088 guint32 size, offset;
2090 gsize default_bitmap [4] = {0};
2095 if (mono_type_is_reference (field->type)) {
2096 default_bitmap [0] = 1;
2098 bitmap = default_bitmap;
2099 } else if (mono_type_is_struct (field->type)) {
2100 fclass = mono_class_from_mono_type (field->type);
2101 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2102 numbits = max_set + 1;
2104 default_bitmap [0] = 0;
2106 bitmap = default_bitmap;
2108 size = mono_type_size (field->type, &align);
2109 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2110 if (!domain->special_static_fields)
2111 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2112 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2113 if (bitmap != default_bitmap)
2116 * This marks the field as special static to speed up the
2117 * checks in mono_field_static_get/set_value ().
2123 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2124 MonoClass *fklass = mono_class_from_mono_type (field->type);
2125 const char *data = mono_field_get_data (field);
2127 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2128 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2129 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2132 if (fklass->valuetype) {
2133 memcpy (t, data, mono_class_value_size (fklass, NULL));
2135 /* it's a pointer type: add check */
2136 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2143 vt->max_interface_id = klass->max_interface_id;
2144 vt->interface_bitmap = klass->interface_bitmap;
2146 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2147 // class->name, klass->interface_offsets_count);
2149 /* Initialize vtable */
2150 if (callbacks.get_vtable_trampoline) {
2151 // This also covers the AOT case
2152 for (i = 0; i < klass->vtable_size; ++i) {
2153 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2156 mono_class_setup_vtable (klass);
2158 for (i = 0; i < klass->vtable_size; ++i) {
2161 if ((cm = klass->vtable [i]))
2162 vt->vtable [i] = arch_create_jit_trampoline (cm);
2166 if (imt_table_bytes) {
2167 /* Now that the vtable is full, we can actually fill up the IMT */
2168 for (i = 0; i < MONO_IMT_SIZE; ++i)
2169 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2173 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2174 * re-acquire them and check if another thread has created the vtable in the meantime.
2176 /* Special case System.MonoType to avoid infinite recursion */
2177 if (klass != mono_defaults.monotype_class) {
2178 /*FIXME check for OOM*/
2179 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2180 mono_error_raise_exception (&error); /* FIXME don't raise here */
2182 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2183 /* This is unregistered in
2184 unregister_vtable_reflection_type() in
2186 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2189 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2191 /* class_vtable_array keeps an array of created vtables
2193 g_ptr_array_add (domain->class_vtable_array, vt);
2194 /* klass->runtime_info is protected by the loader lock, both when
2195 * it it enlarged and when it is stored info.
2199 * Store the vtable in klass->runtime_info.
2200 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2202 mono_memory_barrier ();
2204 old_info = klass->runtime_info;
2205 if (old_info && old_info->max_domain >= domain->domain_id) {
2206 /* someone already created a large enough runtime info */
2207 old_info->domain_vtables [domain->domain_id] = vt;
2209 int new_size = domain->domain_id;
2211 new_size = MAX (new_size, old_info->max_domain);
2213 /* make the new size a power of two */
2215 while (new_size > i)
2218 /* this is a bounded memory retention issue: may want to
2219 * handle it differently when we'll have a rcu-like system.
2221 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2222 runtime_info->max_domain = new_size - 1;
2223 /* copy the stuff from the older info */
2225 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2227 runtime_info->domain_vtables [domain->domain_id] = vt;
2229 mono_memory_barrier ();
2230 klass->runtime_info = runtime_info;
2233 if (klass == mono_defaults.monotype_class) {
2234 /*FIXME check for OOM*/
2235 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
2236 mono_error_raise_exception (&error); /* FIXME don't raise here */
2238 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2239 /* This is unregistered in
2240 unregister_vtable_reflection_type() in
2242 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2245 mono_domain_unlock (domain);
2246 mono_loader_unlock ();
2248 /* make sure the parent is initialized */
2249 /*FIXME shouldn't this fail the current type?*/
2251 mono_class_vtable_full (domain, klass->parent, raise_on_error);
2256 #ifndef DISABLE_REMOTING
2258 * mono_class_proxy_vtable:
2259 * @domain: the application domain
2260 * @remove_class: the remote class
2262 * Creates a vtable for transparent proxies. It is basically
2263 * a copy of the real vtable of the class wrapped in @remote_class,
2264 * but all function pointers invoke the remoting functions, and
2265 * vtable->klass points to the transparent proxy class, and not to @class.
2268 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2270 MONO_REQ_GC_UNSAFE_MODE;
2273 MonoVTable *vt, *pvt;
2274 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2276 GSList *extra_interfaces = NULL;
2277 MonoClass *klass = remote_class->proxy_class;
2278 gpointer *interface_offsets;
2281 size_t imt_table_bytes;
2283 #ifdef COMPRESSED_INTERFACE_BITMAP
2287 vt = mono_class_vtable (domain, klass);
2288 g_assert (vt); /*FIXME property handle failure*/
2289 max_interface_id = vt->max_interface_id;
2291 /* Calculate vtable space for extra interfaces */
2292 for (j = 0; j < remote_class->interface_count; j++) {
2293 MonoClass* iclass = remote_class->interfaces[j];
2297 /*FIXME test for interfaces with variant generic arguments*/
2298 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2299 continue; /* interface implemented by the class */
2300 if (g_slist_find (extra_interfaces, iclass))
2303 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2305 method_count = mono_class_num_methods (iclass);
2307 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2308 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2310 for (i = 0; i < ifaces->len; ++i) {
2311 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2312 /*FIXME test for interfaces with variant generic arguments*/
2313 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2314 continue; /* interface implemented by the class */
2315 if (g_slist_find (extra_interfaces, ic))
2317 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2318 method_count += mono_class_num_methods (ic);
2320 g_ptr_array_free (ifaces, TRUE);
2323 extra_interface_vtsize += method_count * sizeof (gpointer);
2324 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2327 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2328 mono_stats.imt_number_of_tables++;
2329 mono_stats.imt_tables_size += imt_table_bytes;
2331 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2333 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2335 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2336 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2337 g_assert (!((gsize)pvt & 7));
2339 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2341 pvt->klass = mono_defaults.transparent_proxy_class;
2342 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2343 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2345 /* initialize vtable */
2346 mono_class_setup_vtable (klass);
2347 for (i = 0; i < klass->vtable_size; ++i) {
2350 if ((cm = klass->vtable [i]))
2351 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2353 pvt->vtable [i] = NULL;
2356 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2357 /* create trampolines for abstract methods */
2358 for (k = klass; k; k = k->parent) {
2360 gpointer iter = NULL;
2361 while ((m = mono_class_get_methods (k, &iter)))
2362 if (!pvt->vtable [m->slot])
2363 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2367 pvt->max_interface_id = max_interface_id;
2368 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2369 #ifdef COMPRESSED_INTERFACE_BITMAP
2370 bitmap = (uint8_t *)g_malloc0 (bsize);
2372 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2375 for (i = 0; i < klass->interface_offsets_count; ++i) {
2376 int interface_id = klass->interfaces_packed [i]->interface_id;
2377 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2380 if (extra_interfaces) {
2381 int slot = klass->vtable_size;
2387 /* Create trampolines for the methods of the interfaces */
2388 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2389 interf = (MonoClass *)list_item->data;
2391 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2395 while ((cm = mono_class_get_methods (interf, &iter)))
2396 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2398 slot += mono_class_num_methods (interf);
2402 /* Now that the vtable is full, we can actually fill up the IMT */
2403 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2404 if (extra_interfaces) {
2405 g_slist_free (extra_interfaces);
2408 #ifdef COMPRESSED_INTERFACE_BITMAP
2409 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2410 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2411 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2414 pvt->interface_bitmap = bitmap;
2419 #endif /* DISABLE_REMOTING */
2422 * mono_class_field_is_special_static:
2424 * Returns whether @field is a thread/context static field.
2427 mono_class_field_is_special_static (MonoClassField *field)
2429 MONO_REQ_GC_NEUTRAL_MODE
2431 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2433 if (mono_field_is_deleted (field))
2435 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2436 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2443 * mono_class_field_get_special_static_type:
2444 * @field: The MonoClassField describing the field.
2446 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2447 * SPECIAL_STATIC_NONE otherwise.
2450 mono_class_field_get_special_static_type (MonoClassField *field)
2452 MONO_REQ_GC_NEUTRAL_MODE
2454 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2455 return SPECIAL_STATIC_NONE;
2456 if (mono_field_is_deleted (field))
2457 return SPECIAL_STATIC_NONE;
2458 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2459 return field_is_special_static (field->parent, field);
2460 return SPECIAL_STATIC_NONE;
2464 * mono_class_has_special_static_fields:
2466 * Returns whenever @klass has any thread/context static fields.
2469 mono_class_has_special_static_fields (MonoClass *klass)
2471 MONO_REQ_GC_NEUTRAL_MODE
2473 MonoClassField *field;
2477 while ((field = mono_class_get_fields (klass, &iter))) {
2478 g_assert (field->parent == klass);
2479 if (mono_class_field_is_special_static (field))
2486 #ifndef DISABLE_REMOTING
2488 * create_remote_class_key:
2489 * Creates an array of pointers that can be used as a hash key for a remote class.
2490 * The first element of the array is the number of pointers.
2493 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2495 MONO_REQ_GC_NEUTRAL_MODE;
2500 if (remote_class == NULL) {
2501 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2502 key = (void **)g_malloc (sizeof(gpointer) * 3);
2503 key [0] = GINT_TO_POINTER (2);
2504 key [1] = mono_defaults.marshalbyrefobject_class;
2505 key [2] = extra_class;
2507 key = (void **)g_malloc (sizeof(gpointer) * 2);
2508 key [0] = GINT_TO_POINTER (1);
2509 key [1] = extra_class;
2512 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2513 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2514 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2515 key [1] = remote_class->proxy_class;
2517 // Keep the list of interfaces sorted
2518 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2519 if (extra_class && remote_class->interfaces [i] > extra_class) {
2520 key [j++] = extra_class;
2523 key [j] = remote_class->interfaces [i];
2526 key [j] = extra_class;
2528 // Replace the old class. The interface list is the same
2529 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2530 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2531 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2532 for (i = 0; i < remote_class->interface_count; i++)
2533 key [2 + i] = remote_class->interfaces [i];
2541 * copy_remote_class_key:
2543 * Make a copy of KEY in the domain and return the copy.
2546 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2548 MONO_REQ_GC_NEUTRAL_MODE
2550 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2551 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2553 memcpy (mp_key, key, key_size);
2559 * mono_remote_class:
2560 * @domain: the application domain
2561 * @class_name: name of the remote class
2563 * Creates and initializes a MonoRemoteClass object for a remote type.
2565 * Can raise an exception on failure.
2568 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2570 MONO_REQ_GC_UNSAFE_MODE;
2573 MonoRemoteClass *rc;
2574 gpointer* key, *mp_key;
2577 key = create_remote_class_key (NULL, proxy_class);
2579 mono_domain_lock (domain);
2580 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2584 mono_domain_unlock (domain);
2588 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2589 if (!mono_error_ok (&error)) {
2591 mono_domain_unlock (domain);
2592 mono_error_raise_exception (&error);
2595 mp_key = copy_remote_class_key (domain, key);
2599 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2600 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2601 rc->interface_count = 1;
2602 rc->interfaces [0] = proxy_class;
2603 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2605 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2606 rc->interface_count = 0;
2607 rc->proxy_class = proxy_class;
2610 rc->default_vtable = NULL;
2611 rc->xdomain_vtable = NULL;
2612 rc->proxy_class_name = name;
2613 #ifndef DISABLE_PERFCOUNTERS
2614 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2617 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2619 mono_domain_unlock (domain);
2624 * clone_remote_class:
2625 * Creates a copy of the remote_class, adding the provided class or interface
2627 static MonoRemoteClass*
2628 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2630 MONO_REQ_GC_NEUTRAL_MODE;
2632 MonoRemoteClass *rc;
2633 gpointer* key, *mp_key;
2635 key = create_remote_class_key (remote_class, extra_class);
2636 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2642 mp_key = copy_remote_class_key (domain, key);
2646 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2648 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2649 rc->proxy_class = remote_class->proxy_class;
2650 rc->interface_count = remote_class->interface_count + 1;
2652 // Keep the list of interfaces sorted, since the hash key of
2653 // the remote class depends on this
2654 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2655 if (remote_class->interfaces [i] > extra_class && i == j)
2656 rc->interfaces [j++] = extra_class;
2657 rc->interfaces [j] = remote_class->interfaces [i];
2660 rc->interfaces [j] = extra_class;
2662 // Replace the old class. The interface array is the same
2663 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2664 rc->proxy_class = extra_class;
2665 rc->interface_count = remote_class->interface_count;
2666 if (rc->interface_count > 0)
2667 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2670 rc->default_vtable = NULL;
2671 rc->xdomain_vtable = NULL;
2672 rc->proxy_class_name = remote_class->proxy_class_name;
2674 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2680 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2682 MONO_REQ_GC_UNSAFE_MODE;
2684 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2685 mono_domain_lock (domain);
2686 if (rp->target_domain_id != -1) {
2687 if (remote_class->xdomain_vtable == NULL)
2688 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2689 mono_domain_unlock (domain);
2690 mono_loader_unlock ();
2691 return remote_class->xdomain_vtable;
2693 if (remote_class->default_vtable == NULL) {
2696 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2697 klass = mono_class_from_mono_type (type);
2699 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)))
2700 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2703 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2706 mono_domain_unlock (domain);
2707 mono_loader_unlock ();
2708 return remote_class->default_vtable;
2712 * mono_upgrade_remote_class:
2713 * @domain: the application domain
2714 * @tproxy: the proxy whose remote class has to be upgraded.
2715 * @klass: class to which the remote class can be casted.
2717 * Updates the vtable of the remote class by adding the necessary method slots
2718 * and interface offsets so it can be safely casted to klass. klass can be a
2719 * class or an interface.
2722 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2724 MONO_REQ_GC_UNSAFE_MODE;
2726 MonoTransparentProxy *tproxy;
2727 MonoRemoteClass *remote_class;
2728 gboolean redo_vtable;
2730 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2731 mono_domain_lock (domain);
2733 tproxy = (MonoTransparentProxy*) proxy_object;
2734 remote_class = tproxy->remote_class;
2736 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2739 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2740 if (remote_class->interfaces [i] == klass)
2741 redo_vtable = FALSE;
2744 redo_vtable = (remote_class->proxy_class != klass);
2748 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2749 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2752 mono_domain_unlock (domain);
2753 mono_loader_unlock ();
2755 #endif /* DISABLE_REMOTING */
2759 * mono_object_get_virtual_method:
2760 * @obj: object to operate on.
2763 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2764 * the instance of a callvirt of method.
2767 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2769 MONO_REQ_GC_UNSAFE_MODE;
2772 MonoMethod **vtable;
2773 gboolean is_proxy = FALSE;
2774 MonoMethod *res = NULL;
2776 klass = mono_object_class (obj);
2777 #ifndef DISABLE_REMOTING
2778 if (klass == mono_defaults.transparent_proxy_class) {
2779 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2784 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2787 mono_class_setup_vtable (klass);
2788 vtable = klass->vtable;
2790 if (method->slot == -1) {
2791 /* method->slot might not be set for instances of generic methods */
2792 if (method->is_inflated) {
2793 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2794 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2797 g_assert_not_reached ();
2801 /* check method->slot is a valid index: perform isinstance? */
2802 if (method->slot != -1) {
2803 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2805 gboolean variance_used = FALSE;
2806 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2807 g_assert (iface_offset > 0);
2808 res = vtable [iface_offset + method->slot];
2811 res = vtable [method->slot];
2815 #ifndef DISABLE_REMOTING
2817 /* It may be an interface, abstract class method or generic method */
2818 if (!res || mono_method_signature (res)->generic_param_count)
2821 /* generic methods demand invoke_with_check */
2822 if (mono_method_signature (res)->generic_param_count)
2823 res = mono_marshal_get_remoting_invoke_with_check (res);
2826 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2827 res = mono_cominterop_get_invoke (res);
2830 res = mono_marshal_get_remoting_invoke (res);
2835 if (method->is_inflated) {
2837 /* Have to inflate the result */
2838 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2839 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2849 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2851 MONO_REQ_GC_UNSAFE_MODE;
2853 MonoObject *result = NULL;
2855 g_assert (callbacks.runtime_invoke);
2857 mono_error_init (error);
2859 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2860 mono_profiler_method_start_invoke (method);
2862 MONO_PREPARE_RESET_BLOCKING;
2864 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2866 MONO_FINISH_RESET_BLOCKING;
2868 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2869 mono_profiler_method_end_invoke (method);
2871 if (!mono_error_ok (error))
2878 * mono_runtime_invoke:
2879 * @method: method to invoke
2880 * @obJ: object instance
2881 * @params: arguments to the method
2882 * @exc: exception information.
2884 * Invokes the method represented by @method on the object @obj.
2886 * obj is the 'this' pointer, it should be NULL for static
2887 * methods, a MonoObject* for object instances and a pointer to
2888 * the value type for value types.
2890 * The params array contains the arguments to the method with the
2891 * same convention: MonoObject* pointers for object instances and
2892 * pointers to the value type otherwise.
2894 * From unmanaged code you'll usually use the
2895 * mono_runtime_invoke() variant.
2897 * Note that this function doesn't handle virtual methods for
2898 * you, it will exec the exact method you pass: we still need to
2899 * expose a function to lookup the derived class implementation
2900 * of a virtual method (there are examples of this in the code,
2903 * You can pass NULL as the exc argument if you don't want to
2904 * catch exceptions, otherwise, *exc will be set to the exception
2905 * thrown, if any. if an exception is thrown, you can't use the
2906 * MonoObject* result from the function.
2908 * If the method returns a value type, it is boxed in an object
2912 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2917 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2918 if (*exc == NULL && !mono_error_ok(&error)) {
2919 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2921 mono_error_cleanup (&error);
2923 res = mono_runtime_invoke_checked (method, obj, params, &error);
2924 mono_error_raise_exception (&error);
2930 * mono_runtime_try_invoke:
2931 * @method: method to invoke
2932 * @obJ: object instance
2933 * @params: arguments to the method
2934 * @exc: exception information.
2935 * @error: set on error
2937 * Invokes the method represented by @method on the object @obj.
2939 * obj is the 'this' pointer, it should be NULL for static
2940 * methods, a MonoObject* for object instances and a pointer to
2941 * the value type for value types.
2943 * The params array contains the arguments to the method with the
2944 * same convention: MonoObject* pointers for object instances and
2945 * pointers to the value type otherwise.
2947 * From unmanaged code you'll usually use the
2948 * mono_runtime_invoke() variant.
2950 * Note that this function doesn't handle virtual methods for
2951 * you, it will exec the exact method you pass: we still need to
2952 * expose a function to lookup the derived class implementation
2953 * of a virtual method (there are examples of this in the code,
2956 * For this function, you must not pass NULL as the exc argument if
2957 * you don't want to catch exceptions, use
2958 * mono_runtime_invoke_checked(). If an exception is thrown, you
2959 * can't use the MonoObject* result from the function.
2961 * If this method cannot be invoked, @error will be set and @exc and
2962 * the return value must not be used.
2964 * If the method returns a value type, it is boxed in an object
2968 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2970 MONO_REQ_GC_UNSAFE_MODE;
2972 g_assert (exc != NULL);
2974 if (mono_runtime_get_no_exec ())
2975 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2977 return do_runtime_invoke (method, obj, params, exc, error);
2981 * mono_runtime_invoke_checked:
2982 * @method: method to invoke
2983 * @obJ: object instance
2984 * @params: arguments to the method
2985 * @error: set on error
2987 * Invokes the method represented by @method on the object @obj.
2989 * obj is the 'this' pointer, it should be NULL for static
2990 * methods, a MonoObject* for object instances and a pointer to
2991 * the value type for value types.
2993 * The params array contains the arguments to the method with the
2994 * same convention: MonoObject* pointers for object instances and
2995 * pointers to the value type otherwise.
2997 * From unmanaged code you'll usually use the
2998 * mono_runtime_invoke() variant.
3000 * Note that this function doesn't handle virtual methods for
3001 * you, it will exec the exact method you pass: we still need to
3002 * expose a function to lookup the derived class implementation
3003 * of a virtual method (there are examples of this in the code,
3006 * If an exception is thrown, you can't use the MonoObject* result
3007 * from the function.
3009 * If this method cannot be invoked, @error will be set. If the
3010 * method throws an exception (and we're in coop mode) the exception
3011 * will be set in @error.
3013 * If the method returns a value type, it is boxed in an object
3017 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3019 MONO_REQ_GC_UNSAFE_MODE;
3021 if (mono_runtime_get_no_exec ())
3022 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3024 return do_runtime_invoke (method, obj, params, NULL, error);
3028 * mono_method_get_unmanaged_thunk:
3029 * @method: method to generate a thunk for.
3031 * Returns an unmanaged->managed thunk that can be used to call
3032 * a managed method directly from C.
3034 * The thunk's C signature closely matches the managed signature:
3036 * C#: public bool Equals (object obj);
3037 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3038 * MonoObject*, MonoException**);
3040 * The 1st ("this") parameter must not be used with static methods:
3042 * C#: public static bool ReferenceEquals (object a, object b);
3043 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3046 * The last argument must be a non-null pointer of a MonoException* pointer.
3047 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3048 * exception has been thrown in managed code. Otherwise it will point
3049 * to the MonoException* caught by the thunk. In this case, the result of
3050 * the thunk is undefined:
3052 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3053 * MonoException *ex = NULL;
3054 * Equals func = mono_method_get_unmanaged_thunk (method);
3055 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3057 * // handle exception
3060 * The calling convention of the thunk matches the platform's default
3061 * convention. This means that under Windows, C declarations must
3062 * contain the __stdcall attribute:
3064 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3065 * MonoObject*, MonoException**);
3069 * Value type arguments and return values are treated as they were objects:
3071 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3072 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3074 * Arguments must be properly boxed upon trunk's invocation, while return
3075 * values must be unboxed.
3078 mono_method_get_unmanaged_thunk (MonoMethod *method)
3080 MONO_REQ_GC_NEUTRAL_MODE;
3081 MONO_REQ_API_ENTRYPOINT;
3085 MONO_PREPARE_RESET_BLOCKING;
3086 method = mono_marshal_get_thunk_invoke_wrapper (method);
3087 res = mono_compile_method (method);
3088 MONO_FINISH_RESET_BLOCKING;
3094 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3096 MONO_REQ_GC_UNSAFE_MODE;
3100 /* object fields cannot be byref, so we don't need a
3102 gpointer *p = (gpointer*)dest;
3109 case MONO_TYPE_BOOLEAN:
3111 case MONO_TYPE_U1: {
3112 guint8 *p = (guint8*)dest;
3113 *p = value ? *(guint8*)value : 0;
3118 case MONO_TYPE_CHAR: {
3119 guint16 *p = (guint16*)dest;
3120 *p = value ? *(guint16*)value : 0;
3123 #if SIZEOF_VOID_P == 4
3128 case MONO_TYPE_U4: {
3129 gint32 *p = (gint32*)dest;
3130 *p = value ? *(gint32*)value : 0;
3133 #if SIZEOF_VOID_P == 8
3138 case MONO_TYPE_U8: {
3139 gint64 *p = (gint64*)dest;
3140 *p = value ? *(gint64*)value : 0;
3143 case MONO_TYPE_R4: {
3144 float *p = (float*)dest;
3145 *p = value ? *(float*)value : 0;
3148 case MONO_TYPE_R8: {
3149 double *p = (double*)dest;
3150 *p = value ? *(double*)value : 0;
3153 case MONO_TYPE_STRING:
3154 case MONO_TYPE_SZARRAY:
3155 case MONO_TYPE_CLASS:
3156 case MONO_TYPE_OBJECT:
3157 case MONO_TYPE_ARRAY:
3158 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3160 case MONO_TYPE_FNPTR:
3161 case MONO_TYPE_PTR: {
3162 gpointer *p = (gpointer*)dest;
3163 *p = deref_pointer? *(gpointer*)value: value;
3166 case MONO_TYPE_VALUETYPE:
3167 /* note that 't' and 'type->type' can be different */
3168 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3169 t = mono_class_enum_basetype (type->data.klass)->type;
3172 MonoClass *klass = mono_class_from_mono_type (type);
3173 int size = mono_class_value_size (klass, NULL);
3175 mono_gc_bzero_atomic (dest, size);
3177 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3180 case MONO_TYPE_GENERICINST:
3181 t = type->data.generic_class->container_class->byval_arg.type;
3184 g_error ("got type %x", type->type);
3189 * mono_field_set_value:
3190 * @obj: Instance object
3191 * @field: MonoClassField describing the field to set
3192 * @value: The value to be set
3194 * Sets the value of the field described by @field in the object instance @obj
3195 * to the value passed in @value. This method should only be used for instance
3196 * fields. For static fields, use mono_field_static_set_value.
3198 * The value must be on the native format of the field type.
3201 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3203 MONO_REQ_GC_UNSAFE_MODE;
3207 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3209 dest = (char*)obj + field->offset;
3210 mono_copy_value (field->type, dest, value, FALSE);
3214 * mono_field_static_set_value:
3215 * @field: MonoClassField describing the field to set
3216 * @value: The value to be set
3218 * Sets the value of the static field described by @field
3219 * to the value passed in @value.
3221 * The value must be on the native format of the field type.
3224 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3226 MONO_REQ_GC_UNSAFE_MODE;
3230 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3231 /* you cant set a constant! */
3232 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3234 if (field->offset == -1) {
3235 /* Special static */
3238 mono_domain_lock (vt->domain);
3239 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3240 mono_domain_unlock (vt->domain);
3241 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3243 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3245 mono_copy_value (field->type, dest, value, FALSE);
3249 * mono_vtable_get_static_field_data:
3251 * Internal use function: return a pointer to the memory holding the static fields
3252 * for a class or NULL if there are no static fields.
3253 * This is exported only for use by the debugger.
3256 mono_vtable_get_static_field_data (MonoVTable *vt)
3258 MONO_REQ_GC_NEUTRAL_MODE
3260 if (!vt->has_static_fields)
3262 return vt->vtable [vt->klass->vtable_size];
3266 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3268 MONO_REQ_GC_UNSAFE_MODE;
3272 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3273 if (field->offset == -1) {
3274 /* Special static */
3277 mono_domain_lock (vt->domain);
3278 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3279 mono_domain_unlock (vt->domain);
3280 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3282 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3285 src = (guint8*)obj + field->offset;
3292 * mono_field_get_value:
3293 * @obj: Object instance
3294 * @field: MonoClassField describing the field to fetch information from
3295 * @value: pointer to the location where the value will be stored
3297 * Use this routine to get the value of the field @field in the object
3300 * The pointer provided by value must be of the field type, for reference
3301 * types this is a MonoObject*, for value types its the actual pointer to
3306 * mono_field_get_value (obj, int_field, &i);
3309 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3311 MONO_REQ_GC_UNSAFE_MODE;
3317 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3319 src = (char*)obj + field->offset;
3320 mono_copy_value (field->type, value, src, TRUE);
3324 * mono_field_get_value_object:
3325 * @domain: domain where the object will be created (if boxing)
3326 * @field: MonoClassField describing the field to fetch information from
3327 * @obj: The object instance for the field.
3329 * Returns: a new MonoObject with the value from the given field. If the
3330 * field represents a value type, the value is boxed.
3334 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3336 MONO_REQ_GC_UNSAFE_MODE;
3341 MonoVTable *vtable = NULL;
3343 gboolean is_static = FALSE;
3344 gboolean is_ref = FALSE;
3345 gboolean is_literal = FALSE;
3346 gboolean is_ptr = FALSE;
3347 MonoType *type = mono_field_get_type_checked (field, &error);
3349 if (!mono_error_ok (&error))
3350 mono_error_raise_exception (&error);
3352 switch (type->type) {
3353 case MONO_TYPE_STRING:
3354 case MONO_TYPE_OBJECT:
3355 case MONO_TYPE_CLASS:
3356 case MONO_TYPE_ARRAY:
3357 case MONO_TYPE_SZARRAY:
3362 case MONO_TYPE_BOOLEAN:
3365 case MONO_TYPE_CHAR:
3374 case MONO_TYPE_VALUETYPE:
3375 is_ref = type->byref;
3377 case MONO_TYPE_GENERICINST:
3378 is_ref = !mono_type_generic_inst_is_valuetype (type);
3384 g_error ("type 0x%x not handled in "
3385 "mono_field_get_value_object", type->type);
3389 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3392 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3396 vtable = mono_class_vtable_full (domain, field->parent, TRUE);
3397 if (!vtable->initialized)
3398 mono_runtime_class_init (vtable);
3406 get_default_field_value (domain, field, &o);
3407 } else if (is_static) {
3408 mono_field_static_get_value (vtable, field, &o);
3410 mono_field_get_value (obj, field, &o);
3416 static MonoMethod *m;
3422 MonoClass *ptr_klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
3423 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3429 get_default_field_value (domain, field, v);
3430 } else if (is_static) {
3431 mono_field_static_get_value (vtable, field, v);
3433 mono_field_get_value (obj, field, v);
3436 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3437 args [0] = ptr ? *ptr : NULL;
3438 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3439 mono_error_raise_exception (&error); /* FIXME don't raise here */
3441 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3442 mono_error_raise_exception (&error); /* FIXME don't raise here */
3447 /* boxed value type */
3448 klass = mono_class_from_mono_type (type);
3450 if (mono_class_is_nullable (klass))
3451 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3453 o = mono_object_new_checked (domain, klass, &error);
3454 mono_error_raise_exception (&error); /* FIXME don't raise here */
3455 v = ((gchar *) o) + sizeof (MonoObject);
3458 get_default_field_value (domain, field, v);
3459 } else if (is_static) {
3460 mono_field_static_get_value (vtable, field, v);
3462 mono_field_get_value (obj, field, v);
3469 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3471 MONO_REQ_GC_UNSAFE_MODE;
3474 const char *p = blob;
3475 mono_metadata_decode_blob_size (p, &p);
3478 case MONO_TYPE_BOOLEAN:
3481 *(guint8 *) value = *p;
3483 case MONO_TYPE_CHAR:
3486 *(guint16*) value = read16 (p);
3490 *(guint32*) value = read32 (p);
3494 *(guint64*) value = read64 (p);
3497 readr4 (p, (float*) value);
3500 readr8 (p, (double*) value);
3502 case MONO_TYPE_STRING:
3503 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3505 case MONO_TYPE_CLASS:
3506 *(gpointer*) value = NULL;
3510 g_warning ("type 0x%02x should not be in constant table", type);
3516 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3518 MONO_REQ_GC_NEUTRAL_MODE;
3520 MonoTypeEnum def_type;
3523 data = mono_class_get_field_default_value (field, &def_type);
3524 mono_get_constant_value_from_blob (domain, def_type, data, value);
3528 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3530 MONO_REQ_GC_UNSAFE_MODE;
3534 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3536 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3537 get_default_field_value (vt->domain, field, value);
3541 if (field->offset == -1) {
3542 /* Special static */
3543 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3544 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3546 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3548 mono_copy_value (field->type, value, src, TRUE);
3552 * mono_field_static_get_value:
3553 * @vt: vtable to the object
3554 * @field: MonoClassField describing the field to fetch information from
3555 * @value: where the value is returned
3557 * Use this routine to get the value of the static field @field value.
3559 * The pointer provided by value must be of the field type, for reference
3560 * types this is a MonoObject*, for value types its the actual pointer to
3565 * mono_field_static_get_value (vt, int_field, &i);
3568 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3570 MONO_REQ_GC_NEUTRAL_MODE;
3572 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3576 * mono_property_set_value:
3577 * @prop: MonoProperty to set
3578 * @obj: instance object on which to act
3579 * @params: parameters to pass to the propery
3580 * @exc: optional exception
3582 * Invokes the property's set method with the given arguments on the
3583 * object instance obj (or NULL for static properties).
3585 * You can pass NULL as the exc argument if you don't want to
3586 * catch exceptions, otherwise, *exc will be set to the exception
3587 * thrown, if any. if an exception is thrown, you can't use the
3588 * MonoObject* result from the function.
3591 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3593 MONO_REQ_GC_UNSAFE_MODE;
3596 do_runtime_invoke (prop->set, obj, params, exc, &error);
3597 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3598 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3600 mono_error_raise_exception (&error); /* FIXME don't raise here */
3605 * mono_property_get_value:
3606 * @prop: MonoProperty to fetch
3607 * @obj: instance object on which to act
3608 * @params: parameters to pass to the propery
3609 * @exc: optional exception
3611 * Invokes the property's get method with the given arguments on the
3612 * object instance obj (or NULL for static properties).
3614 * You can pass NULL as the exc argument if you don't want to
3615 * catch exceptions, otherwise, *exc will be set to the exception
3616 * thrown, if any. if an exception is thrown, you can't use the
3617 * MonoObject* result from the function.
3619 * Returns: the value from invoking the get method on the property.
3622 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3624 MONO_REQ_GC_UNSAFE_MODE;
3627 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3628 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3629 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3631 mono_error_raise_exception (&error); /* FIXME don't raise here */
3638 * mono_nullable_init:
3639 * @buf: The nullable structure to initialize.
3640 * @value: the value to initialize from
3641 * @klass: the type for the object
3643 * Initialize the nullable structure pointed to by @buf from @value which
3644 * should be a boxed value type. The size of @buf should be able to hold
3645 * as much data as the @klass->instance_size (which is the number of bytes
3646 * that will be copies).
3648 * Since Nullables have variable structure, we can not define a C
3649 * structure for them.
3652 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3654 MONO_REQ_GC_UNSAFE_MODE;
3656 MonoClass *param_class = klass->cast_class;
3658 mono_class_setup_fields_locking (klass);
3659 g_assert (klass->fields_inited);
3661 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3662 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3664 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3666 if (param_class->has_references)
3667 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3669 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3671 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3676 * mono_nullable_box:
3677 * @buf: The buffer representing the data to be boxed
3678 * @klass: the type to box it as.
3680 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3684 mono_nullable_box (guint8 *buf, MonoClass *klass)
3686 MONO_REQ_GC_UNSAFE_MODE;
3690 MonoClass *param_class = klass->cast_class;
3692 mono_class_setup_fields_locking (klass);
3693 g_assert (klass->fields_inited);
3695 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3696 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3698 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3699 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3700 mono_error_raise_exception (&error); /* FIXME don't raise here */
3701 if (param_class->has_references)
3702 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3704 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3712 * mono_get_delegate_invoke:
3713 * @klass: The delegate class
3715 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3718 mono_get_delegate_invoke (MonoClass *klass)
3720 MONO_REQ_GC_NEUTRAL_MODE;
3724 /* This is called at runtime, so avoid the slower search in metadata */
3725 mono_class_setup_methods (klass);
3726 if (klass->exception_type)
3728 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3733 * mono_get_delegate_begin_invoke:
3734 * @klass: The delegate class
3736 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3739 mono_get_delegate_begin_invoke (MonoClass *klass)
3741 MONO_REQ_GC_NEUTRAL_MODE;
3745 /* This is called at runtime, so avoid the slower search in metadata */
3746 mono_class_setup_methods (klass);
3747 if (klass->exception_type)
3749 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3754 * mono_get_delegate_end_invoke:
3755 * @klass: The delegate class
3757 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3760 mono_get_delegate_end_invoke (MonoClass *klass)
3762 MONO_REQ_GC_NEUTRAL_MODE;
3766 /* This is called at runtime, so avoid the slower search in metadata */
3767 mono_class_setup_methods (klass);
3768 if (klass->exception_type)
3770 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3775 * mono_runtime_delegate_invoke:
3776 * @delegate: pointer to a delegate object.
3777 * @params: parameters for the delegate.
3778 * @exc: Pointer to the exception result.
3780 * Invokes the delegate method @delegate with the parameters provided.
3782 * You can pass NULL as the exc argument if you don't want to
3783 * catch exceptions, otherwise, *exc will be set to the exception
3784 * thrown, if any. if an exception is thrown, you can't use the
3785 * MonoObject* result from the function.
3788 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3790 MONO_REQ_GC_UNSAFE_MODE;
3794 MonoClass *klass = delegate->vtable->klass;
3797 im = mono_get_delegate_invoke (klass);
3799 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3802 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3803 if (*exc == NULL && !mono_error_ok (&error))
3804 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3806 mono_error_cleanup (&error);
3808 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3809 mono_error_raise_exception (&error); /* FIXME don't raise here */
3815 static char **main_args = NULL;
3816 static int num_main_args = 0;
3819 * mono_runtime_get_main_args:
3821 * Returns: a MonoArray with the arguments passed to the main program
3824 mono_runtime_get_main_args (void)
3826 MONO_REQ_GC_UNSAFE_MODE;
3830 MonoDomain *domain = mono_domain_get ();
3832 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3834 for (i = 0; i < num_main_args; ++i)
3835 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3841 free_main_args (void)
3843 MONO_REQ_GC_NEUTRAL_MODE;
3847 for (i = 0; i < num_main_args; ++i)
3848 g_free (main_args [i]);
3855 * mono_runtime_set_main_args:
3856 * @argc: number of arguments from the command line
3857 * @argv: array of strings from the command line
3859 * Set the command line arguments from an embedding application that doesn't otherwise call
3860 * mono_runtime_run_main ().
3863 mono_runtime_set_main_args (int argc, char* argv[])
3865 MONO_REQ_GC_NEUTRAL_MODE;
3870 main_args = g_new0 (char*, argc);
3871 num_main_args = argc;
3873 for (i = 0; i < argc; ++i) {
3876 utf8_arg = mono_utf8_from_external (argv[i]);
3877 if (utf8_arg == NULL) {
3878 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3879 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3883 main_args [i] = utf8_arg;
3890 * mono_runtime_run_main:
3891 * @method: the method to start the application with (usually Main)
3892 * @argc: number of arguments from the command line
3893 * @argv: array of strings from the command line
3894 * @exc: excetption results
3896 * Execute a standard Main() method (argc/argv contains the
3897 * executable name). This method also sets the command line argument value
3898 * needed by System.Environment.
3903 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3906 MONO_REQ_GC_UNSAFE_MODE;
3909 MonoArray *args = NULL;
3910 MonoDomain *domain = mono_domain_get ();
3911 gchar *utf8_fullpath;
3912 MonoMethodSignature *sig;
3914 g_assert (method != NULL);
3916 mono_thread_set_main (mono_thread_current ());
3918 main_args = g_new0 (char*, argc);
3919 num_main_args = argc;
3921 if (!g_path_is_absolute (argv [0])) {
3922 gchar *basename = g_path_get_basename (argv [0]);
3923 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3927 utf8_fullpath = mono_utf8_from_external (fullpath);
3928 if(utf8_fullpath == NULL) {
3929 /* Printing the arg text will cause glib to
3930 * whinge about "Invalid UTF-8", but at least
3931 * its relevant, and shows the problem text
3934 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3935 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3942 utf8_fullpath = mono_utf8_from_external (argv[0]);
3943 if(utf8_fullpath == NULL) {
3944 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3945 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3950 main_args [0] = utf8_fullpath;
3952 for (i = 1; i < argc; ++i) {
3955 utf8_arg=mono_utf8_from_external (argv[i]);
3956 if(utf8_arg==NULL) {
3957 /* Ditto the comment about Invalid UTF-8 here */
3958 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3959 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3963 main_args [i] = utf8_arg;
3968 sig = mono_method_signature (method);
3970 g_print ("Unable to load Main method.\n");
3974 if (sig->param_count) {
3975 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3976 for (i = 0; i < argc; ++i) {
3977 /* The encodings should all work, given that
3978 * we've checked all these args for the
3981 gchar *str = mono_utf8_from_external (argv [i]);
3982 MonoString *arg = mono_string_new (domain, str);
3983 mono_array_setref (args, i, arg);
3987 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
3990 mono_assembly_set_main (method->klass->image->assembly);
3992 return mono_runtime_exec_main (method, args, exc);
3996 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
3998 static MonoMethod *serialize_method;
4004 if (!serialize_method) {
4005 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
4006 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4009 if (!serialize_method) {
4014 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4019 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4020 if (*exc == NULL && !mono_error_ok (&error))
4021 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4023 mono_error_cleanup (&error);
4032 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4034 MONO_REQ_GC_UNSAFE_MODE;
4036 static MonoMethod *deserialize_method;
4042 if (!deserialize_method) {
4043 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingServices");
4044 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4046 if (!deserialize_method) {
4054 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4055 if (*exc == NULL && !mono_error_ok (&error))
4056 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4058 mono_error_cleanup (&error);
4066 #ifndef DISABLE_REMOTING
4068 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4070 MONO_REQ_GC_UNSAFE_MODE;
4072 static MonoMethod *get_proxy_method;
4075 MonoDomain *domain = mono_domain_get ();
4076 MonoRealProxy *real_proxy;
4077 MonoReflectionType *reflection_type;
4078 MonoTransparentProxy *transparent_proxy;
4080 if (!get_proxy_method)
4081 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4083 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4085 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4086 mono_error_raise_exception (&error); /* FIXME don't raise here */
4087 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4088 mono_error_raise_exception (&error); /* FIXME don't raise here */
4090 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4091 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4095 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4096 if (*exc == NULL && !mono_error_ok (&error))
4097 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4099 mono_error_cleanup (&error);
4103 return (MonoObject*) transparent_proxy;
4105 #endif /* DISABLE_REMOTING */
4108 * mono_object_xdomain_representation
4110 * @target_domain: a domain
4111 * @exc: pointer to a MonoObject*
4113 * Creates a representation of obj in the domain target_domain. This
4114 * is either a copy of obj arrived through via serialization and
4115 * deserialization or a proxy, depending on whether the object is
4116 * serializable or marshal by ref. obj must not be in target_domain.
4118 * If the object cannot be represented in target_domain, NULL is
4119 * returned and *exc is set to an appropriate exception.
4122 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4124 MONO_REQ_GC_UNSAFE_MODE;
4126 MonoObject *deserialized = NULL;
4127 gboolean failure = FALSE;
4129 g_assert (exc != NULL);
4132 #ifndef DISABLE_REMOTING
4133 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4134 deserialized = make_transparent_proxy (obj, &failure, exc);
4139 MonoDomain *domain = mono_domain_get ();
4140 MonoObject *serialized;
4142 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4143 serialized = serialize_object (obj, &failure, exc);
4144 mono_domain_set_internal_with_options (target_domain, FALSE);
4146 deserialized = deserialize_object (serialized, &failure, exc);
4147 if (domain != target_domain)
4148 mono_domain_set_internal_with_options (domain, FALSE);
4151 return deserialized;
4154 /* Used in call_unhandled_exception_delegate */
4156 create_unhandled_exception_eventargs (MonoObject *exc)
4158 MONO_REQ_GC_UNSAFE_MODE;
4163 MonoMethod *method = NULL;
4164 MonoBoolean is_terminating = TRUE;
4167 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
4170 mono_class_init (klass);
4172 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4173 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4177 args [1] = &is_terminating;
4179 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4180 mono_error_raise_exception (&error); /* FIXME don't raise here */
4182 mono_runtime_invoke_checked (method, obj, args, &error);
4183 mono_error_raise_exception (&error); /* FIXME don't raise here */
4188 /* Used in mono_unhandled_exception */
4190 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4191 MONO_REQ_GC_UNSAFE_MODE;
4193 MonoObject *e = NULL;
4195 MonoDomain *current_domain = mono_domain_get ();
4197 if (domain != current_domain)
4198 mono_domain_set_internal_with_options (domain, FALSE);
4200 g_assert (domain == mono_object_domain (domain->domain));
4202 if (mono_object_domain (exc) != domain) {
4203 MonoObject *serialization_exc;
4205 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4207 if (serialization_exc) {
4209 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4212 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4213 "System.Runtime.Serialization", "SerializationException",
4214 "Could not serialize unhandled exception.");
4218 g_assert (mono_object_domain (exc) == domain);
4220 pa [0] = domain->domain;
4221 pa [1] = create_unhandled_exception_eventargs (exc);
4222 mono_runtime_delegate_invoke (delegate, pa, &e);
4224 if (domain != current_domain)
4225 mono_domain_set_internal_with_options (current_domain, FALSE);
4229 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4230 if (!mono_error_ok (&error)) {
4231 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4232 mono_error_cleanup (&error);
4234 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4240 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4243 * mono_runtime_unhandled_exception_policy_set:
4244 * @policy: the new policy
4246 * This is a VM internal routine.
4248 * Sets the runtime policy for handling unhandled exceptions.
4251 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4252 runtime_unhandled_exception_policy = policy;
4256 * mono_runtime_unhandled_exception_policy_get:
4258 * This is a VM internal routine.
4260 * Gets the runtime policy for handling unhandled exceptions.
4262 MonoRuntimeUnhandledExceptionPolicy
4263 mono_runtime_unhandled_exception_policy_get (void) {
4264 return runtime_unhandled_exception_policy;
4268 * mono_unhandled_exception:
4269 * @exc: exception thrown
4271 * This is a VM internal routine.
4273 * We call this function when we detect an unhandled exception
4274 * in the default domain.
4276 * It invokes the * UnhandledException event in AppDomain or prints
4277 * a warning to the console
4280 mono_unhandled_exception (MonoObject *exc)
4282 MONO_REQ_GC_UNSAFE_MODE;
4284 MonoClassField *field;
4285 MonoDomain *current_domain, *root_domain;
4286 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4288 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4291 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4294 current_domain = mono_domain_get ();
4295 root_domain = mono_get_root_domain ();
4297 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4298 if (current_domain != root_domain)
4299 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4301 /* set exitcode only if we will abort the process */
4302 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4303 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4304 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4306 mono_environment_exitcode_set (1);
4309 mono_print_unhandled_exception (exc);
4311 if (root_appdomain_delegate)
4312 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4313 if (current_appdomain_delegate)
4314 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4319 * mono_runtime_exec_managed_code:
4320 * @domain: Application domain
4321 * @main_func: function to invoke from the execution thread
4322 * @main_args: parameter to the main_func
4324 * Launch a new thread to execute a function
4326 * main_func is called back from the thread with main_args as the
4327 * parameter. The callback function is expected to start Main()
4328 * eventually. This function then waits for all managed threads to
4330 * It is not necesseray anymore to execute managed code in a subthread,
4331 * so this function should not be used anymore by default: just
4332 * execute the code and then call mono_thread_manage ().
4335 mono_runtime_exec_managed_code (MonoDomain *domain,
4336 MonoMainThreadFunc main_func,
4339 mono_thread_create (domain, main_func, main_args);
4341 mono_thread_manage ();
4345 * Execute a standard Main() method (args doesn't contain the
4349 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4351 MONO_REQ_GC_UNSAFE_MODE;
4357 MonoCustomAttrInfo* cinfo;
4358 gboolean has_stathread_attribute;
4359 MonoInternalThread* thread = mono_thread_internal_current ();
4365 domain = mono_object_domain (args);
4366 if (!domain->entry_assembly) {
4368 MonoAssembly *assembly;
4370 assembly = method->klass->image->assembly;
4371 domain->entry_assembly = assembly;
4372 /* Domains created from another domain already have application_base and configuration_file set */
4373 if (domain->setup->application_base == NULL) {
4374 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4377 if (domain->setup->configuration_file == NULL) {
4378 str = g_strconcat (assembly->image->name, ".config", NULL);
4379 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4381 mono_domain_set_options_from_config (domain);
4385 cinfo = mono_custom_attrs_from_method (method);
4387 static MonoClass *stathread_attribute = NULL;
4388 if (!stathread_attribute)
4389 stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
4390 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
4392 mono_custom_attrs_free (cinfo);
4394 has_stathread_attribute = FALSE;
4396 if (has_stathread_attribute) {
4397 thread->apartment_state = ThreadApartmentState_STA;
4399 thread->apartment_state = ThreadApartmentState_MTA;
4401 mono_thread_init_apartment_state ();
4403 /* FIXME: check signature of method */
4404 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4407 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4408 if (*exc == NULL && !mono_error_ok (&error))
4409 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4411 mono_error_cleanup (&error);
4413 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4414 mono_error_raise_exception (&error); /* FIXME don't raise here */
4418 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4422 mono_environment_exitcode_set (rval);
4425 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4426 if (*exc == NULL && !mono_error_ok (&error))
4427 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4429 mono_error_cleanup (&error);
4431 mono_runtime_invoke_checked (method, NULL, pa, &error);
4432 mono_error_raise_exception (&error); /* FIXME don't raise here */
4438 /* If the return type of Main is void, only
4439 * set the exitcode if an exception was thrown
4440 * (we don't want to blow away an
4441 * explicitly-set exit code)
4444 mono_environment_exitcode_set (rval);
4452 * mono_runtime_invoke_array:
4453 * @method: method to invoke
4454 * @obJ: object instance
4455 * @params: arguments to the method
4456 * @exc: exception information.
4458 * Invokes the method represented by @method on the object @obj.
4460 * obj is the 'this' pointer, it should be NULL for static
4461 * methods, a MonoObject* for object instances and a pointer to
4462 * the value type for value types.
4464 * The params array contains the arguments to the method with the
4465 * same convention: MonoObject* pointers for object instances and
4466 * pointers to the value type otherwise. The _invoke_array
4467 * variant takes a C# object[] as the params argument (MonoArray
4468 * *params): in this case the value types are boxed inside the
4469 * respective reference representation.
4471 * From unmanaged code you'll usually use the
4472 * mono_runtime_invoke_checked() variant.
4474 * Note that this function doesn't handle virtual methods for
4475 * you, it will exec the exact method you pass: we still need to
4476 * expose a function to lookup the derived class implementation
4477 * of a virtual method (there are examples of this in the code,
4480 * You can pass NULL as the exc argument if you don't want to
4481 * catch exceptions, otherwise, *exc will be set to the exception
4482 * thrown, if any. if an exception is thrown, you can't use the
4483 * MonoObject* result from the function.
4485 * If the method returns a value type, it is boxed in an object
4489 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4492 MONO_REQ_GC_UNSAFE_MODE;
4495 MonoMethodSignature *sig = mono_method_signature (method);
4496 gpointer *pa = NULL;
4499 gboolean has_byref_nullables = FALSE;
4501 if (NULL != params) {
4502 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4503 for (i = 0; i < mono_array_length (params); i++) {
4504 MonoType *t = sig->params [i];
4510 case MONO_TYPE_BOOLEAN:
4513 case MONO_TYPE_CHAR:
4522 case MONO_TYPE_VALUETYPE:
4523 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4524 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4525 pa [i] = mono_array_get (params, MonoObject*, i);
4527 has_byref_nullables = TRUE;
4529 /* MS seems to create the objects if a null is passed in */
4530 if (!mono_array_get (params, MonoObject*, i)) {
4531 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4532 mono_error_raise_exception (&error); /* FIXME don't raise here */
4533 mono_array_setref (params, i, o);
4538 * We can't pass the unboxed vtype byref to the callee, since
4539 * that would mean the callee would be able to modify boxed
4540 * primitive types. So we (and MS) make a copy of the boxed
4541 * object, pass that to the callee, and replace the original
4542 * boxed object in the arg array with the copy.
4544 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4545 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4546 mono_array_setref (params, i, copy);
4549 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4552 case MONO_TYPE_STRING:
4553 case MONO_TYPE_OBJECT:
4554 case MONO_TYPE_CLASS:
4555 case MONO_TYPE_ARRAY:
4556 case MONO_TYPE_SZARRAY:
4558 pa [i] = mono_array_addr (params, MonoObject*, i);
4559 // FIXME: I need to check this code path
4561 pa [i] = mono_array_get (params, MonoObject*, i);
4563 case MONO_TYPE_GENERICINST:
4565 t = &t->data.generic_class->container_class->this_arg;
4567 t = &t->data.generic_class->container_class->byval_arg;
4569 case MONO_TYPE_PTR: {
4572 /* The argument should be an IntPtr */
4573 arg = mono_array_get (params, MonoObject*, i);
4577 g_assert (arg->vtable->klass == mono_defaults.int_class);
4578 pa [i] = ((MonoIntPtr*)arg)->m_value;
4583 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4588 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4591 if (mono_class_is_nullable (method->klass)) {
4592 /* Need to create a boxed vtype instead */
4598 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4602 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4603 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4604 #ifndef DISABLE_REMOTING
4605 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4606 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4609 if (method->klass->valuetype)
4610 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4613 } else if (method->klass->valuetype) {
4614 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4618 mono_runtime_try_invoke (method, o, pa, exc, &error);
4619 if (*exc == NULL && !mono_error_ok (&error))
4620 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4622 mono_error_cleanup (&error);
4624 mono_runtime_invoke_checked (method, o, pa, &error);
4625 mono_error_raise_exception (&error); /* FIXME don't raise here */
4628 return (MonoObject *)obj;
4630 if (mono_class_is_nullable (method->klass)) {
4631 MonoObject *nullable;
4633 /* Convert the unboxed vtype into a Nullable structure */
4634 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4635 mono_error_raise_exception (&error); /* FIXME don't raise here */
4637 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4638 obj = mono_object_unbox (nullable);
4641 /* obj must be already unboxed if needed */
4643 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4644 if (*exc == NULL && !mono_error_ok (&error))
4645 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4647 mono_error_cleanup (&error);
4649 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4650 mono_error_raise_exception (&error); /* FIXME don't raise here */
4653 if (sig->ret->type == MONO_TYPE_PTR) {
4654 MonoClass *pointer_class;
4655 static MonoMethod *box_method;
4657 MonoObject *box_exc;
4660 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4661 * convert it to a Pointer object.
4663 pointer_class = mono_class_from_name_cached (mono_defaults.corlib, "System.Reflection", "Pointer");
4665 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4667 g_assert (res->vtable->klass == mono_defaults.int_class);
4668 box_args [0] = ((MonoIntPtr*)res)->m_value;
4669 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4670 mono_error_raise_exception (&error); /* FIXME don't raise here */
4672 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4673 g_assert (box_exc == NULL);
4674 mono_error_assert_ok (&error);
4677 if (has_byref_nullables) {
4679 * The runtime invoke wrapper already converted byref nullables back,
4680 * and stored them in pa, we just need to copy them back to the
4683 for (i = 0; i < mono_array_length (params); i++) {
4684 MonoType *t = sig->params [i];
4686 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4687 mono_array_setref (params, i, pa [i]);
4697 * @klass: the class of the object that we want to create
4699 * Returns: a newly created object whose definition is
4700 * looked up using @klass. This will not invoke any constructors,
4701 * so the consumer of this routine has to invoke any constructors on
4702 * its own to initialize the object.
4704 * It returns NULL on failure.
4707 mono_object_new (MonoDomain *domain, MonoClass *klass)
4709 MONO_REQ_GC_UNSAFE_MODE;
4713 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4715 mono_error_raise_exception (&error);
4720 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4722 MONO_REQ_GC_UNSAFE_MODE;
4726 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4728 mono_error_raise_exception (&error);
4733 * mono_object_new_checked:
4734 * @klass: the class of the object that we want to create
4735 * @error: set on error
4737 * Returns: a newly created object whose definition is
4738 * looked up using @klass. This will not invoke any constructors,
4739 * so the consumer of this routine has to invoke any constructors on
4740 * its own to initialize the object.
4742 * It returns NULL on failure and sets @error.
4745 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4747 MONO_REQ_GC_UNSAFE_MODE;
4751 vtable = mono_class_vtable (domain, klass);
4752 g_assert (vtable); /* FIXME don't swallow the error */
4754 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4759 * mono_object_new_pinned:
4761 * Same as mono_object_new, but the returned object will be pinned.
4762 * For SGEN, these objects will only be freed at appdomain unload.
4765 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4767 MONO_REQ_GC_UNSAFE_MODE;
4771 mono_error_init (error);
4773 vtable = mono_class_vtable (domain, klass);
4774 g_assert (vtable); /* FIXME don't swallow the error */
4776 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4778 if (G_UNLIKELY (!o))
4779 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4780 else if (G_UNLIKELY (vtable->klass->has_finalize))
4781 mono_object_register_finalizer (o);
4787 * mono_object_new_specific:
4788 * @vtable: the vtable of the object that we want to create
4790 * Returns: A newly created object with class and domain specified
4794 mono_object_new_specific (MonoVTable *vtable)
4797 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4798 mono_error_raise_exception (&error);
4804 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4806 MONO_REQ_GC_UNSAFE_MODE;
4810 mono_error_init (error);
4812 /* check for is_com_object for COM Interop */
4813 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4816 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4819 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
4822 mono_class_init (klass);
4824 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4826 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4829 vtable->domain->create_proxy_for_type_method = im;
4832 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4833 if (!mono_error_ok (error))
4836 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4837 if (!mono_error_ok (error))
4844 return mono_object_new_alloc_specific_checked (vtable, error);
4848 ves_icall_object_new_specific (MonoVTable *vtable)
4851 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4852 mono_error_raise_exception (&error);
4858 * mono_object_new_alloc_specific:
4859 * @vtable: virtual table for the object.
4861 * This function allocates a new `MonoObject` with the type derived
4862 * from the @vtable information. If the class of this object has a
4863 * finalizer, then the object will be tracked for finalization.
4865 * This method might raise an exception on errors. Use the
4866 * `mono_object_new_fast_checked` method if you want to manually raise
4869 * Returns: the allocated object.
4872 mono_object_new_alloc_specific (MonoVTable *vtable)
4875 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4876 mono_error_raise_exception (&error);
4882 * mono_object_new_alloc_specific_checked:
4883 * @vtable: virtual table for the object.
4884 * @error: holds the error return value.
4886 * This function allocates a new `MonoObject` with the type derived
4887 * from the @vtable information. If the class of this object has a
4888 * finalizer, then the object will be tracked for finalization.
4890 * If there is not enough memory, the @error parameter will be set
4891 * and will contain a user-visible message with the amount of bytes
4892 * that were requested.
4894 * Returns: the allocated object, or NULL if there is not enough memory
4898 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4900 MONO_REQ_GC_UNSAFE_MODE;
4904 mono_error_init (error);
4906 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4908 if (G_UNLIKELY (!o))
4909 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4910 else if (G_UNLIKELY (vtable->klass->has_finalize))
4911 mono_object_register_finalizer (o);
4917 * mono_object_new_fast:
4918 * @vtable: virtual table for the object.
4920 * This function allocates a new `MonoObject` with the type derived
4921 * from the @vtable information. The returned object is not tracked
4922 * for finalization. If your object implements a finalizer, you should
4923 * use `mono_object_new_alloc_specific` instead.
4925 * This method might raise an exception on errors. Use the
4926 * `mono_object_new_fast_checked` method if you want to manually raise
4929 * Returns: the allocated object.
4932 mono_object_new_fast (MonoVTable *vtable)
4935 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4936 mono_error_raise_exception (&error);
4942 * mono_object_new_fast_checked:
4943 * @vtable: virtual table for the object.
4944 * @error: holds the error return value.
4946 * This function allocates a new `MonoObject` with the type derived
4947 * from the @vtable information. The returned object is not tracked
4948 * for finalization. If your object implements a finalizer, you should
4949 * use `mono_object_new_alloc_specific_checked` instead.
4951 * If there is not enough memory, the @error parameter will be set
4952 * and will contain a user-visible message with the amount of bytes
4953 * that were requested.
4955 * Returns: the allocated object, or NULL if there is not enough memory
4959 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4961 MONO_REQ_GC_UNSAFE_MODE;
4965 mono_error_init (error);
4967 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4969 if (G_UNLIKELY (!o))
4970 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4976 ves_icall_object_new_fast (MonoVTable *vtable)
4979 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4980 mono_error_raise_exception (&error);
4986 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4988 MONO_REQ_GC_UNSAFE_MODE;
4992 mono_error_init (error);
4994 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4996 if (G_UNLIKELY (!o))
4997 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4998 else if (G_UNLIKELY (vtable->klass->has_finalize))
4999 mono_object_register_finalizer (o);
5005 * mono_class_get_allocation_ftn:
5007 * @for_box: the object will be used for boxing
5008 * @pass_size_in_words:
5010 * Return the allocation function appropriate for the given class.
5014 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5016 MONO_REQ_GC_NEUTRAL_MODE;
5018 *pass_size_in_words = FALSE;
5020 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5021 return ves_icall_object_new_specific;
5023 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5025 return ves_icall_object_new_fast;
5028 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5029 * of the overhead of parameter passing.
5032 *pass_size_in_words = TRUE;
5033 #ifdef GC_REDIRECT_TO_LOCAL
5034 return GC_local_gcj_fast_malloc;
5036 return GC_gcj_fast_malloc;
5041 return ves_icall_object_new_specific;
5045 * mono_object_new_from_token:
5046 * @image: Context where the type_token is hosted
5047 * @token: a token of the type that we want to create
5049 * Returns: A newly created object whose definition is
5050 * looked up using @token in the @image image
5053 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5055 MONO_REQ_GC_UNSAFE_MODE;
5061 klass = mono_class_get_checked (image, token, &error);
5062 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5064 result = mono_object_new_checked (domain, klass, &error);
5066 mono_error_raise_exception (&error); /* FIXME don't raise here */
5073 * mono_object_clone:
5074 * @obj: the object to clone
5076 * Returns: A newly created object who is a shallow copy of @obj
5079 mono_object_clone (MonoObject *obj)
5082 MonoObject *o = mono_object_clone_checked (obj, &error);
5083 mono_error_raise_exception (&error);
5089 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5091 MONO_REQ_GC_UNSAFE_MODE;
5096 mono_error_init (error);
5098 size = obj->vtable->klass->instance_size;
5100 if (obj->vtable->klass->rank)
5101 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5103 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5105 if (G_UNLIKELY (!o)) {
5106 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5110 /* If the object doesn't contain references this will do a simple memmove. */
5111 mono_gc_wbarrier_object_copy (o, obj);
5113 if (obj->vtable->klass->has_finalize)
5114 mono_object_register_finalizer (o);
5119 * mono_array_full_copy:
5120 * @src: source array to copy
5121 * @dest: destination array
5123 * Copies the content of one array to another with exactly the same type and size.
5126 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5128 MONO_REQ_GC_UNSAFE_MODE;
5131 MonoClass *klass = src->obj.vtable->klass;
5133 g_assert (klass == dest->obj.vtable->klass);
5135 size = mono_array_length (src);
5136 g_assert (size == mono_array_length (dest));
5137 size *= mono_array_element_size (klass);
5139 if (klass->element_class->valuetype) {
5140 if (klass->element_class->has_references)
5141 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5143 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5145 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5148 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5153 * mono_array_clone_in_domain:
5154 * @domain: the domain in which the array will be cloned into
5155 * @array: the array to clone
5157 * This routine returns a copy of the array that is hosted on the
5158 * specified MonoDomain.
5161 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5163 MONO_REQ_GC_UNSAFE_MODE;
5169 MonoClass *klass = array->obj.vtable->klass;
5171 if (array->bounds == NULL) {
5172 size = mono_array_length (array);
5173 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5174 mono_error_raise_exception (&error); /* FIXME don't raise here */
5176 size *= mono_array_element_size (klass);
5178 if (klass->element_class->valuetype) {
5179 if (klass->element_class->has_references)
5180 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5182 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5184 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5187 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5192 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5193 size = mono_array_element_size (klass);
5194 for (i = 0; i < klass->rank; ++i) {
5195 sizes [i] = array->bounds [i].length;
5196 size *= array->bounds [i].length;
5197 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5199 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5200 mono_error_raise_exception (&error); /* FIXME don't raise here */
5202 if (klass->element_class->valuetype) {
5203 if (klass->element_class->has_references)
5204 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5206 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5208 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5211 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5219 * @array: the array to clone
5221 * Returns: A newly created array who is a shallow copy of @array
5224 mono_array_clone (MonoArray *array)
5226 MONO_REQ_GC_UNSAFE_MODE;
5228 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5231 /* helper macros to check for overflow when calculating the size of arrays */
5232 #ifdef MONO_BIG_ARRAYS
5233 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5234 #define MYGUINT_MAX MYGUINT64_MAX
5235 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5236 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5237 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5238 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5239 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5241 #define MYGUINT32_MAX 4294967295U
5242 #define MYGUINT_MAX MYGUINT32_MAX
5243 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5244 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5245 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5246 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5247 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5251 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5253 MONO_REQ_GC_NEUTRAL_MODE;
5257 byte_len = mono_array_element_size (klass);
5258 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5261 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5263 byte_len += MONO_SIZEOF_MONO_ARRAY;
5271 * mono_array_new_full:
5272 * @domain: domain where the object is created
5273 * @array_class: array class
5274 * @lengths: lengths for each dimension in the array
5275 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5277 * This routine creates a new array objects with the given dimensions,
5278 * lower bounds and type.
5281 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5284 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5285 mono_error_raise_exception (&error);
5291 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5293 MONO_REQ_GC_UNSAFE_MODE;
5295 uintptr_t byte_len = 0, len, bounds_size;
5298 MonoArrayBounds *bounds;
5302 mono_error_init (error);
5304 if (!array_class->inited)
5305 mono_class_init (array_class);
5309 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5310 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5312 if (len > MONO_ARRAY_MAX_INDEX) {
5313 mono_error_set_generic_error (error, "System", "OverflowException", "");
5318 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5320 for (i = 0; i < array_class->rank; ++i) {
5321 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5322 mono_error_set_generic_error (error, "System", "OverflowException", "");
5325 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5326 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5333 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5334 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5340 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5341 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5344 byte_len = (byte_len + 3) & ~3;
5345 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5346 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5349 byte_len += bounds_size;
5352 * Following three lines almost taken from mono_object_new ():
5353 * they need to be kept in sync.
5355 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5357 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5359 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5361 if (G_UNLIKELY (!o)) {
5362 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5366 array = (MonoArray*)o;
5368 bounds = array->bounds;
5371 for (i = 0; i < array_class->rank; ++i) {
5372 bounds [i].length = lengths [i];
5374 bounds [i].lower_bound = lower_bounds [i];
5383 * @domain: domain where the object is created
5384 * @eclass: element class
5385 * @n: number of array elements
5387 * This routine creates a new szarray with @n elements of type @eclass.
5390 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5392 MONO_REQ_GC_UNSAFE_MODE;
5398 ac = mono_array_class_get (eclass, 1);
5401 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5402 mono_error_raise_exception (&error); /* FIXME don't raise here */
5408 * mono_array_new_specific:
5409 * @vtable: a vtable in the appropriate domain for an initialized class
5410 * @n: number of array elements
5412 * This routine is a fast alternative to mono_array_new() for code which
5413 * can be sure about the domain it operates in.
5416 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5419 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5420 mono_error_raise_exception (&error); /* FIXME don't raise here */
5426 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5428 MONO_REQ_GC_UNSAFE_MODE;
5433 mono_error_init (error);
5435 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5436 mono_error_set_generic_error (error, "System", "OverflowException", "");
5440 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5441 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5444 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5446 if (G_UNLIKELY (!o)) {
5447 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5451 return (MonoArray*)o;
5455 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5458 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5459 mono_error_raise_exception (&error);
5465 * mono_string_new_utf16:
5466 * @text: a pointer to an utf16 string
5467 * @len: the length of the string
5469 * Returns: A newly created string object which contains @text.
5472 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5474 MONO_REQ_GC_UNSAFE_MODE;
5477 MonoString *res = NULL;
5478 res = mono_string_new_utf16_checked (domain, text, len, &error);
5479 mono_error_raise_exception (&error);
5485 * mono_string_new_utf16_checked:
5486 * @text: a pointer to an utf16 string
5487 * @len: the length of the string
5488 * @error: written on error.
5490 * Returns: A newly created string object which contains @text.
5491 * On error, returns NULL and sets @error.
5494 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5496 MONO_REQ_GC_UNSAFE_MODE;
5500 mono_error_init (error);
5502 s = mono_string_new_size_checked (domain, len, error);
5504 memcpy (mono_string_chars (s), text, len * 2);
5510 * mono_string_new_utf32:
5511 * @text: a pointer to an utf32 string
5512 * @len: the length of the string
5514 * Returns: A newly created string object which contains @text.
5517 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5519 MONO_REQ_GC_UNSAFE_MODE;
5523 mono_unichar2 *utf16_output = NULL;
5524 gint32 utf16_len = 0;
5525 GError *gerror = NULL;
5526 glong items_written;
5528 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5531 g_error_free (gerror);
5533 while (utf16_output [utf16_len]) utf16_len++;
5535 s = mono_string_new_size_checked (domain, utf16_len, &error);
5536 mono_error_raise_exception (&error); /* FIXME don't raise here */
5538 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5540 g_free (utf16_output);
5546 * mono_string_new_size:
5547 * @text: a pointer to an utf16 string
5548 * @len: the length of the string
5550 * Returns: A newly created string object of @len
5553 mono_string_new_size (MonoDomain *domain, gint32 len)
5556 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5557 mono_error_raise_exception (&error);
5563 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5565 MONO_REQ_GC_UNSAFE_MODE;
5571 mono_error_init (error);
5573 /* check for overflow */
5574 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5575 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5579 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5580 g_assert (size > 0);
5582 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5585 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5587 if (G_UNLIKELY (!s)) {
5588 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5596 * mono_string_new_len:
5597 * @text: a pointer to an utf8 string
5598 * @length: number of bytes in @text to consider
5600 * Returns: A newly created string object which contains @text.
5603 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5605 MONO_REQ_GC_UNSAFE_MODE;
5608 GError *eg_error = NULL;
5609 MonoString *o = NULL;
5611 glong items_written;
5613 mono_error_init (&error);
5615 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5618 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5620 g_error_free (eg_error);
5624 mono_error_raise_exception (&error); /* FIXME don't raise here */
5630 * @text: a pointer to an utf8 string
5632 * Returns: A newly created string object which contains @text.
5634 * This function asserts if it cannot allocate a new string.
5636 * @deprecated Use mono_string_new_checked in new code.
5639 mono_string_new (MonoDomain *domain, const char *text)
5642 MonoString *res = NULL;
5643 res = mono_string_new_checked (domain, text, &error);
5644 mono_error_assert_ok (&error);
5649 * mono_string_new_checked:
5650 * @text: a pointer to an utf8 string
5651 * @merror: set on error
5653 * Returns: A newly created string object which contains @text.
5654 * On error returns NULL and sets @merror.
5657 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5659 MONO_REQ_GC_UNSAFE_MODE;
5661 GError *eg_error = NULL;
5662 MonoString *o = NULL;
5664 glong items_written;
5667 mono_error_init (error);
5671 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5674 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5676 g_error_free (eg_error);
5679 mono_error_raise_exception (error);
5681 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5686 MonoString *o = NULL;
5688 if (!g_utf8_validate (text, -1, &end)) {
5689 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5693 len = g_utf8_strlen (text, -1);
5694 o = mono_string_new_size_checked (domain, len, error);
5697 str = mono_string_chars (o);
5699 while (text < end) {
5700 *str++ = g_utf8_get_char (text);
5701 text = g_utf8_next_char (text);
5710 * mono_string_new_wrapper:
5711 * @text: pointer to utf8 characters.
5713 * Helper function to create a string object from @text in the current domain.
5716 mono_string_new_wrapper (const char *text)
5718 MONO_REQ_GC_UNSAFE_MODE;
5720 MonoDomain *domain = mono_domain_get ();
5723 return mono_string_new (domain, text);
5730 * @class: the class of the value
5731 * @value: a pointer to the unboxed data
5733 * Returns: A newly created object which contains @value.
5736 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5738 MONO_REQ_GC_UNSAFE_MODE;
5745 g_assert (klass->valuetype);
5746 if (mono_class_is_nullable (klass))
5747 return mono_nullable_box ((guint8 *)value, klass);
5749 vtable = mono_class_vtable (domain, klass);
5752 size = mono_class_instance_size (klass);
5753 res = mono_object_new_alloc_specific_checked (vtable, &error);
5754 mono_error_raise_exception (&error); /* FIXME don't raise here */
5756 size = size - sizeof (MonoObject);
5759 g_assert (size == mono_class_value_size (klass, NULL));
5760 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5762 #if NO_UNALIGNED_ACCESS
5763 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5767 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5770 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5773 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5776 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5779 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5783 if (klass->has_finalize)
5784 mono_object_register_finalizer (res);
5790 * @dest: destination pointer
5791 * @src: source pointer
5792 * @klass: a valuetype class
5794 * Copy a valuetype from @src to @dest. This function must be used
5795 * when @klass contains references fields.
5798 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5800 MONO_REQ_GC_UNSAFE_MODE;
5802 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5806 * mono_value_copy_array:
5807 * @dest: destination array
5808 * @dest_idx: index in the @dest array
5809 * @src: source pointer
5810 * @count: number of items
5812 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5813 * This function must be used when @klass contains references fields.
5814 * Overlap is handled.
5817 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5819 MONO_REQ_GC_UNSAFE_MODE;
5821 int size = mono_array_element_size (dest->obj.vtable->klass);
5822 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5823 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5824 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5828 * mono_object_get_domain:
5829 * @obj: object to query
5831 * Returns: the MonoDomain where the object is hosted
5834 mono_object_get_domain (MonoObject *obj)
5836 MONO_REQ_GC_UNSAFE_MODE;
5838 return mono_object_domain (obj);
5842 * mono_object_get_class:
5843 * @obj: object to query
5845 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5847 * Returns: the MonoClass of the object.
5850 mono_object_get_class (MonoObject *obj)
5852 MONO_REQ_GC_UNSAFE_MODE;
5854 return mono_object_class (obj);
5857 * mono_object_get_size:
5858 * @o: object to query
5860 * Returns: the size, in bytes, of @o
5863 mono_object_get_size (MonoObject* o)
5865 MONO_REQ_GC_UNSAFE_MODE;
5867 MonoClass* klass = mono_object_class (o);
5868 if (klass == mono_defaults.string_class) {
5869 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5870 } else if (o->vtable->rank) {
5871 MonoArray *array = (MonoArray*)o;
5872 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5873 if (array->bounds) {
5876 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5880 return mono_class_instance_size (klass);
5885 * mono_object_unbox:
5886 * @obj: object to unbox
5888 * Returns: a pointer to the start of the valuetype boxed in this
5891 * This method will assert if the object passed is not a valuetype.
5894 mono_object_unbox (MonoObject *obj)
5896 MONO_REQ_GC_UNSAFE_MODE;
5898 /* add assert for valuetypes? */
5899 g_assert (obj->vtable->klass->valuetype);
5900 return ((char*)obj) + sizeof (MonoObject);
5904 * mono_object_isinst:
5906 * @klass: a pointer to a class
5908 * Returns: @obj if @obj is derived from @klass
5911 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5913 MONO_REQ_GC_UNSAFE_MODE;
5916 mono_class_init (klass);
5918 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5919 return mono_object_isinst_mbyref (obj, klass);
5924 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5928 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5930 MONO_REQ_GC_UNSAFE_MODE;
5940 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5941 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5945 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5946 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5949 MonoClass *oklass = vt->klass;
5950 if (mono_class_is_transparent_proxy (oklass))
5951 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5953 mono_class_setup_supertypes (klass);
5954 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5957 #ifndef DISABLE_REMOTING
5958 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5960 MonoDomain *domain = mono_domain_get ();
5962 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5963 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5964 MonoMethod *im = NULL;
5967 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5969 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5970 im = mono_object_get_virtual_method (rp, im);
5973 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5974 mono_error_raise_exception (&error); /* FIXME don't raise here */
5977 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5978 mono_error_raise_exception (&error); /* FIXME don't raise here */
5980 if (*(MonoBoolean *) mono_object_unbox(res)) {
5981 /* Update the vtable of the remote type, so it can safely cast to this new type */
5982 mono_upgrade_remote_class (domain, obj, klass);
5986 #endif /* DISABLE_REMOTING */
5991 * mono_object_castclass_mbyref:
5993 * @klass: a pointer to a class
5995 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5998 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6000 MONO_REQ_GC_UNSAFE_MODE;
6002 if (!obj) return NULL;
6003 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6005 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6007 "InvalidCastException"));
6012 MonoDomain *orig_domain;
6018 str_lookup (MonoDomain *domain, gpointer user_data)
6020 MONO_REQ_GC_UNSAFE_MODE;
6022 LDStrInfo *info = (LDStrInfo *)user_data;
6023 if (info->res || domain == info->orig_domain)
6025 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6029 mono_string_get_pinned (MonoString *str, MonoError *error)
6031 MONO_REQ_GC_UNSAFE_MODE;
6033 mono_error_init (error);
6035 /* We only need to make a pinned version of a string if this is a moving GC */
6036 if (!mono_gc_is_moving ())
6040 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6041 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6043 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6044 news->length = mono_string_length (str);
6046 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6052 mono_string_is_interned_lookup (MonoString *str, int insert)
6054 MONO_REQ_GC_UNSAFE_MODE;
6057 MonoGHashTable *ldstr_table;
6058 MonoString *s, *res;
6061 domain = ((MonoObject *)str)->vtable->domain;
6062 ldstr_table = domain->ldstr_table;
6064 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6070 /* Allocate outside the lock */
6072 s = mono_string_get_pinned (str, &error);
6073 mono_error_raise_exception (&error); /* FIXME don't raise here */
6076 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6081 mono_g_hash_table_insert (ldstr_table, s, s);
6086 LDStrInfo ldstr_info;
6087 ldstr_info.orig_domain = domain;
6088 ldstr_info.ins = str;
6089 ldstr_info.res = NULL;
6091 mono_domain_foreach (str_lookup, &ldstr_info);
6092 if (ldstr_info.res) {
6094 * the string was already interned in some other domain:
6095 * intern it in the current one as well.
6097 mono_g_hash_table_insert (ldstr_table, str, str);
6107 * mono_string_is_interned:
6108 * @o: String to probe
6110 * Returns whether the string has been interned.
6113 mono_string_is_interned (MonoString *o)
6115 MONO_REQ_GC_UNSAFE_MODE;
6117 return mono_string_is_interned_lookup (o, FALSE);
6121 * mono_string_intern:
6122 * @o: String to intern
6124 * Interns the string passed.
6125 * Returns: The interned string.
6128 mono_string_intern (MonoString *str)
6130 MONO_REQ_GC_UNSAFE_MODE;
6132 return mono_string_is_interned_lookup (str, TRUE);
6137 * @domain: the domain where the string will be used.
6138 * @image: a metadata context
6139 * @idx: index into the user string table.
6141 * Implementation for the ldstr opcode.
6142 * Returns: a loaded string from the @image/@idx combination.
6145 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6147 MONO_REQ_GC_UNSAFE_MODE;
6149 if (image->dynamic) {
6150 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6153 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6154 return NULL; /*FIXME we should probably be raising an exception here*/
6155 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6160 * mono_ldstr_metadata_sig
6161 * @domain: the domain for the string
6162 * @sig: the signature of a metadata string
6164 * Returns: a MonoString for a string stored in the metadata
6167 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6169 MONO_REQ_GC_UNSAFE_MODE;
6172 const char *str = sig;
6173 MonoString *o, *interned;
6176 len2 = mono_metadata_decode_blob_size (str, &str);
6179 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6180 mono_error_raise_exception (&error); /* FIXME don't raise here */
6181 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6184 guint16 *p2 = (guint16*)mono_string_chars (o);
6185 for (i = 0; i < len2; ++i) {
6186 *p2 = GUINT16_FROM_LE (*p2);
6192 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6195 return interned; /* o will get garbage collected */
6197 o = mono_string_get_pinned (o, &error);
6198 mono_error_raise_exception (&error); /* FIXME don't raise here */
6201 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6203 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6213 * mono_string_to_utf8:
6214 * @s: a System.String
6216 * Returns the UTF8 representation for @s.
6217 * The resulting buffer needs to be freed with mono_free().
6219 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6222 mono_string_to_utf8 (MonoString *s)
6224 MONO_REQ_GC_UNSAFE_MODE;
6227 char *result = mono_string_to_utf8_checked (s, &error);
6229 if (!mono_error_ok (&error))
6230 mono_error_raise_exception (&error);
6235 * mono_string_to_utf8_checked:
6236 * @s: a System.String
6237 * @error: a MonoError.
6239 * Converts a MonoString to its UTF8 representation. May fail; check
6240 * @error to determine whether the conversion was successful.
6241 * The resulting buffer should be freed with mono_free().
6244 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6246 MONO_REQ_GC_UNSAFE_MODE;
6250 GError *gerror = NULL;
6252 mono_error_init (error);
6258 return g_strdup ("");
6260 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6262 mono_error_set_argument (error, "string", "%s", gerror->message);
6263 g_error_free (gerror);
6266 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6267 if (s->length > written) {
6268 /* allocate the total length and copy the part of the string that has been converted */
6269 char *as2 = (char *)g_malloc0 (s->length);
6270 memcpy (as2, as, written);
6279 * mono_string_to_utf8_ignore:
6282 * Converts a MonoString to its UTF8 representation. Will ignore
6283 * invalid surrogate pairs.
6284 * The resulting buffer should be freed with mono_free().
6288 mono_string_to_utf8_ignore (MonoString *s)
6290 MONO_REQ_GC_UNSAFE_MODE;
6299 return g_strdup ("");
6301 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6303 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6304 if (s->length > written) {
6305 /* allocate the total length and copy the part of the string that has been converted */
6306 char *as2 = (char *)g_malloc0 (s->length);
6307 memcpy (as2, as, written);
6316 * mono_string_to_utf8_image_ignore:
6317 * @s: a System.String
6319 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6322 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6324 MONO_REQ_GC_UNSAFE_MODE;
6326 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6330 * mono_string_to_utf8_mp_ignore:
6331 * @s: a System.String
6333 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6336 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6338 MONO_REQ_GC_UNSAFE_MODE;
6340 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6345 * mono_string_to_utf16:
6348 * Return an null-terminated array of the utf-16 chars
6349 * contained in @s. The result must be freed with g_free().
6350 * This is a temporary helper until our string implementation
6351 * is reworked to always include the null terminating char.
6354 mono_string_to_utf16 (MonoString *s)
6356 MONO_REQ_GC_UNSAFE_MODE;
6363 as = (char *)g_malloc ((s->length * 2) + 2);
6364 as [(s->length * 2)] = '\0';
6365 as [(s->length * 2) + 1] = '\0';
6368 return (gunichar2 *)(as);
6371 memcpy (as, mono_string_chars(s), s->length * 2);
6372 return (gunichar2 *)(as);
6376 * mono_string_to_utf32:
6379 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6380 * contained in @s. The result must be freed with g_free().
6383 mono_string_to_utf32 (MonoString *s)
6385 MONO_REQ_GC_UNSAFE_MODE;
6387 mono_unichar4 *utf32_output = NULL;
6388 GError *error = NULL;
6389 glong items_written;
6394 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6397 g_error_free (error);
6399 return utf32_output;
6403 * mono_string_from_utf16:
6404 * @data: the UTF16 string (LPWSTR) to convert
6406 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6408 * Returns: a MonoString.
6411 mono_string_from_utf16 (gunichar2 *data)
6413 MONO_REQ_GC_UNSAFE_MODE;
6416 MonoString *res = NULL;
6417 MonoDomain *domain = mono_domain_get ();
6423 while (data [len]) len++;
6425 res = mono_string_new_utf16_checked (domain, data, len, &error);
6426 mono_error_raise_exception (&error); /* FIXME don't raise here */
6431 * mono_string_from_utf32:
6432 * @data: the UTF32 string (LPWSTR) to convert
6434 * Converts a UTF32 (UCS-4)to a MonoString.
6436 * Returns: a MonoString.
6439 mono_string_from_utf32 (mono_unichar4 *data)
6441 MONO_REQ_GC_UNSAFE_MODE;
6443 MonoString* result = NULL;
6444 mono_unichar2 *utf16_output = NULL;
6445 GError *error = NULL;
6446 glong items_written;
6452 while (data [len]) len++;
6454 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6457 g_error_free (error);
6459 result = mono_string_from_utf16 (utf16_output);
6460 g_free (utf16_output);
6465 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6467 MONO_REQ_GC_UNSAFE_MODE;
6474 r = mono_string_to_utf8_ignore (s);
6476 r = mono_string_to_utf8_checked (s, error);
6477 if (!mono_error_ok (error))
6484 len = strlen (r) + 1;
6486 mp_s = (char *)mono_mempool_alloc (mp, len);
6488 mp_s = (char *)mono_image_alloc (image, len);
6490 memcpy (mp_s, r, len);
6498 * mono_string_to_utf8_image:
6499 * @s: a System.String
6501 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6504 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6506 MONO_REQ_GC_UNSAFE_MODE;
6508 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6512 * mono_string_to_utf8_mp:
6513 * @s: a System.String
6515 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6518 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6520 MONO_REQ_GC_UNSAFE_MODE;
6522 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6526 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6529 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6531 eh_callbacks = *cbs;
6534 MonoRuntimeExceptionHandlingCallbacks *
6535 mono_get_eh_callbacks (void)
6537 return &eh_callbacks;
6541 * mono_raise_exception:
6542 * @ex: exception object
6544 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6547 mono_raise_exception (MonoException *ex)
6549 MONO_REQ_GC_UNSAFE_MODE;
6552 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6553 * that will cause gcc to omit the function epilog, causing problems when
6554 * the JIT tries to walk the stack, since the return address on the stack
6555 * will point into the next function in the executable, not this one.
6557 eh_callbacks.mono_raise_exception (ex);
6561 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6563 MONO_REQ_GC_UNSAFE_MODE;
6565 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6569 * mono_wait_handle_new:
6570 * @domain: Domain where the object will be created
6571 * @handle: Handle for the wait handle
6573 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6576 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6578 MONO_REQ_GC_UNSAFE_MODE;
6581 MonoWaitHandle *res;
6582 gpointer params [1];
6583 static MonoMethod *handle_set;
6585 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6586 mono_error_raise_exception (&error); /* FIXME don't raise here */
6588 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6590 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6592 params [0] = &handle;
6594 mono_runtime_invoke_checked (handle_set, res, params, &error);
6595 mono_error_raise_exception (&error); /* FIXME don't raise here */
6601 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6603 MONO_REQ_GC_UNSAFE_MODE;
6605 static MonoClassField *f_os_handle;
6606 static MonoClassField *f_safe_handle;
6608 if (!f_os_handle && !f_safe_handle) {
6609 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6610 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6615 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6619 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6626 mono_runtime_capture_context (MonoDomain *domain)
6628 MONO_REQ_GC_UNSAFE_MODE;
6630 RuntimeInvokeFunction runtime_invoke;
6632 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6633 MonoMethod *method = mono_get_context_capture_method ();
6634 MonoMethod *wrapper;
6637 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6638 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6639 domain->capture_context_method = mono_compile_method (method);
6642 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6644 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6647 * mono_async_result_new:
6648 * @domain:domain where the object will be created.
6649 * @handle: wait handle.
6650 * @state: state to pass to AsyncResult
6651 * @data: C closure data.
6653 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6654 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6658 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6660 MONO_REQ_GC_UNSAFE_MODE;
6663 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6664 mono_error_raise_exception (&error); /* FIXME don't raise here */
6665 MonoObject *context = mono_runtime_capture_context (domain);
6666 /* we must capture the execution context from the original thread */
6668 MONO_OBJECT_SETREF (res, execution_context, context);
6669 /* note: result may be null if the flow is suppressed */
6672 res->data = (void **)data;
6673 MONO_OBJECT_SETREF (res, object_data, object_data);
6674 MONO_OBJECT_SETREF (res, async_state, state);
6676 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6678 res->sync_completed = FALSE;
6679 res->completed = FALSE;
6685 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6687 MONO_REQ_GC_UNSAFE_MODE;
6694 g_assert (ares->async_delegate);
6696 ac = (MonoAsyncCall*) ares->object_data;
6698 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6700 gpointer wait_event = NULL;
6702 ac->msg->exc = NULL;
6703 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6704 MONO_OBJECT_SETREF (ac, res, res);
6706 mono_monitor_enter ((MonoObject*) ares);
6707 ares->completed = 1;
6709 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6710 mono_monitor_exit ((MonoObject*) ares);
6712 if (wait_event != NULL)
6713 SetEvent (wait_event);
6715 if (ac->cb_method) {
6716 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6717 mono_error_raise_exception (&error);
6725 mono_message_init (MonoDomain *domain,
6726 MonoMethodMessage *this_obj,
6727 MonoReflectionMethod *method,
6728 MonoArray *out_args)
6730 MONO_REQ_GC_UNSAFE_MODE;
6732 static MonoClass *object_array_klass;
6733 static MonoClass *byte_array_klass;
6734 static MonoClass *string_array_klass;
6736 MonoMethodSignature *sig = mono_method_signature (method->method);
6743 if (!object_array_klass) {
6746 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6748 byte_array_klass = klass;
6750 klass = mono_array_class_get (mono_defaults.string_class, 1);
6752 string_array_klass = klass;
6754 klass = mono_array_class_get (mono_defaults.object_class, 1);
6757 mono_atomic_store_release (&object_array_klass, klass);
6760 MONO_OBJECT_SETREF (this_obj, method, method);
6762 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6763 mono_error_raise_exception (&error); /* FIXME don't raise here */
6765 MONO_OBJECT_SETREF (this_obj, args, arr);
6767 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6768 mono_error_raise_exception (&error); /* FIXME don't raise here */
6770 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6772 this_obj->async_result = NULL;
6773 this_obj->call_type = CallType_Sync;
6775 names = g_new (char *, sig->param_count);
6776 mono_method_get_param_names (method->method, (const char **) names);
6778 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6779 mono_error_raise_exception (&error); /* FIXME don't raise here */
6781 MONO_OBJECT_SETREF (this_obj, names, arr);
6783 for (i = 0; i < sig->param_count; i++) {
6784 name = mono_string_new (domain, names [i]);
6785 mono_array_setref (this_obj->names, i, name);
6789 for (i = 0, j = 0; i < sig->param_count; i++) {
6790 if (sig->params [i]->byref) {
6792 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6793 mono_array_setref (this_obj->args, i, arg);
6797 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6801 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6804 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6808 #ifndef DISABLE_REMOTING
6810 * mono_remoting_invoke:
6811 * @real_proxy: pointer to a RealProxy object
6812 * @msg: The MonoMethodMessage to execute
6813 * @exc: used to store exceptions
6814 * @out_args: used to store output arguments
6816 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6817 * IMessage interface and it is not trivial to extract results from there. So
6818 * we call an helper method PrivateInvoke instead of calling
6819 * RealProxy::Invoke() directly.
6821 * Returns: the result object.
6824 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6825 MonoObject **exc, MonoArray **out_args)
6827 MONO_REQ_GC_UNSAFE_MODE;
6831 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6834 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6837 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6839 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6840 real_proxy->vtable->domain->private_invoke_method = im;
6843 pa [0] = real_proxy;
6849 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6851 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6853 mono_error_raise_exception (&error); /* FIXME don't raise here */
6860 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6861 MonoObject **exc, MonoArray **out_args)
6863 MONO_REQ_GC_UNSAFE_MODE;
6865 static MonoClass *object_array_klass;
6869 MonoMethodSignature *sig;
6872 int i, j, outarg_count = 0;
6874 #ifndef DISABLE_REMOTING
6875 if (target && mono_object_is_transparent_proxy (target)) {
6876 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6877 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6878 target = tp->rp->unwrapped_server;
6880 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6885 domain = mono_domain_get ();
6886 method = msg->method->method;
6887 sig = mono_method_signature (method);
6889 for (i = 0; i < sig->param_count; i++) {
6890 if (sig->params [i]->byref)
6894 if (!object_array_klass) {
6897 klass = mono_array_class_get (mono_defaults.object_class, 1);
6900 mono_memory_barrier ();
6901 object_array_klass = klass;
6904 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6905 mono_error_raise_exception (&error); /* FIXME don't raise here */
6907 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6910 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6912 for (i = 0, j = 0; i < sig->param_count; i++) {
6913 if (sig->params [i]->byref) {
6915 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6916 mono_array_setref (*out_args, j, arg);
6925 * mono_object_to_string:
6927 * @exc: Any exception thrown by ToString (). May be NULL.
6929 * Returns: the result of calling ToString () on an object.
6932 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6934 MONO_REQ_GC_UNSAFE_MODE;
6936 static MonoMethod *to_string = NULL;
6945 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6947 method = mono_object_get_virtual_method (obj, to_string);
6949 // Unbox value type if needed
6950 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6951 target = mono_object_unbox (obj);
6955 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6956 if (*exc == NULL && !mono_error_ok (&error))
6957 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6959 mono_error_cleanup (&error);
6961 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6962 mono_error_raise_exception (&error); /* FIXME don't raise here */
6969 * mono_print_unhandled_exception:
6970 * @exc: The exception
6972 * Prints the unhandled exception.
6975 mono_print_unhandled_exception (MonoObject *exc)
6977 MONO_REQ_GC_UNSAFE_MODE;
6980 char *message = (char*)"";
6981 gboolean free_message = FALSE;
6984 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6985 message = g_strdup ("OutOfMemoryException");
6986 free_message = TRUE;
6987 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6988 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6989 free_message = TRUE;
6992 if (((MonoException*)exc)->native_trace_ips) {
6993 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6994 free_message = TRUE;
6996 MonoObject *other_exc = NULL;
6997 str = mono_object_to_string (exc, &other_exc);
6999 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7000 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7002 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7003 original_backtrace, nested_backtrace);
7005 g_free (original_backtrace);
7006 g_free (nested_backtrace);
7007 free_message = TRUE;
7009 message = mono_string_to_utf8_checked (str, &error);
7010 if (!mono_error_ok (&error)) {
7011 mono_error_cleanup (&error);
7012 message = (char *) "";
7014 free_message = TRUE;
7021 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7022 * exc->vtable->klass->name, message);
7024 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7031 * mono_delegate_ctor:
7032 * @this: pointer to an uninitialized delegate object
7033 * @target: target object
7034 * @addr: pointer to native code
7037 * Initialize a delegate and sets a specific method, not the one
7038 * associated with addr. This is useful when sharing generic code.
7039 * In that case addr will most probably not be associated with the
7040 * correct instantiation of the method.
7043 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7045 MONO_REQ_GC_UNSAFE_MODE;
7047 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7049 g_assert (this_obj);
7052 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7055 delegate->method = method;
7057 mono_stats.delegate_creations++;
7059 #ifndef DISABLE_REMOTING
7060 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7062 method = mono_marshal_get_remoting_invoke (method);
7063 delegate->method_ptr = mono_compile_method (method);
7064 MONO_OBJECT_SETREF (delegate, target, target);
7068 delegate->method_ptr = addr;
7069 MONO_OBJECT_SETREF (delegate, target, target);
7072 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7073 if (callbacks.init_delegate)
7074 callbacks.init_delegate (delegate);
7078 * mono_delegate_ctor:
7079 * @this: pointer to an uninitialized delegate object
7080 * @target: target object
7081 * @addr: pointer to native code
7083 * This is used to initialize a delegate.
7086 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7088 MONO_REQ_GC_UNSAFE_MODE;
7090 MonoDomain *domain = mono_domain_get ();
7092 MonoMethod *method = NULL;
7096 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7098 if (!ji && domain != mono_get_root_domain ())
7099 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7101 method = mono_jit_info_get_method (ji);
7102 g_assert (!method->klass->generic_container);
7105 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7109 * mono_method_call_message_new:
7110 * @method: method to encapsulate
7111 * @params: parameters to the method
7112 * @invoke: optional, delegate invoke.
7113 * @cb: async callback delegate.
7114 * @state: state passed to the async callback.
7116 * Translates arguments pointers into a MonoMethodMessage.
7119 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7120 MonoDelegate **cb, MonoObject **state)
7122 MONO_REQ_GC_UNSAFE_MODE;
7126 MonoDomain *domain = mono_domain_get ();
7127 MonoMethodSignature *sig = mono_method_signature (method);
7128 MonoMethodMessage *msg;
7131 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7132 mono_error_raise_exception (&error); /* FIXME don't raise here */
7135 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7136 mono_error_raise_exception (&error); /* FIXME don't raise here */
7137 mono_message_init (domain, msg, rm, NULL);
7138 count = sig->param_count - 2;
7140 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7141 mono_error_raise_exception (&error); /* FIXME don't raise here */
7142 mono_message_init (domain, msg, rm, NULL);
7143 count = sig->param_count;
7146 for (i = 0; i < count; i++) {
7151 if (sig->params [i]->byref)
7152 vpos = *((gpointer *)params [i]);
7156 klass = mono_class_from_mono_type (sig->params [i]);
7158 if (klass->valuetype)
7159 arg = mono_value_box (domain, klass, vpos);
7161 arg = *((MonoObject **)vpos);
7163 mono_array_setref (msg->args, i, arg);
7166 if (cb != NULL && state != NULL) {
7167 *cb = *((MonoDelegate **)params [i]);
7169 *state = *((MonoObject **)params [i]);
7176 * mono_method_return_message_restore:
7178 * Restore results from message based processing back to arguments pointers
7181 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7183 MONO_REQ_GC_UNSAFE_MODE;
7185 MonoMethodSignature *sig = mono_method_signature (method);
7186 int i, j, type, size, out_len;
7188 if (out_args == NULL)
7190 out_len = mono_array_length (out_args);
7194 for (i = 0, j = 0; i < sig->param_count; i++) {
7195 MonoType *pt = sig->params [i];
7200 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7202 arg = (char *)mono_array_get (out_args, gpointer, j);
7205 g_assert (type != MONO_TYPE_VOID);
7207 if (MONO_TYPE_IS_REFERENCE (pt)) {
7208 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7211 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7212 size = mono_class_value_size (klass, NULL);
7213 if (klass->has_references)
7214 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7216 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7218 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7219 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7228 #ifndef DISABLE_REMOTING
7231 * mono_load_remote_field:
7232 * @this: pointer to an object
7233 * @klass: klass of the object containing @field
7234 * @field: the field to load
7235 * @res: a storage to store the result
7237 * This method is called by the runtime on attempts to load fields of
7238 * transparent proxy objects. @this points to such TP, @klass is the class of
7239 * the object containing @field. @res is a storage location which can be
7240 * used to store the result.
7242 * Returns: an address pointing to the value of field.
7245 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7247 MONO_REQ_GC_UNSAFE_MODE;
7251 static MonoMethod *getter = NULL;
7252 MonoDomain *domain = mono_domain_get ();
7253 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7254 MonoClass *field_class;
7255 MonoMethodMessage *msg;
7256 MonoArray *out_args;
7260 g_assert (mono_object_is_transparent_proxy (this_obj));
7261 g_assert (res != NULL);
7263 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7264 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7269 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7271 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7274 field_class = mono_class_from_mono_type (field->type);
7276 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7277 mono_error_raise_exception (&error); /* FIXME don't raise here */
7278 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7279 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7280 mono_error_raise_exception (&error); /* FIXME don't raise here */
7281 mono_message_init (domain, msg, rm, out_args);
7283 full_name = mono_type_get_full_name (klass);
7284 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7285 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7288 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7290 if (exc) mono_raise_exception ((MonoException *)exc);
7292 if (mono_array_length (out_args) == 0)
7295 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7297 if (field_class->valuetype) {
7298 return ((char *)*res) + sizeof (MonoObject);
7304 * mono_load_remote_field_new:
7309 * Missing documentation.
7312 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7314 MONO_REQ_GC_UNSAFE_MODE;
7318 static MonoMethod *getter = NULL;
7319 MonoDomain *domain = mono_domain_get ();
7320 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7321 MonoClass *field_class;
7322 MonoMethodMessage *msg;
7323 MonoArray *out_args;
7324 MonoObject *exc, *res;
7327 g_assert (mono_object_is_transparent_proxy (this_obj));
7329 field_class = mono_class_from_mono_type (field->type);
7331 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7333 if (field_class->valuetype) {
7334 res = mono_object_new_checked (domain, field_class, &error);
7335 mono_error_raise_exception (&error); /* FIXME don't raise here */
7336 val = ((gchar *) res) + sizeof (MonoObject);
7340 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7345 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7347 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7350 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7351 mono_error_raise_exception (&error); /* FIXME don't raise here */
7352 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7354 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7355 mono_error_raise_exception (&error); /* FIXME don't raise here */
7356 mono_message_init (domain, msg, rm, out_args);
7358 full_name = mono_type_get_full_name (klass);
7359 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7360 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7363 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7365 if (exc) mono_raise_exception ((MonoException *)exc);
7367 if (mono_array_length (out_args) == 0)
7370 res = mono_array_get (out_args, MonoObject *, 0);
7376 * mono_store_remote_field:
7377 * @this_obj: pointer to an object
7378 * @klass: klass of the object containing @field
7379 * @field: the field to load
7380 * @val: the value/object to store
7382 * This method is called by the runtime on attempts to store fields of
7383 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7384 * the object containing @field. @val is the new value to store in @field.
7387 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7389 MONO_REQ_GC_UNSAFE_MODE;
7393 static MonoMethod *setter = NULL;
7394 MonoDomain *domain = mono_domain_get ();
7395 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7396 MonoClass *field_class;
7397 MonoMethodMessage *msg;
7398 MonoArray *out_args;
7403 g_assert (mono_object_is_transparent_proxy (this_obj));
7405 field_class = mono_class_from_mono_type (field->type);
7407 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7408 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7409 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7414 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7416 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7419 if (field_class->valuetype)
7420 arg = mono_value_box (domain, field_class, val);
7422 arg = *((MonoObject **)val);
7425 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7426 mono_error_raise_exception (&error); /* FIXME don't raise here */
7427 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7428 mono_error_raise_exception (&error); /* FIXME don't raise here */
7429 mono_message_init (domain, msg, rm, NULL);
7431 full_name = mono_type_get_full_name (klass);
7432 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7433 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7434 mono_array_setref (msg->args, 2, arg);
7437 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7439 if (exc) mono_raise_exception ((MonoException *)exc);
7443 * mono_store_remote_field_new:
7449 * Missing documentation
7452 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7454 MONO_REQ_GC_UNSAFE_MODE;
7458 static MonoMethod *setter = NULL;
7459 MonoDomain *domain = mono_domain_get ();
7460 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7461 MonoClass *field_class;
7462 MonoMethodMessage *msg;
7463 MonoArray *out_args;
7467 g_assert (mono_object_is_transparent_proxy (this_obj));
7469 field_class = mono_class_from_mono_type (field->type);
7471 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7472 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7473 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7478 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7480 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7483 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7484 mono_error_raise_exception (&error); /* FIXME don't raise here */
7485 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7486 mono_error_raise_exception (&error); /* FIXME don't raise here */
7487 mono_message_init (domain, msg, rm, NULL);
7489 full_name = mono_type_get_full_name (klass);
7490 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7491 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7492 mono_array_setref (msg->args, 2, arg);
7495 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7497 if (exc) mono_raise_exception ((MonoException *)exc);
7502 * mono_create_ftnptr:
7504 * Given a function address, create a function descriptor for it.
7505 * This is only needed on some platforms.
7508 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7510 return callbacks.create_ftnptr (domain, addr);
7514 * mono_get_addr_from_ftnptr:
7516 * Given a pointer to a function descriptor, return the function address.
7517 * This is only needed on some platforms.
7520 mono_get_addr_from_ftnptr (gpointer descr)
7522 return callbacks.get_addr_from_ftnptr (descr);
7526 * mono_string_chars:
7529 * Returns a pointer to the UCS16 characters stored in the MonoString
7532 mono_string_chars (MonoString *s)
7534 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7540 * mono_string_length:
7543 * Returns the lenght in characters of the string
7546 mono_string_length (MonoString *s)
7548 MONO_REQ_GC_UNSAFE_MODE;
7554 * mono_array_length:
7555 * @array: a MonoArray*
7557 * Returns the total number of elements in the array. This works for
7558 * both vectors and multidimensional arrays.
7561 mono_array_length (MonoArray *array)
7563 MONO_REQ_GC_UNSAFE_MODE;
7565 return array->max_length;
7569 * mono_array_addr_with_size:
7570 * @array: a MonoArray*
7571 * @size: size of the array elements
7572 * @idx: index into the array
7574 * Use this function to obtain the address for the @idx item on the
7575 * @array containing elements of size @size.
7577 * This method performs no bounds checking or type checking.
7579 * Returns the address of the @idx element in the array.
7582 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7584 MONO_REQ_GC_UNSAFE_MODE;
7586 return ((char*)(array)->vector) + size * idx;
7591 mono_glist_to_array (GList *list, MonoClass *eclass)
7593 MonoDomain *domain = mono_domain_get ();
7600 len = g_list_length (list);
7601 res = mono_array_new (domain, eclass, len);
7603 for (i = 0; list; list = list->next, i++)
7604 mono_array_set (res, gpointer, i, list->data);
7611 * The following section is purely to declare prototypes and
7612 * document the API, as these C files are processed by our
7618 * @array: array to alter
7619 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7620 * @index: index into the array
7621 * @value: value to set
7623 * Value Type version: This sets the @index's element of the @array
7624 * with elements of size sizeof(type) to the provided @value.
7626 * This macro does not attempt to perform type checking or bounds checking.
7628 * Use this to set value types in a `MonoArray`.
7630 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7635 * mono_array_setref:
7636 * @array: array to alter
7637 * @index: index into the array
7638 * @value: value to set
7640 * Reference Type version: This sets the @index's element of the
7641 * @array with elements of size sizeof(type) to the provided @value.
7643 * This macro does not attempt to perform type checking or bounds checking.
7645 * Use this to reference types in a `MonoArray`.
7647 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7653 * @array: array on which to operate on
7654 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7655 * @index: index into the array
7657 * Use this macro to retrieve the @index element of an @array and
7658 * extract the value assuming that the elements of the array match
7659 * the provided type value.
7661 * This method can be used with both arrays holding value types and
7662 * reference types. For reference types, the @type parameter should
7663 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7665 * This macro does not attempt to perform type checking or bounds checking.
7667 * Returns: The element at the @index position in the @array.
7669 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)