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 (MonoVTable *vtable)
4861 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4862 mono_error_raise_exception (&error);
4868 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4870 MONO_REQ_GC_UNSAFE_MODE;
4874 mono_error_init (error);
4876 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4878 if (G_UNLIKELY (!o))
4879 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4880 else if (G_UNLIKELY (vtable->klass->has_finalize))
4881 mono_object_register_finalizer (o);
4887 mono_object_new_fast (MonoVTable *vtable)
4890 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4891 mono_error_raise_exception (&error);
4897 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4899 MONO_REQ_GC_UNSAFE_MODE;
4903 mono_error_init (error);
4905 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4907 if (G_UNLIKELY (!o))
4908 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4914 ves_icall_object_new_fast (MonoVTable *vtable)
4917 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4918 mono_error_raise_exception (&error);
4924 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4926 MONO_REQ_GC_UNSAFE_MODE;
4930 mono_error_init (error);
4932 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
4934 if (G_UNLIKELY (!o))
4935 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4936 else if (G_UNLIKELY (vtable->klass->has_finalize))
4937 mono_object_register_finalizer (o);
4943 * mono_class_get_allocation_ftn:
4945 * @for_box: the object will be used for boxing
4946 * @pass_size_in_words:
4948 * Return the allocation function appropriate for the given class.
4952 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
4954 MONO_REQ_GC_NEUTRAL_MODE;
4956 *pass_size_in_words = FALSE;
4958 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
4959 return ves_icall_object_new_specific;
4961 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
4963 return ves_icall_object_new_fast;
4966 * FIXME: This is actually slower than ves_icall_object_new_fast, because
4967 * of the overhead of parameter passing.
4970 *pass_size_in_words = TRUE;
4971 #ifdef GC_REDIRECT_TO_LOCAL
4972 return GC_local_gcj_fast_malloc;
4974 return GC_gcj_fast_malloc;
4979 return ves_icall_object_new_specific;
4983 * mono_object_new_from_token:
4984 * @image: Context where the type_token is hosted
4985 * @token: a token of the type that we want to create
4987 * Returns: A newly created object whose definition is
4988 * looked up using @token in the @image image
4991 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
4993 MONO_REQ_GC_UNSAFE_MODE;
4999 klass = mono_class_get_checked (image, token, &error);
5000 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5002 result = mono_object_new_checked (domain, klass, &error);
5004 mono_error_raise_exception (&error); /* FIXME don't raise here */
5011 * mono_object_clone:
5012 * @obj: the object to clone
5014 * Returns: A newly created object who is a shallow copy of @obj
5017 mono_object_clone (MonoObject *obj)
5020 MonoObject *o = mono_object_clone_checked (obj, &error);
5021 mono_error_raise_exception (&error);
5027 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5029 MONO_REQ_GC_UNSAFE_MODE;
5034 mono_error_init (error);
5036 size = obj->vtable->klass->instance_size;
5038 if (obj->vtable->klass->rank)
5039 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5041 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5043 if (G_UNLIKELY (!o)) {
5044 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5048 /* If the object doesn't contain references this will do a simple memmove. */
5049 mono_gc_wbarrier_object_copy (o, obj);
5051 if (obj->vtable->klass->has_finalize)
5052 mono_object_register_finalizer (o);
5057 * mono_array_full_copy:
5058 * @src: source array to copy
5059 * @dest: destination array
5061 * Copies the content of one array to another with exactly the same type and size.
5064 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5066 MONO_REQ_GC_UNSAFE_MODE;
5069 MonoClass *klass = src->obj.vtable->klass;
5071 g_assert (klass == dest->obj.vtable->klass);
5073 size = mono_array_length (src);
5074 g_assert (size == mono_array_length (dest));
5075 size *= mono_array_element_size (klass);
5077 if (klass->element_class->valuetype) {
5078 if (klass->element_class->has_references)
5079 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5081 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5083 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5086 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5091 * mono_array_clone_in_domain:
5092 * @domain: the domain in which the array will be cloned into
5093 * @array: the array to clone
5095 * This routine returns a copy of the array that is hosted on the
5096 * specified MonoDomain.
5099 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5101 MONO_REQ_GC_UNSAFE_MODE;
5107 MonoClass *klass = array->obj.vtable->klass;
5109 if (array->bounds == NULL) {
5110 size = mono_array_length (array);
5111 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5112 mono_error_raise_exception (&error); /* FIXME don't raise here */
5114 size *= mono_array_element_size (klass);
5116 if (klass->element_class->valuetype) {
5117 if (klass->element_class->has_references)
5118 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5120 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5122 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5125 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5130 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5131 size = mono_array_element_size (klass);
5132 for (i = 0; i < klass->rank; ++i) {
5133 sizes [i] = array->bounds [i].length;
5134 size *= array->bounds [i].length;
5135 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5137 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5138 mono_error_raise_exception (&error); /* FIXME don't raise here */
5140 if (klass->element_class->valuetype) {
5141 if (klass->element_class->has_references)
5142 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5144 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5146 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5149 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5157 * @array: the array to clone
5159 * Returns: A newly created array who is a shallow copy of @array
5162 mono_array_clone (MonoArray *array)
5164 MONO_REQ_GC_UNSAFE_MODE;
5166 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5169 /* helper macros to check for overflow when calculating the size of arrays */
5170 #ifdef MONO_BIG_ARRAYS
5171 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5172 #define MYGUINT_MAX MYGUINT64_MAX
5173 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5174 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5175 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5176 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5177 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5179 #define MYGUINT32_MAX 4294967295U
5180 #define MYGUINT_MAX MYGUINT32_MAX
5181 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5182 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5183 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5184 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5185 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5189 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5191 MONO_REQ_GC_NEUTRAL_MODE;
5195 byte_len = mono_array_element_size (klass);
5196 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5199 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5201 byte_len += MONO_SIZEOF_MONO_ARRAY;
5209 * mono_array_new_full:
5210 * @domain: domain where the object is created
5211 * @array_class: array class
5212 * @lengths: lengths for each dimension in the array
5213 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5215 * This routine creates a new array objects with the given dimensions,
5216 * lower bounds and type.
5219 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5222 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5223 mono_error_raise_exception (&error);
5229 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5231 MONO_REQ_GC_UNSAFE_MODE;
5233 uintptr_t byte_len = 0, len, bounds_size;
5236 MonoArrayBounds *bounds;
5240 mono_error_init (error);
5242 if (!array_class->inited)
5243 mono_class_init (array_class);
5247 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5248 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5250 if (len > MONO_ARRAY_MAX_INDEX) {
5251 mono_error_set_generic_error (error, "System", "OverflowException", "");
5256 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5258 for (i = 0; i < array_class->rank; ++i) {
5259 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5260 mono_error_set_generic_error (error, "System", "OverflowException", "");
5263 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5264 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5271 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5272 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5278 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5279 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5282 byte_len = (byte_len + 3) & ~3;
5283 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5284 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5287 byte_len += bounds_size;
5290 * Following three lines almost taken from mono_object_new ():
5291 * they need to be kept in sync.
5293 vtable = mono_class_vtable_full (domain, array_class, TRUE);
5295 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5297 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5299 if (G_UNLIKELY (!o)) {
5300 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5304 array = (MonoArray*)o;
5306 bounds = array->bounds;
5309 for (i = 0; i < array_class->rank; ++i) {
5310 bounds [i].length = lengths [i];
5312 bounds [i].lower_bound = lower_bounds [i];
5321 * @domain: domain where the object is created
5322 * @eclass: element class
5323 * @n: number of array elements
5325 * This routine creates a new szarray with @n elements of type @eclass.
5328 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5330 MONO_REQ_GC_UNSAFE_MODE;
5336 ac = mono_array_class_get (eclass, 1);
5339 arr = mono_array_new_specific_checked (mono_class_vtable_full (domain, ac, TRUE), n, &error);
5340 mono_error_raise_exception (&error); /* FIXME don't raise here */
5346 * mono_array_new_specific:
5347 * @vtable: a vtable in the appropriate domain for an initialized class
5348 * @n: number of array elements
5350 * This routine is a fast alternative to mono_array_new() for code which
5351 * can be sure about the domain it operates in.
5354 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5357 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5358 mono_error_raise_exception (&error); /* FIXME don't raise here */
5364 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5366 MONO_REQ_GC_UNSAFE_MODE;
5371 mono_error_init (error);
5373 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5374 mono_error_set_generic_error (error, "System", "OverflowException", "");
5378 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5379 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5382 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5384 if (G_UNLIKELY (!o)) {
5385 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5389 return (MonoArray*)o;
5393 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5396 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5397 mono_error_raise_exception (&error);
5403 * mono_string_new_utf16:
5404 * @text: a pointer to an utf16 string
5405 * @len: the length of the string
5407 * Returns: A newly created string object which contains @text.
5410 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5412 MONO_REQ_GC_UNSAFE_MODE;
5415 MonoString *res = NULL;
5416 res = mono_string_new_utf16_checked (domain, text, len, &error);
5417 mono_error_raise_exception (&error);
5423 * mono_string_new_utf16_checked:
5424 * @text: a pointer to an utf16 string
5425 * @len: the length of the string
5426 * @error: written on error.
5428 * Returns: A newly created string object which contains @text.
5429 * On error, returns NULL and sets @error.
5432 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5434 MONO_REQ_GC_UNSAFE_MODE;
5438 mono_error_init (error);
5440 s = mono_string_new_size_checked (domain, len, error);
5442 memcpy (mono_string_chars (s), text, len * 2);
5448 * mono_string_new_utf32:
5449 * @text: a pointer to an utf32 string
5450 * @len: the length of the string
5452 * Returns: A newly created string object which contains @text.
5455 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5457 MONO_REQ_GC_UNSAFE_MODE;
5461 mono_unichar2 *utf16_output = NULL;
5462 gint32 utf16_len = 0;
5463 GError *gerror = NULL;
5464 glong items_written;
5466 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5469 g_error_free (gerror);
5471 while (utf16_output [utf16_len]) utf16_len++;
5473 s = mono_string_new_size_checked (domain, utf16_len, &error);
5474 mono_error_raise_exception (&error); /* FIXME don't raise here */
5476 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5478 g_free (utf16_output);
5484 * mono_string_new_size:
5485 * @text: a pointer to an utf16 string
5486 * @len: the length of the string
5488 * Returns: A newly created string object of @len
5491 mono_string_new_size (MonoDomain *domain, gint32 len)
5494 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5495 mono_error_raise_exception (&error);
5501 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5503 MONO_REQ_GC_UNSAFE_MODE;
5509 mono_error_init (error);
5511 /* check for overflow */
5512 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5513 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5517 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5518 g_assert (size > 0);
5520 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5523 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5525 if (G_UNLIKELY (!s)) {
5526 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5534 * mono_string_new_len:
5535 * @text: a pointer to an utf8 string
5536 * @length: number of bytes in @text to consider
5538 * Returns: A newly created string object which contains @text.
5541 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5543 MONO_REQ_GC_UNSAFE_MODE;
5546 GError *eg_error = NULL;
5547 MonoString *o = NULL;
5549 glong items_written;
5551 mono_error_init (&error);
5553 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5556 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5558 g_error_free (eg_error);
5562 mono_error_raise_exception (&error); /* FIXME don't raise here */
5568 * @text: a pointer to an utf8 string
5570 * Returns: A newly created string object which contains @text.
5572 * This function asserts if it cannot allocate a new string.
5574 * @deprecated Use mono_string_new_checked in new code.
5577 mono_string_new (MonoDomain *domain, const char *text)
5580 MonoString *res = NULL;
5581 res = mono_string_new_checked (domain, text, &error);
5582 mono_error_assert_ok (&error);
5587 * mono_string_new_checked:
5588 * @text: a pointer to an utf8 string
5589 * @merror: set on error
5591 * Returns: A newly created string object which contains @text.
5592 * On error returns NULL and sets @merror.
5595 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5597 MONO_REQ_GC_UNSAFE_MODE;
5599 GError *eg_error = NULL;
5600 MonoString *o = NULL;
5602 glong items_written;
5605 mono_error_init (error);
5609 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5612 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5614 g_error_free (eg_error);
5617 mono_error_raise_exception (error);
5619 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5624 MonoString *o = NULL;
5626 if (!g_utf8_validate (text, -1, &end)) {
5627 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5631 len = g_utf8_strlen (text, -1);
5632 o = mono_string_new_size_checked (domain, len, error);
5635 str = mono_string_chars (o);
5637 while (text < end) {
5638 *str++ = g_utf8_get_char (text);
5639 text = g_utf8_next_char (text);
5648 * mono_string_new_wrapper:
5649 * @text: pointer to utf8 characters.
5651 * Helper function to create a string object from @text in the current domain.
5654 mono_string_new_wrapper (const char *text)
5656 MONO_REQ_GC_UNSAFE_MODE;
5658 MonoDomain *domain = mono_domain_get ();
5661 return mono_string_new (domain, text);
5668 * @class: the class of the value
5669 * @value: a pointer to the unboxed data
5671 * Returns: A newly created object which contains @value.
5674 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5676 MONO_REQ_GC_UNSAFE_MODE;
5683 g_assert (klass->valuetype);
5684 if (mono_class_is_nullable (klass))
5685 return mono_nullable_box ((guint8 *)value, klass);
5687 vtable = mono_class_vtable (domain, klass);
5690 size = mono_class_instance_size (klass);
5691 res = mono_object_new_alloc_specific_checked (vtable, &error);
5692 mono_error_raise_exception (&error); /* FIXME don't raise here */
5694 size = size - sizeof (MonoObject);
5697 g_assert (size == mono_class_value_size (klass, NULL));
5698 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5700 #if NO_UNALIGNED_ACCESS
5701 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5705 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5708 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5711 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5714 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5717 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5721 if (klass->has_finalize)
5722 mono_object_register_finalizer (res);
5728 * @dest: destination pointer
5729 * @src: source pointer
5730 * @klass: a valuetype class
5732 * Copy a valuetype from @src to @dest. This function must be used
5733 * when @klass contains references fields.
5736 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5738 MONO_REQ_GC_UNSAFE_MODE;
5740 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5744 * mono_value_copy_array:
5745 * @dest: destination array
5746 * @dest_idx: index in the @dest array
5747 * @src: source pointer
5748 * @count: number of items
5750 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5751 * This function must be used when @klass contains references fields.
5752 * Overlap is handled.
5755 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5757 MONO_REQ_GC_UNSAFE_MODE;
5759 int size = mono_array_element_size (dest->obj.vtable->klass);
5760 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5761 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5762 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5766 * mono_object_get_domain:
5767 * @obj: object to query
5769 * Returns: the MonoDomain where the object is hosted
5772 mono_object_get_domain (MonoObject *obj)
5774 MONO_REQ_GC_UNSAFE_MODE;
5776 return mono_object_domain (obj);
5780 * mono_object_get_class:
5781 * @obj: object to query
5783 * Returns: the MonOClass of the object.
5786 mono_object_get_class (MonoObject *obj)
5788 MONO_REQ_GC_UNSAFE_MODE;
5790 return mono_object_class (obj);
5793 * mono_object_get_size:
5794 * @o: object to query
5796 * Returns: the size, in bytes, of @o
5799 mono_object_get_size (MonoObject* o)
5801 MONO_REQ_GC_UNSAFE_MODE;
5803 MonoClass* klass = mono_object_class (o);
5804 if (klass == mono_defaults.string_class) {
5805 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5806 } else if (o->vtable->rank) {
5807 MonoArray *array = (MonoArray*)o;
5808 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5809 if (array->bounds) {
5812 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5816 return mono_class_instance_size (klass);
5821 * mono_object_unbox:
5822 * @obj: object to unbox
5824 * Returns: a pointer to the start of the valuetype boxed in this
5827 * This method will assert if the object passed is not a valuetype.
5830 mono_object_unbox (MonoObject *obj)
5832 MONO_REQ_GC_UNSAFE_MODE;
5834 /* add assert for valuetypes? */
5835 g_assert (obj->vtable->klass->valuetype);
5836 return ((char*)obj) + sizeof (MonoObject);
5840 * mono_object_isinst:
5842 * @klass: a pointer to a class
5844 * Returns: @obj if @obj is derived from @klass
5847 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5849 MONO_REQ_GC_UNSAFE_MODE;
5852 mono_class_init (klass);
5854 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5855 return mono_object_isinst_mbyref (obj, klass);
5860 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5864 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5866 MONO_REQ_GC_UNSAFE_MODE;
5876 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5877 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5881 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5882 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5885 MonoClass *oklass = vt->klass;
5886 if (mono_class_is_transparent_proxy (oklass))
5887 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5889 mono_class_setup_supertypes (klass);
5890 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5893 #ifndef DISABLE_REMOTING
5894 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5896 MonoDomain *domain = mono_domain_get ();
5898 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5899 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5900 MonoMethod *im = NULL;
5903 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5905 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5906 im = mono_object_get_virtual_method (rp, im);
5909 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5910 mono_error_raise_exception (&error); /* FIXME don't raise here */
5913 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5914 mono_error_raise_exception (&error); /* FIXME don't raise here */
5916 if (*(MonoBoolean *) mono_object_unbox(res)) {
5917 /* Update the vtable of the remote type, so it can safely cast to this new type */
5918 mono_upgrade_remote_class (domain, obj, klass);
5922 #endif /* DISABLE_REMOTING */
5927 * mono_object_castclass_mbyref:
5929 * @klass: a pointer to a class
5931 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5934 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5936 MONO_REQ_GC_UNSAFE_MODE;
5938 if (!obj) return NULL;
5939 if (mono_object_isinst_mbyref (obj, klass)) return obj;
5941 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5943 "InvalidCastException"));
5948 MonoDomain *orig_domain;
5954 str_lookup (MonoDomain *domain, gpointer user_data)
5956 MONO_REQ_GC_UNSAFE_MODE;
5958 LDStrInfo *info = (LDStrInfo *)user_data;
5959 if (info->res || domain == info->orig_domain)
5961 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5965 mono_string_get_pinned (MonoString *str, MonoError *error)
5967 MONO_REQ_GC_UNSAFE_MODE;
5969 mono_error_init (error);
5971 /* We only need to make a pinned version of a string if this is a moving GC */
5972 if (!mono_gc_is_moving ())
5976 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5977 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5979 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5980 news->length = mono_string_length (str);
5982 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5988 mono_string_is_interned_lookup (MonoString *str, int insert)
5990 MONO_REQ_GC_UNSAFE_MODE;
5993 MonoGHashTable *ldstr_table;
5994 MonoString *s, *res;
5997 domain = ((MonoObject *)str)->vtable->domain;
5998 ldstr_table = domain->ldstr_table;
6000 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6006 /* Allocate outside the lock */
6008 s = mono_string_get_pinned (str, &error);
6009 mono_error_raise_exception (&error); /* FIXME don't raise here */
6012 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6017 mono_g_hash_table_insert (ldstr_table, s, s);
6022 LDStrInfo ldstr_info;
6023 ldstr_info.orig_domain = domain;
6024 ldstr_info.ins = str;
6025 ldstr_info.res = NULL;
6027 mono_domain_foreach (str_lookup, &ldstr_info);
6028 if (ldstr_info.res) {
6030 * the string was already interned in some other domain:
6031 * intern it in the current one as well.
6033 mono_g_hash_table_insert (ldstr_table, str, str);
6043 * mono_string_is_interned:
6044 * @o: String to probe
6046 * Returns whether the string has been interned.
6049 mono_string_is_interned (MonoString *o)
6051 MONO_REQ_GC_UNSAFE_MODE;
6053 return mono_string_is_interned_lookup (o, FALSE);
6057 * mono_string_intern:
6058 * @o: String to intern
6060 * Interns the string passed.
6061 * Returns: The interned string.
6064 mono_string_intern (MonoString *str)
6066 MONO_REQ_GC_UNSAFE_MODE;
6068 return mono_string_is_interned_lookup (str, TRUE);
6073 * @domain: the domain where the string will be used.
6074 * @image: a metadata context
6075 * @idx: index into the user string table.
6077 * Implementation for the ldstr opcode.
6078 * Returns: a loaded string from the @image/@idx combination.
6081 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6083 MONO_REQ_GC_UNSAFE_MODE;
6085 if (image->dynamic) {
6086 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6089 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6090 return NULL; /*FIXME we should probably be raising an exception here*/
6091 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6096 * mono_ldstr_metadata_sig
6097 * @domain: the domain for the string
6098 * @sig: the signature of a metadata string
6100 * Returns: a MonoString for a string stored in the metadata
6103 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6105 MONO_REQ_GC_UNSAFE_MODE;
6108 const char *str = sig;
6109 MonoString *o, *interned;
6112 len2 = mono_metadata_decode_blob_size (str, &str);
6115 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6116 mono_error_raise_exception (&error); /* FIXME don't raise here */
6117 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6120 guint16 *p2 = (guint16*)mono_string_chars (o);
6121 for (i = 0; i < len2; ++i) {
6122 *p2 = GUINT16_FROM_LE (*p2);
6128 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6131 return interned; /* o will get garbage collected */
6133 o = mono_string_get_pinned (o, &error);
6134 mono_error_raise_exception (&error); /* FIXME don't raise here */
6137 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6139 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6149 * mono_string_to_utf8:
6150 * @s: a System.String
6152 * Returns the UTF8 representation for @s.
6153 * The resulting buffer needs to be freed with mono_free().
6155 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6158 mono_string_to_utf8 (MonoString *s)
6160 MONO_REQ_GC_UNSAFE_MODE;
6163 char *result = mono_string_to_utf8_checked (s, &error);
6165 if (!mono_error_ok (&error))
6166 mono_error_raise_exception (&error);
6171 * mono_string_to_utf8_checked:
6172 * @s: a System.String
6173 * @error: a MonoError.
6175 * Converts a MonoString to its UTF8 representation. May fail; check
6176 * @error to determine whether the conversion was successful.
6177 * The resulting buffer should be freed with mono_free().
6180 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6182 MONO_REQ_GC_UNSAFE_MODE;
6186 GError *gerror = NULL;
6188 mono_error_init (error);
6194 return g_strdup ("");
6196 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6198 mono_error_set_argument (error, "string", "%s", gerror->message);
6199 g_error_free (gerror);
6202 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6203 if (s->length > written) {
6204 /* allocate the total length and copy the part of the string that has been converted */
6205 char *as2 = (char *)g_malloc0 (s->length);
6206 memcpy (as2, as, written);
6215 * mono_string_to_utf8_ignore:
6218 * Converts a MonoString to its UTF8 representation. Will ignore
6219 * invalid surrogate pairs.
6220 * The resulting buffer should be freed with mono_free().
6224 mono_string_to_utf8_ignore (MonoString *s)
6226 MONO_REQ_GC_UNSAFE_MODE;
6235 return g_strdup ("");
6237 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6239 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6240 if (s->length > written) {
6241 /* allocate the total length and copy the part of the string that has been converted */
6242 char *as2 = (char *)g_malloc0 (s->length);
6243 memcpy (as2, as, written);
6252 * mono_string_to_utf8_image_ignore:
6253 * @s: a System.String
6255 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6258 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6260 MONO_REQ_GC_UNSAFE_MODE;
6262 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6266 * mono_string_to_utf8_mp_ignore:
6267 * @s: a System.String
6269 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6272 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6274 MONO_REQ_GC_UNSAFE_MODE;
6276 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6281 * mono_string_to_utf16:
6284 * Return an null-terminated array of the utf-16 chars
6285 * contained in @s. The result must be freed with g_free().
6286 * This is a temporary helper until our string implementation
6287 * is reworked to always include the null terminating char.
6290 mono_string_to_utf16 (MonoString *s)
6292 MONO_REQ_GC_UNSAFE_MODE;
6299 as = (char *)g_malloc ((s->length * 2) + 2);
6300 as [(s->length * 2)] = '\0';
6301 as [(s->length * 2) + 1] = '\0';
6304 return (gunichar2 *)(as);
6307 memcpy (as, mono_string_chars(s), s->length * 2);
6308 return (gunichar2 *)(as);
6312 * mono_string_to_utf32:
6315 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6316 * contained in @s. The result must be freed with g_free().
6319 mono_string_to_utf32 (MonoString *s)
6321 MONO_REQ_GC_UNSAFE_MODE;
6323 mono_unichar4 *utf32_output = NULL;
6324 GError *error = NULL;
6325 glong items_written;
6330 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6333 g_error_free (error);
6335 return utf32_output;
6339 * mono_string_from_utf16:
6340 * @data: the UTF16 string (LPWSTR) to convert
6342 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6344 * Returns: a MonoString.
6347 mono_string_from_utf16 (gunichar2 *data)
6349 MONO_REQ_GC_UNSAFE_MODE;
6352 MonoString *res = NULL;
6353 MonoDomain *domain = mono_domain_get ();
6359 while (data [len]) len++;
6361 res = mono_string_new_utf16_checked (domain, data, len, &error);
6362 mono_error_raise_exception (&error); /* FIXME don't raise here */
6367 * mono_string_from_utf32:
6368 * @data: the UTF32 string (LPWSTR) to convert
6370 * Converts a UTF32 (UCS-4)to a MonoString.
6372 * Returns: a MonoString.
6375 mono_string_from_utf32 (mono_unichar4 *data)
6377 MONO_REQ_GC_UNSAFE_MODE;
6379 MonoString* result = NULL;
6380 mono_unichar2 *utf16_output = NULL;
6381 GError *error = NULL;
6382 glong items_written;
6388 while (data [len]) len++;
6390 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6393 g_error_free (error);
6395 result = mono_string_from_utf16 (utf16_output);
6396 g_free (utf16_output);
6401 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6403 MONO_REQ_GC_UNSAFE_MODE;
6410 r = mono_string_to_utf8_ignore (s);
6412 r = mono_string_to_utf8_checked (s, error);
6413 if (!mono_error_ok (error))
6420 len = strlen (r) + 1;
6422 mp_s = (char *)mono_mempool_alloc (mp, len);
6424 mp_s = (char *)mono_image_alloc (image, len);
6426 memcpy (mp_s, r, len);
6434 * mono_string_to_utf8_image:
6435 * @s: a System.String
6437 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6440 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6442 MONO_REQ_GC_UNSAFE_MODE;
6444 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6448 * mono_string_to_utf8_mp:
6449 * @s: a System.String
6451 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6454 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6456 MONO_REQ_GC_UNSAFE_MODE;
6458 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6462 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6465 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6467 eh_callbacks = *cbs;
6470 MonoRuntimeExceptionHandlingCallbacks *
6471 mono_get_eh_callbacks (void)
6473 return &eh_callbacks;
6477 * mono_raise_exception:
6478 * @ex: exception object
6480 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6483 mono_raise_exception (MonoException *ex)
6485 MONO_REQ_GC_UNSAFE_MODE;
6488 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6489 * that will cause gcc to omit the function epilog, causing problems when
6490 * the JIT tries to walk the stack, since the return address on the stack
6491 * will point into the next function in the executable, not this one.
6493 eh_callbacks.mono_raise_exception (ex);
6497 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6499 MONO_REQ_GC_UNSAFE_MODE;
6501 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6505 * mono_wait_handle_new:
6506 * @domain: Domain where the object will be created
6507 * @handle: Handle for the wait handle
6509 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6512 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6514 MONO_REQ_GC_UNSAFE_MODE;
6517 MonoWaitHandle *res;
6518 gpointer params [1];
6519 static MonoMethod *handle_set;
6521 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6522 mono_error_raise_exception (&error); /* FIXME don't raise here */
6524 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6526 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6528 params [0] = &handle;
6530 mono_runtime_invoke_checked (handle_set, res, params, &error);
6531 mono_error_raise_exception (&error); /* FIXME don't raise here */
6537 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6539 MONO_REQ_GC_UNSAFE_MODE;
6541 static MonoClassField *f_os_handle;
6542 static MonoClassField *f_safe_handle;
6544 if (!f_os_handle && !f_safe_handle) {
6545 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6546 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6551 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6555 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6562 mono_runtime_capture_context (MonoDomain *domain)
6564 MONO_REQ_GC_UNSAFE_MODE;
6566 RuntimeInvokeFunction runtime_invoke;
6568 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6569 MonoMethod *method = mono_get_context_capture_method ();
6570 MonoMethod *wrapper;
6573 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6574 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6575 domain->capture_context_method = mono_compile_method (method);
6578 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6580 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6583 * mono_async_result_new:
6584 * @domain:domain where the object will be created.
6585 * @handle: wait handle.
6586 * @state: state to pass to AsyncResult
6587 * @data: C closure data.
6589 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6590 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6594 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6596 MONO_REQ_GC_UNSAFE_MODE;
6599 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6600 mono_error_raise_exception (&error); /* FIXME don't raise here */
6601 MonoObject *context = mono_runtime_capture_context (domain);
6602 /* we must capture the execution context from the original thread */
6604 MONO_OBJECT_SETREF (res, execution_context, context);
6605 /* note: result may be null if the flow is suppressed */
6608 res->data = (void **)data;
6609 MONO_OBJECT_SETREF (res, object_data, object_data);
6610 MONO_OBJECT_SETREF (res, async_state, state);
6612 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6614 res->sync_completed = FALSE;
6615 res->completed = FALSE;
6621 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6623 MONO_REQ_GC_UNSAFE_MODE;
6630 g_assert (ares->async_delegate);
6632 ac = (MonoAsyncCall*) ares->object_data;
6634 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6636 gpointer wait_event = NULL;
6638 ac->msg->exc = NULL;
6639 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6640 MONO_OBJECT_SETREF (ac, res, res);
6642 mono_monitor_enter ((MonoObject*) ares);
6643 ares->completed = 1;
6645 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6646 mono_monitor_exit ((MonoObject*) ares);
6648 if (wait_event != NULL)
6649 SetEvent (wait_event);
6651 if (ac->cb_method) {
6652 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6653 mono_error_raise_exception (&error);
6661 mono_message_init (MonoDomain *domain,
6662 MonoMethodMessage *this_obj,
6663 MonoReflectionMethod *method,
6664 MonoArray *out_args)
6666 MONO_REQ_GC_UNSAFE_MODE;
6668 static MonoClass *object_array_klass;
6669 static MonoClass *byte_array_klass;
6670 static MonoClass *string_array_klass;
6672 MonoMethodSignature *sig = mono_method_signature (method->method);
6679 if (!object_array_klass) {
6682 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6684 byte_array_klass = klass;
6686 klass = mono_array_class_get (mono_defaults.string_class, 1);
6688 string_array_klass = klass;
6690 klass = mono_array_class_get (mono_defaults.object_class, 1);
6693 mono_atomic_store_release (&object_array_klass, klass);
6696 MONO_OBJECT_SETREF (this_obj, method, method);
6698 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6699 mono_error_raise_exception (&error); /* FIXME don't raise here */
6701 MONO_OBJECT_SETREF (this_obj, args, arr);
6703 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6704 mono_error_raise_exception (&error); /* FIXME don't raise here */
6706 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6708 this_obj->async_result = NULL;
6709 this_obj->call_type = CallType_Sync;
6711 names = g_new (char *, sig->param_count);
6712 mono_method_get_param_names (method->method, (const char **) names);
6714 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6715 mono_error_raise_exception (&error); /* FIXME don't raise here */
6717 MONO_OBJECT_SETREF (this_obj, names, arr);
6719 for (i = 0; i < sig->param_count; i++) {
6720 name = mono_string_new (domain, names [i]);
6721 mono_array_setref (this_obj->names, i, name);
6725 for (i = 0, j = 0; i < sig->param_count; i++) {
6726 if (sig->params [i]->byref) {
6728 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6729 mono_array_setref (this_obj->args, i, arg);
6733 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6737 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6740 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6744 #ifndef DISABLE_REMOTING
6746 * mono_remoting_invoke:
6747 * @real_proxy: pointer to a RealProxy object
6748 * @msg: The MonoMethodMessage to execute
6749 * @exc: used to store exceptions
6750 * @out_args: used to store output arguments
6752 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6753 * IMessage interface and it is not trivial to extract results from there. So
6754 * we call an helper method PrivateInvoke instead of calling
6755 * RealProxy::Invoke() directly.
6757 * Returns: the result object.
6760 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6761 MonoObject **exc, MonoArray **out_args)
6763 MONO_REQ_GC_UNSAFE_MODE;
6767 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6770 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6773 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6775 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6776 real_proxy->vtable->domain->private_invoke_method = im;
6779 pa [0] = real_proxy;
6785 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6787 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6789 mono_error_raise_exception (&error); /* FIXME don't raise here */
6796 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6797 MonoObject **exc, MonoArray **out_args)
6799 MONO_REQ_GC_UNSAFE_MODE;
6801 static MonoClass *object_array_klass;
6805 MonoMethodSignature *sig;
6808 int i, j, outarg_count = 0;
6810 #ifndef DISABLE_REMOTING
6811 if (target && mono_object_is_transparent_proxy (target)) {
6812 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6813 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6814 target = tp->rp->unwrapped_server;
6816 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6821 domain = mono_domain_get ();
6822 method = msg->method->method;
6823 sig = mono_method_signature (method);
6825 for (i = 0; i < sig->param_count; i++) {
6826 if (sig->params [i]->byref)
6830 if (!object_array_klass) {
6833 klass = mono_array_class_get (mono_defaults.object_class, 1);
6836 mono_memory_barrier ();
6837 object_array_klass = klass;
6840 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6841 mono_error_raise_exception (&error); /* FIXME don't raise here */
6843 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6846 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6848 for (i = 0, j = 0; i < sig->param_count; i++) {
6849 if (sig->params [i]->byref) {
6851 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6852 mono_array_setref (*out_args, j, arg);
6861 * mono_object_to_string:
6863 * @exc: Any exception thrown by ToString (). May be NULL.
6865 * Returns: the result of calling ToString () on an object.
6868 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6870 MONO_REQ_GC_UNSAFE_MODE;
6872 static MonoMethod *to_string = NULL;
6881 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6883 method = mono_object_get_virtual_method (obj, to_string);
6885 // Unbox value type if needed
6886 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6887 target = mono_object_unbox (obj);
6891 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6892 if (*exc == NULL && !mono_error_ok (&error))
6893 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6895 mono_error_cleanup (&error);
6897 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6898 mono_error_raise_exception (&error); /* FIXME don't raise here */
6905 * mono_print_unhandled_exception:
6906 * @exc: The exception
6908 * Prints the unhandled exception.
6911 mono_print_unhandled_exception (MonoObject *exc)
6913 MONO_REQ_GC_UNSAFE_MODE;
6916 char *message = (char*)"";
6917 gboolean free_message = FALSE;
6920 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6921 message = g_strdup ("OutOfMemoryException");
6922 free_message = TRUE;
6923 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6924 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6925 free_message = TRUE;
6928 if (((MonoException*)exc)->native_trace_ips) {
6929 message = mono_exception_get_native_backtrace ((MonoException*)exc);
6930 free_message = TRUE;
6932 MonoObject *other_exc = NULL;
6933 str = mono_object_to_string (exc, &other_exc);
6935 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6936 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6938 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6939 original_backtrace, nested_backtrace);
6941 g_free (original_backtrace);
6942 g_free (nested_backtrace);
6943 free_message = TRUE;
6945 message = mono_string_to_utf8_checked (str, &error);
6946 if (!mono_error_ok (&error)) {
6947 mono_error_cleanup (&error);
6948 message = (char *) "";
6950 free_message = TRUE;
6957 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
6958 * exc->vtable->klass->name, message);
6960 g_printerr ("\nUnhandled Exception:\n%s\n", message);
6967 * mono_delegate_ctor:
6968 * @this: pointer to an uninitialized delegate object
6969 * @target: target object
6970 * @addr: pointer to native code
6973 * Initialize a delegate and sets a specific method, not the one
6974 * associated with addr. This is useful when sharing generic code.
6975 * In that case addr will most probably not be associated with the
6976 * correct instantiation of the method.
6979 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6981 MONO_REQ_GC_UNSAFE_MODE;
6983 MonoDelegate *delegate = (MonoDelegate *)this_obj;
6985 g_assert (this_obj);
6988 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6991 delegate->method = method;
6993 mono_stats.delegate_creations++;
6995 #ifndef DISABLE_REMOTING
6996 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6998 method = mono_marshal_get_remoting_invoke (method);
6999 delegate->method_ptr = mono_compile_method (method);
7000 MONO_OBJECT_SETREF (delegate, target, target);
7004 delegate->method_ptr = addr;
7005 MONO_OBJECT_SETREF (delegate, target, target);
7008 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7009 if (callbacks.init_delegate)
7010 callbacks.init_delegate (delegate);
7014 * mono_delegate_ctor:
7015 * @this: pointer to an uninitialized delegate object
7016 * @target: target object
7017 * @addr: pointer to native code
7019 * This is used to initialize a delegate.
7022 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7024 MONO_REQ_GC_UNSAFE_MODE;
7026 MonoDomain *domain = mono_domain_get ();
7028 MonoMethod *method = NULL;
7032 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7034 if (!ji && domain != mono_get_root_domain ())
7035 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7037 method = mono_jit_info_get_method (ji);
7038 g_assert (!method->klass->generic_container);
7041 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7045 * mono_method_call_message_new:
7046 * @method: method to encapsulate
7047 * @params: parameters to the method
7048 * @invoke: optional, delegate invoke.
7049 * @cb: async callback delegate.
7050 * @state: state passed to the async callback.
7052 * Translates arguments pointers into a MonoMethodMessage.
7055 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7056 MonoDelegate **cb, MonoObject **state)
7058 MONO_REQ_GC_UNSAFE_MODE;
7062 MonoDomain *domain = mono_domain_get ();
7063 MonoMethodSignature *sig = mono_method_signature (method);
7064 MonoMethodMessage *msg;
7067 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7068 mono_error_raise_exception (&error); /* FIXME don't raise here */
7071 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7072 mono_error_raise_exception (&error); /* FIXME don't raise here */
7073 mono_message_init (domain, msg, rm, NULL);
7074 count = sig->param_count - 2;
7076 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7077 mono_error_raise_exception (&error); /* FIXME don't raise here */
7078 mono_message_init (domain, msg, rm, NULL);
7079 count = sig->param_count;
7082 for (i = 0; i < count; i++) {
7087 if (sig->params [i]->byref)
7088 vpos = *((gpointer *)params [i]);
7092 klass = mono_class_from_mono_type (sig->params [i]);
7094 if (klass->valuetype)
7095 arg = mono_value_box (domain, klass, vpos);
7097 arg = *((MonoObject **)vpos);
7099 mono_array_setref (msg->args, i, arg);
7102 if (cb != NULL && state != NULL) {
7103 *cb = *((MonoDelegate **)params [i]);
7105 *state = *((MonoObject **)params [i]);
7112 * mono_method_return_message_restore:
7114 * Restore results from message based processing back to arguments pointers
7117 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7119 MONO_REQ_GC_UNSAFE_MODE;
7121 MonoMethodSignature *sig = mono_method_signature (method);
7122 int i, j, type, size, out_len;
7124 if (out_args == NULL)
7126 out_len = mono_array_length (out_args);
7130 for (i = 0, j = 0; i < sig->param_count; i++) {
7131 MonoType *pt = sig->params [i];
7136 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7138 arg = (char *)mono_array_get (out_args, gpointer, j);
7141 g_assert (type != MONO_TYPE_VOID);
7143 if (MONO_TYPE_IS_REFERENCE (pt)) {
7144 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7147 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7148 size = mono_class_value_size (klass, NULL);
7149 if (klass->has_references)
7150 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7152 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7154 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7155 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7164 #ifndef DISABLE_REMOTING
7167 * mono_load_remote_field:
7168 * @this: pointer to an object
7169 * @klass: klass of the object containing @field
7170 * @field: the field to load
7171 * @res: a storage to store the result
7173 * This method is called by the runtime on attempts to load fields of
7174 * transparent proxy objects. @this points to such TP, @klass is the class of
7175 * the object containing @field. @res is a storage location which can be
7176 * used to store the result.
7178 * Returns: an address pointing to the value of field.
7181 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7183 MONO_REQ_GC_UNSAFE_MODE;
7187 static MonoMethod *getter = NULL;
7188 MonoDomain *domain = mono_domain_get ();
7189 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7190 MonoClass *field_class;
7191 MonoMethodMessage *msg;
7192 MonoArray *out_args;
7196 g_assert (mono_object_is_transparent_proxy (this_obj));
7197 g_assert (res != NULL);
7199 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7200 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7205 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7207 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7210 field_class = mono_class_from_mono_type (field->type);
7212 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7213 mono_error_raise_exception (&error); /* FIXME don't raise here */
7214 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7215 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7216 mono_error_raise_exception (&error); /* FIXME don't raise here */
7217 mono_message_init (domain, msg, rm, out_args);
7219 full_name = mono_type_get_full_name (klass);
7220 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7221 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7224 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7226 if (exc) mono_raise_exception ((MonoException *)exc);
7228 if (mono_array_length (out_args) == 0)
7231 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7233 if (field_class->valuetype) {
7234 return ((char *)*res) + sizeof (MonoObject);
7240 * mono_load_remote_field_new:
7245 * Missing documentation.
7248 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7250 MONO_REQ_GC_UNSAFE_MODE;
7254 static MonoMethod *getter = NULL;
7255 MonoDomain *domain = mono_domain_get ();
7256 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7257 MonoClass *field_class;
7258 MonoMethodMessage *msg;
7259 MonoArray *out_args;
7260 MonoObject *exc, *res;
7263 g_assert (mono_object_is_transparent_proxy (this_obj));
7265 field_class = mono_class_from_mono_type (field->type);
7267 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7269 if (field_class->valuetype) {
7270 res = mono_object_new_checked (domain, field_class, &error);
7271 mono_error_raise_exception (&error); /* FIXME don't raise here */
7272 val = ((gchar *) res) + sizeof (MonoObject);
7276 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7281 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7283 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7286 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7287 mono_error_raise_exception (&error); /* FIXME don't raise here */
7288 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7290 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7291 mono_error_raise_exception (&error); /* FIXME don't raise here */
7292 mono_message_init (domain, msg, rm, out_args);
7294 full_name = mono_type_get_full_name (klass);
7295 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7296 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7299 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7301 if (exc) mono_raise_exception ((MonoException *)exc);
7303 if (mono_array_length (out_args) == 0)
7306 res = mono_array_get (out_args, MonoObject *, 0);
7312 * mono_store_remote_field:
7313 * @this_obj: pointer to an object
7314 * @klass: klass of the object containing @field
7315 * @field: the field to load
7316 * @val: the value/object to store
7318 * This method is called by the runtime on attempts to store fields of
7319 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7320 * the object containing @field. @val is the new value to store in @field.
7323 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7325 MONO_REQ_GC_UNSAFE_MODE;
7329 static MonoMethod *setter = NULL;
7330 MonoDomain *domain = mono_domain_get ();
7331 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7332 MonoClass *field_class;
7333 MonoMethodMessage *msg;
7334 MonoArray *out_args;
7339 g_assert (mono_object_is_transparent_proxy (this_obj));
7341 field_class = mono_class_from_mono_type (field->type);
7343 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7344 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7345 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7350 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7352 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7355 if (field_class->valuetype)
7356 arg = mono_value_box (domain, field_class, val);
7358 arg = *((MonoObject **)val);
7361 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7362 mono_error_raise_exception (&error); /* FIXME don't raise here */
7363 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7364 mono_error_raise_exception (&error); /* FIXME don't raise here */
7365 mono_message_init (domain, msg, rm, NULL);
7367 full_name = mono_type_get_full_name (klass);
7368 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7369 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7370 mono_array_setref (msg->args, 2, arg);
7373 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7375 if (exc) mono_raise_exception ((MonoException *)exc);
7379 * mono_store_remote_field_new:
7385 * Missing documentation
7388 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7390 MONO_REQ_GC_UNSAFE_MODE;
7394 static MonoMethod *setter = NULL;
7395 MonoDomain *domain = mono_domain_get ();
7396 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7397 MonoClass *field_class;
7398 MonoMethodMessage *msg;
7399 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, ((gchar *) arg) + sizeof (MonoObject));
7409 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
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 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7420 mono_error_raise_exception (&error); /* FIXME don't raise here */
7421 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7422 mono_error_raise_exception (&error); /* FIXME don't raise here */
7423 mono_message_init (domain, msg, rm, NULL);
7425 full_name = mono_type_get_full_name (klass);
7426 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7427 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7428 mono_array_setref (msg->args, 2, arg);
7431 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7433 if (exc) mono_raise_exception ((MonoException *)exc);
7438 * mono_create_ftnptr:
7440 * Given a function address, create a function descriptor for it.
7441 * This is only needed on some platforms.
7444 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7446 return callbacks.create_ftnptr (domain, addr);
7450 * mono_get_addr_from_ftnptr:
7452 * Given a pointer to a function descriptor, return the function address.
7453 * This is only needed on some platforms.
7456 mono_get_addr_from_ftnptr (gpointer descr)
7458 return callbacks.get_addr_from_ftnptr (descr);
7462 * mono_string_chars:
7465 * Returns a pointer to the UCS16 characters stored in the MonoString
7468 mono_string_chars (MonoString *s)
7470 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7476 * mono_string_length:
7479 * Returns the lenght in characters of the string
7482 mono_string_length (MonoString *s)
7484 MONO_REQ_GC_UNSAFE_MODE;
7490 * mono_array_length:
7491 * @array: a MonoArray*
7493 * Returns the total number of elements in the array. This works for
7494 * both vectors and multidimensional arrays.
7497 mono_array_length (MonoArray *array)
7499 MONO_REQ_GC_UNSAFE_MODE;
7501 return array->max_length;
7505 * mono_array_addr_with_size:
7506 * @array: a MonoArray*
7507 * @size: size of the array elements
7508 * @idx: index into the array
7510 * Returns the address of the @idx element in the array.
7513 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7515 MONO_REQ_GC_UNSAFE_MODE;
7517 return ((char*)(array)->vector) + size * idx;
7522 mono_glist_to_array (GList *list, MonoClass *eclass)
7524 MonoDomain *domain = mono_domain_get ();
7531 len = g_list_length (list);
7532 res = mono_array_new (domain, eclass, len);
7534 for (i = 0; list; list = list->next, i++)
7535 mono_array_set (res, gpointer, i, list->data);