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/exception-internals.h>
27 #include <mono/metadata/domain-internals.h>
28 #include "mono/metadata/metadata-internals.h"
29 #include "mono/metadata/class-internals.h"
30 #include <mono/metadata/assembly.h>
31 #include <mono/metadata/marshal.h>
32 #include "mono/metadata/debug-helpers.h"
33 #include "mono/metadata/marshal.h"
34 #include <mono/metadata/threads.h>
35 #include <mono/metadata/threads-types.h>
36 #include <mono/metadata/environment.h>
37 #include "mono/metadata/profiler-private.h"
38 #include "mono/metadata/security-manager.h"
39 #include "mono/metadata/mono-debug-debugger.h"
40 #include <mono/metadata/gc-internals.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/reflection-internals.h>
43 #include <mono/utils/strenc.h>
44 #include <mono/utils/mono-counters.h>
45 #include <mono/utils/mono-error-internals.h>
46 #include <mono/utils/mono-memory-model.h>
47 #include <mono/utils/checked-build.h>
48 #include <mono/utils/mono-threads.h>
49 #include "cominterop.h"
52 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
55 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
58 free_main_args (void);
61 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
63 /* Class lazy loading functions */
64 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
65 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
66 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
67 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
68 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
71 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
72 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
73 static mono_mutex_t ldstr_section;
76 * mono_runtime_object_init:
77 * @this_obj: the object to initialize
79 * This function calls the zero-argument constructor (which must
80 * exist) for the given object.
83 mono_runtime_object_init (MonoObject *this_obj)
86 mono_runtime_object_init_checked (this_obj, &error);
87 mono_error_assert_ok (&error);
91 * mono_runtime_object_init_checked:
92 * @this_obj: the object to initialize
93 * @error: set on error.
95 * This function calls the zero-argument constructor (which must
96 * exist) for the given object and returns TRUE on success, or FALSE
97 * on error and sets @error.
100 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
102 MONO_REQ_GC_UNSAFE_MODE;
104 MonoMethod *method = NULL;
105 MonoClass *klass = this_obj->vtable->klass;
107 mono_error_init (error);
108 method = mono_class_get_method_from_name (klass, ".ctor", 0);
110 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
112 if (method->klass->valuetype)
113 this_obj = (MonoObject *)mono_object_unbox (this_obj);
115 mono_runtime_invoke_checked (method, this_obj, NULL, error);
116 return is_ok (error);
119 /* The pseudo algorithm for type initialization from the spec
120 Note it doesn't say anything about domains - only threads.
122 2. If the type is initialized you are done.
123 2.1. If the type is not yet initialized, try to take an
125 2.2. If successful, record this thread as responsible for
126 initializing the type and proceed to step 2.3.
127 2.2.1. If not, see whether this thread or any thread
128 waiting for this thread to complete already holds the lock.
129 2.2.2. If so, return since blocking would create a deadlock. This thread
130 will now see an incompletely initialized state for the type,
131 but no deadlock will arise.
132 2.2.3 If not, block until the type is initialized then return.
133 2.3 Initialize the parent type and then all interfaces implemented
135 2.4 Execute the type initialization code for this type.
136 2.5 Mark the type as initialized, release the initialization lock,
137 awaken any threads waiting for this type to be initialized,
144 MonoNativeThreadId initializing_tid;
145 guint32 waiting_count;
147 MonoCoopMutex initialization_section;
148 } TypeInitializationLock;
150 /* for locking access to type_initialization_hash and blocked_thread_hash */
151 static MonoCoopMutex type_initialization_section;
154 mono_type_initialization_lock (void)
156 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
157 mono_coop_mutex_lock (&type_initialization_section);
161 mono_type_initialization_unlock (void)
163 mono_coop_mutex_unlock (&type_initialization_section);
167 mono_type_init_lock (TypeInitializationLock *lock)
169 MONO_REQ_GC_NEUTRAL_MODE;
171 mono_coop_mutex_lock (&lock->initialization_section);
175 mono_type_init_unlock (TypeInitializationLock *lock)
177 mono_coop_mutex_unlock (&lock->initialization_section);
180 /* from vtable to lock */
181 static GHashTable *type_initialization_hash;
183 /* from thread id to thread id being waited on */
184 static GHashTable *blocked_thread_hash;
187 static MonoThread *main_thread;
189 /* Functions supplied by the runtime */
190 static MonoRuntimeCallbacks callbacks;
193 * mono_thread_set_main:
194 * @thread: thread to set as the main thread
196 * This function can be used to instruct the runtime to treat @thread
197 * as the main thread, ie, the thread that would normally execute the Main()
198 * method. This basically means that at the end of @thread, the runtime will
199 * wait for the existing foreground threads to quit and other such details.
202 mono_thread_set_main (MonoThread *thread)
204 MONO_REQ_GC_UNSAFE_MODE;
206 static gboolean registered = FALSE;
209 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
213 main_thread = thread;
217 mono_thread_get_main (void)
219 MONO_REQ_GC_UNSAFE_MODE;
225 mono_type_initialization_init (void)
227 mono_coop_mutex_init_recursive (&type_initialization_section);
228 type_initialization_hash = g_hash_table_new (NULL, NULL);
229 blocked_thread_hash = g_hash_table_new (NULL, NULL);
230 mono_os_mutex_init_recursive (&ldstr_section);
234 mono_type_initialization_cleanup (void)
237 /* This is causing race conditions with
238 * mono_release_type_locks
240 mono_coop_mutex_destroy (&type_initialization_section);
241 g_hash_table_destroy (type_initialization_hash);
242 type_initialization_hash = NULL;
244 mono_os_mutex_destroy (&ldstr_section);
245 g_hash_table_destroy (blocked_thread_hash);
246 blocked_thread_hash = NULL;
252 * get_type_init_exception_for_vtable:
254 * Return the stored type initialization exception for VTABLE.
256 static MonoException*
257 get_type_init_exception_for_vtable (MonoVTable *vtable)
259 MONO_REQ_GC_UNSAFE_MODE;
262 MonoDomain *domain = vtable->domain;
263 MonoClass *klass = vtable->klass;
267 if (!vtable->init_failed)
268 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
271 * If the initializing thread was rudely aborted, the exception is not stored
275 mono_domain_lock (domain);
276 if (domain->type_init_exception_hash)
277 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
278 mono_domain_unlock (domain);
281 if (klass->name_space && *klass->name_space)
282 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
284 full_name = g_strdup (klass->name);
285 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
287 return_val_if_nok (&error, NULL);
294 * mono_runtime_class_init:
295 * @vtable: vtable that needs to be initialized
297 * This routine calls the class constructor for @vtable.
300 mono_runtime_class_init (MonoVTable *vtable)
302 MONO_REQ_GC_UNSAFE_MODE;
305 mono_runtime_class_init_full (vtable, &error);
306 mono_error_assert_ok (&error);
310 * mono_runtime_class_init_full:
311 * @vtable that neeeds to be initialized
312 * @error set on error
314 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
318 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
320 MONO_REQ_GC_UNSAFE_MODE;
322 MonoMethod *method = NULL;
325 MonoDomain *domain = vtable->domain;
326 TypeInitializationLock *lock;
327 MonoNativeThreadId tid;
328 int do_initialization = 0;
329 MonoDomain *last_domain = NULL;
331 mono_error_init (error);
333 if (vtable->initialized)
336 klass = vtable->klass;
338 if (!klass->image->checked_module_cctor) {
339 mono_image_check_for_module_cctor (klass->image);
340 if (klass->image->has_module_cctor) {
341 MonoClass *module_klass;
342 MonoVTable *module_vtable;
344 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
349 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
352 if (!mono_runtime_class_init_full (module_vtable, error))
356 method = mono_class_get_cctor (klass);
358 vtable->initialized = 1;
362 tid = mono_native_thread_id_get ();
364 mono_type_initialization_lock ();
365 /* double check... */
366 if (vtable->initialized) {
367 mono_type_initialization_unlock ();
370 if (vtable->init_failed) {
371 mono_type_initialization_unlock ();
373 /* The type initialization already failed once, rethrow the same exception */
374 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
377 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
379 /* This thread will get to do the initialization */
380 if (mono_domain_get () != domain) {
381 /* Transfer into the target domain */
382 last_domain = mono_domain_get ();
383 if (!mono_domain_set (domain, FALSE)) {
384 vtable->initialized = 1;
385 mono_type_initialization_unlock ();
386 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
390 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
391 mono_coop_mutex_init_recursive (&lock->initialization_section);
392 lock->initializing_tid = tid;
393 lock->waiting_count = 1;
395 /* grab the vtable lock while this thread still owns type_initialization_section */
396 /* This is why type_initialization_lock needs to enter blocking mode */
397 mono_type_init_lock (lock);
398 g_hash_table_insert (type_initialization_hash, vtable, lock);
399 do_initialization = 1;
402 TypeInitializationLock *pending_lock;
404 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
405 mono_type_initialization_unlock ();
408 /* see if the thread doing the initialization is already blocked on this thread */
409 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
410 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
411 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
412 if (!pending_lock->done) {
413 mono_type_initialization_unlock ();
416 /* the thread doing the initialization is blocked on this thread,
417 but on a lock that has already been freed. It just hasn't got
422 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
424 ++lock->waiting_count;
425 /* record the fact that we are waiting on the initializing thread */
426 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
428 mono_type_initialization_unlock ();
430 if (do_initialization) {
431 MonoException *exc = NULL;
432 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
433 if (exc != NULL && mono_error_ok (error)) {
434 mono_error_set_exception_instance (error, exc);
437 /* If the initialization failed, mark the class as unusable. */
438 /* Avoid infinite loops */
439 if (!(mono_error_ok(error) ||
440 (klass->image == mono_defaults.corlib &&
441 !strcmp (klass->name_space, "System") &&
442 !strcmp (klass->name, "TypeInitializationException")))) {
443 vtable->init_failed = 1;
445 if (klass->name_space && *klass->name_space)
446 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
448 full_name = g_strdup (klass->name);
450 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
452 return_val_if_nok (error, FALSE);
454 mono_error_set_exception_instance (error, exc_to_throw);
456 MonoException *exc_to_store = mono_error_convert_to_exception (error);
457 /* What we really want to do here is clone the error object and store one copy in the
458 * domain's exception hash and use the other one to error out here. */
459 mono_error_set_exception_instance (error, exc_to_store);
461 * Store the exception object so it could be thrown on subsequent
464 mono_domain_lock (domain);
465 if (!domain->type_init_exception_hash)
466 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");
467 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
468 mono_domain_unlock (domain);
472 mono_domain_set (last_domain, TRUE);
474 mono_type_init_unlock (lock);
476 /* this just blocks until the initializing thread is done */
477 mono_type_init_lock (lock);
478 mono_type_init_unlock (lock);
481 mono_type_initialization_lock ();
482 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
483 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
484 --lock->waiting_count;
485 if (lock->waiting_count == 0) {
486 mono_coop_mutex_destroy (&lock->initialization_section);
487 g_hash_table_remove (type_initialization_hash, vtable);
490 mono_memory_barrier ();
491 if (!vtable->init_failed)
492 vtable->initialized = 1;
493 mono_type_initialization_unlock ();
495 if (vtable->init_failed) {
496 /* Either we were the initializing thread or we waited for the initialization */
497 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
504 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
506 MONO_REQ_GC_NEUTRAL_MODE;
508 MonoVTable *vtable = (MonoVTable*)key;
510 TypeInitializationLock *lock = (TypeInitializationLock*) value;
511 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
514 * Have to set this since it cannot be set by the normal code in
515 * mono_runtime_class_init (). In this case, the exception object is not stored,
516 * and get_type_init_exception_for_class () needs to be aware of this.
518 vtable->init_failed = 1;
519 mono_type_init_unlock (lock);
520 --lock->waiting_count;
521 if (lock->waiting_count == 0) {
522 mono_coop_mutex_destroy (&lock->initialization_section);
531 mono_release_type_locks (MonoInternalThread *thread)
533 MONO_REQ_GC_UNSAFE_MODE;
535 mono_type_initialization_lock ();
536 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
537 mono_type_initialization_unlock ();
540 #ifndef DISABLE_REMOTING
543 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
545 g_error ("remoting not installed");
549 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
553 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
555 g_assert_not_reached ();
559 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
560 static MonoImtThunkBuilder imt_thunk_builder;
561 static gboolean always_build_imt_thunks;
563 #if (MONO_IMT_SIZE > 32)
564 #error "MONO_IMT_SIZE cannot be larger than 32"
568 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
570 memcpy (&callbacks, cbs, sizeof (*cbs));
573 MonoRuntimeCallbacks*
574 mono_get_runtime_callbacks (void)
579 #ifndef DISABLE_REMOTING
581 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
583 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
588 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
590 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
594 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
595 imt_thunk_builder = func;
599 mono_set_always_build_imt_thunks (gboolean value)
601 always_build_imt_thunks = value;
605 * mono_compile_method:
606 * @method: The method to compile.
608 * This JIT-compiles the method, and returns the pointer to the native code
612 mono_compile_method (MonoMethod *method)
617 MONO_REQ_GC_NEUTRAL_MODE
619 if (!callbacks.compile_method) {
620 g_error ("compile method called on uninitialized runtime");
623 res = callbacks.compile_method (method, &error);
624 if (!mono_error_ok (&error))
625 mono_error_raise_exception (&error);
630 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
635 MONO_REQ_GC_NEUTRAL_MODE;
637 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, &error);
638 if (!mono_error_ok (&error))
639 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
644 mono_runtime_create_delegate_trampoline (MonoClass *klass)
646 MONO_REQ_GC_NEUTRAL_MODE
648 return arch_create_delegate_trampoline (mono_domain_get (), klass);
651 static MonoFreeMethodFunc default_mono_free_method = NULL;
654 * mono_install_free_method:
655 * @func: pointer to the MonoFreeMethodFunc used to release a method
657 * This is an internal VM routine, it is used for the engines to
658 * register a handler to release the resources associated with a method.
660 * Methods are freed when no more references to the delegate that holds
664 mono_install_free_method (MonoFreeMethodFunc func)
666 default_mono_free_method = func;
670 * mono_runtime_free_method:
671 * @domain; domain where the method is hosted
672 * @method: method to release
674 * This routine is invoked to free the resources associated with
675 * a method that has been JIT compiled. This is used to discard
676 * methods that were used only temporarily (for example, used in marshalling)
680 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
682 MONO_REQ_GC_NEUTRAL_MODE
684 if (default_mono_free_method != NULL)
685 default_mono_free_method (domain, method);
687 mono_method_clear_object (domain, method);
689 mono_free_method (method);
693 * The vtables in the root appdomain are assumed to be reachable by other
694 * roots, and we don't use typed allocation in the other domains.
697 /* The sync block is no longer a GC pointer */
698 #define GC_HEADER_BITMAP (0)
700 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
703 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
705 MONO_REQ_GC_NEUTRAL_MODE;
707 MonoClassField *field;
713 max_size = mono_class_data_size (klass) / sizeof (gpointer);
715 max_size = klass->instance_size / sizeof (gpointer);
716 if (max_size > size) {
717 g_assert (offset <= 0);
718 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
723 /*An Ephemeron cannot be marked by sgen*/
724 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
726 memset (bitmap, 0, size / 8);
731 for (p = klass; p != NULL; p = p->parent) {
732 gpointer iter = NULL;
733 while ((field = mono_class_get_fields (p, &iter))) {
737 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
739 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
742 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
745 /* FIXME: should not happen, flag as type load error */
746 if (field->type->byref)
749 if (static_fields && field->offset == -1)
753 pos = field->offset / sizeof (gpointer);
756 type = mono_type_get_underlying_type (field->type);
757 switch (type->type) {
760 case MONO_TYPE_FNPTR:
762 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
767 if (klass->image != mono_defaults.corlib)
770 case MONO_TYPE_STRING:
771 case MONO_TYPE_SZARRAY:
772 case MONO_TYPE_CLASS:
773 case MONO_TYPE_OBJECT:
774 case MONO_TYPE_ARRAY:
775 g_assert ((field->offset % sizeof(gpointer)) == 0);
777 g_assert (pos < size || pos <= max_size);
778 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
779 *max_set = MAX (*max_set, pos);
781 case MONO_TYPE_GENERICINST:
782 if (!mono_type_generic_inst_is_valuetype (type)) {
783 g_assert ((field->offset % sizeof(gpointer)) == 0);
785 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
786 *max_set = MAX (*max_set, pos);
791 case MONO_TYPE_VALUETYPE: {
792 MonoClass *fclass = mono_class_from_mono_type (field->type);
793 if (fclass->has_references) {
794 /* remove the object header */
795 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
809 case MONO_TYPE_BOOLEAN:
813 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
824 * mono_class_compute_bitmap:
826 * Mono internal function to compute a bitmap of reference fields in a class.
829 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
831 MONO_REQ_GC_NEUTRAL_MODE;
833 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
838 * similar to the above, but sets the bits in the bitmap for any non-ref field
839 * and ignores static fields
842 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
844 MonoClassField *field;
849 max_size = class->instance_size / sizeof (gpointer);
850 if (max_size >= size) {
851 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
854 for (p = class; p != NULL; p = p->parent) {
855 gpointer iter = NULL;
856 while ((field = mono_class_get_fields (p, &iter))) {
859 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
861 /* FIXME: should not happen, flag as type load error */
862 if (field->type->byref)
865 pos = field->offset / sizeof (gpointer);
868 type = mono_type_get_underlying_type (field->type);
869 switch (type->type) {
870 #if SIZEOF_VOID_P == 8
874 case MONO_TYPE_FNPTR:
879 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
880 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
881 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
884 #if SIZEOF_VOID_P == 4
888 case MONO_TYPE_FNPTR:
893 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
894 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
895 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
901 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
902 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
903 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
906 case MONO_TYPE_BOOLEAN:
909 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
911 case MONO_TYPE_STRING:
912 case MONO_TYPE_SZARRAY:
913 case MONO_TYPE_CLASS:
914 case MONO_TYPE_OBJECT:
915 case MONO_TYPE_ARRAY:
917 case MONO_TYPE_GENERICINST:
918 if (!mono_type_generic_inst_is_valuetype (type)) {
923 case MONO_TYPE_VALUETYPE: {
924 MonoClass *fclass = mono_class_from_mono_type (field->type);
925 /* remove the object header */
926 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
930 g_assert_not_reached ();
939 * mono_class_insecure_overlapping:
940 * check if a class with explicit layout has references and non-references
941 * fields overlapping.
943 * Returns: TRUE if it is insecure to load the type.
946 mono_class_insecure_overlapping (MonoClass *klass)
950 gsize default_bitmap [4] = {0};
952 gsize default_nrbitmap [4] = {0};
953 int i, insecure = FALSE;
956 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
957 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
959 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
960 int idx = i % (sizeof (bitmap [0]) * 8);
961 if (bitmap [idx] & nrbitmap [idx]) {
966 if (bitmap != default_bitmap)
968 if (nrbitmap != default_nrbitmap)
971 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
979 ves_icall_string_alloc (int length)
982 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
983 mono_error_raise_exception (&error);
989 mono_class_compute_gc_descriptor (MonoClass *klass)
991 MONO_REQ_GC_NEUTRAL_MODE;
995 gsize default_bitmap [4] = {0};
996 static gboolean gcj_inited = FALSE;
1001 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1002 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1005 mono_loader_unlock ();
1009 mono_class_init (klass);
1011 if (klass->gc_descr_inited)
1014 klass->gc_descr_inited = TRUE;
1015 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1017 bitmap = default_bitmap;
1018 if (klass == mono_defaults.string_class) {
1019 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1020 } else if (klass->rank) {
1021 mono_class_compute_gc_descriptor (klass->element_class);
1022 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1024 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1025 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1026 class->name_space, class->name);*/
1028 /* remove the object header */
1029 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1030 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));
1031 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1032 class->name_space, class->name);*/
1033 if (bitmap != default_bitmap)
1037 /*static int count = 0;
1040 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1041 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1043 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1044 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1046 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1047 if (bitmap != default_bitmap)
1053 * field_is_special_static:
1054 * @fklass: The MonoClass to look up.
1055 * @field: The MonoClassField describing the field.
1057 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1058 * SPECIAL_STATIC_NONE otherwise.
1061 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1063 MONO_REQ_GC_NEUTRAL_MODE;
1066 MonoCustomAttrInfo *ainfo;
1068 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1069 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1072 for (i = 0; i < ainfo->num_attrs; ++i) {
1073 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1074 if (klass->image == mono_defaults.corlib) {
1075 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1076 mono_custom_attrs_free (ainfo);
1077 return SPECIAL_STATIC_THREAD;
1079 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1080 mono_custom_attrs_free (ainfo);
1081 return SPECIAL_STATIC_CONTEXT;
1085 mono_custom_attrs_free (ainfo);
1086 return SPECIAL_STATIC_NONE;
1089 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1090 #define mix(a,b,c) { \
1091 a -= c; a ^= rot(c, 4); c += b; \
1092 b -= a; b ^= rot(a, 6); a += c; \
1093 c -= b; c ^= rot(b, 8); b += a; \
1094 a -= c; a ^= rot(c,16); c += b; \
1095 b -= a; b ^= rot(a,19); a += c; \
1096 c -= b; c ^= rot(b, 4); b += a; \
1098 #define final(a,b,c) { \
1099 c ^= b; c -= rot(b,14); \
1100 a ^= c; a -= rot(c,11); \
1101 b ^= a; b -= rot(a,25); \
1102 c ^= b; c -= rot(b,16); \
1103 a ^= c; a -= rot(c,4); \
1104 b ^= a; b -= rot(a,14); \
1105 c ^= b; c -= rot(b,24); \
1109 * mono_method_get_imt_slot:
1111 * The IMT slot is embedded into AOTed code, so this must return the same value
1112 * for the same method across all executions. This means:
1113 * - pointers shouldn't be used as hash values.
1114 * - mono_metadata_str_hash () should be used for hashing strings.
1117 mono_method_get_imt_slot (MonoMethod *method)
1119 MONO_REQ_GC_NEUTRAL_MODE;
1121 MonoMethodSignature *sig;
1123 guint32 *hashes_start, *hashes;
1127 /* This can be used to stress tests the collision code */
1131 * We do this to simplify generic sharing. It will hurt
1132 * performance in cases where a class implements two different
1133 * instantiations of the same generic interface.
1134 * The code in build_imt_slots () depends on this.
1136 if (method->is_inflated)
1137 method = ((MonoMethodInflated*)method)->declaring;
1139 sig = mono_method_signature (method);
1140 hashes_count = sig->param_count + 4;
1141 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1142 hashes = hashes_start;
1144 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1145 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1146 method->klass->name_space, method->klass->name, method->name);
1149 /* Initialize hashes */
1150 hashes [0] = mono_metadata_str_hash (method->klass->name);
1151 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1152 hashes [2] = mono_metadata_str_hash (method->name);
1153 hashes [3] = mono_metadata_type_hash (sig->ret);
1154 for (i = 0; i < sig->param_count; i++) {
1155 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1158 /* Setup internal state */
1159 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1161 /* Handle most of the hashes */
1162 while (hashes_count > 3) {
1171 /* Handle the last 3 hashes (all the case statements fall through) */
1172 switch (hashes_count) {
1173 case 3 : c += hashes [2];
1174 case 2 : b += hashes [1];
1175 case 1 : a += hashes [0];
1177 case 0: /* nothing left to add */
1181 free (hashes_start);
1182 /* Report the result */
1183 return c % MONO_IMT_SIZE;
1192 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1193 MONO_REQ_GC_NEUTRAL_MODE;
1195 guint32 imt_slot = mono_method_get_imt_slot (method);
1196 MonoImtBuilderEntry *entry;
1198 if (slot_num >= 0 && imt_slot != slot_num) {
1199 /* we build just a single imt slot and this is not it */
1203 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1204 entry->key = method;
1205 entry->value.vtable_slot = vtable_slot;
1206 entry->next = imt_builder [imt_slot];
1207 if (imt_builder [imt_slot] != NULL) {
1208 entry->children = imt_builder [imt_slot]->children + 1;
1209 if (entry->children == 1) {
1210 mono_stats.imt_slots_with_collisions++;
1211 *imt_collisions_bitmap |= (1 << imt_slot);
1214 entry->children = 0;
1215 mono_stats.imt_used_slots++;
1217 imt_builder [imt_slot] = entry;
1220 char *method_name = mono_method_full_name (method, TRUE);
1221 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1222 method, method_name, imt_slot, vtable_slot, entry->children);
1223 g_free (method_name);
1230 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1232 MonoMethod *method = e->key;
1233 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1237 method->klass->name_space,
1238 method->klass->name,
1241 printf (" * %s: NULL\n", message);
1247 compare_imt_builder_entries (const void *p1, const void *p2) {
1248 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1249 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1251 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1255 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1257 MONO_REQ_GC_NEUTRAL_MODE;
1259 int count = end - start;
1260 int chunk_start = out_array->len;
1263 for (i = start; i < end; ++i) {
1264 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1265 item->key = sorted_array [i]->key;
1266 item->value = sorted_array [i]->value;
1267 item->has_target_code = sorted_array [i]->has_target_code;
1268 item->is_equals = TRUE;
1270 item->check_target_idx = out_array->len + 1;
1272 item->check_target_idx = 0;
1273 g_ptr_array_add (out_array, item);
1276 int middle = start + count / 2;
1277 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1279 item->key = sorted_array [middle]->key;
1280 item->is_equals = FALSE;
1281 g_ptr_array_add (out_array, item);
1282 imt_emit_ir (sorted_array, start, middle, out_array);
1283 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1289 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1290 MONO_REQ_GC_NEUTRAL_MODE;
1292 int number_of_entries = entries->children + 1;
1293 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1294 GPtrArray *result = g_ptr_array_new ();
1295 MonoImtBuilderEntry *current_entry;
1298 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1299 sorted_array [i] = current_entry;
1301 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1303 /*for (i = 0; i < number_of_entries; i++) {
1304 print_imt_entry (" sorted array:", sorted_array [i], i);
1307 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1309 free (sorted_array);
1314 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1316 MONO_REQ_GC_NEUTRAL_MODE;
1318 if (imt_builder_entry != NULL) {
1319 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1320 /* No collision, return the vtable slot contents */
1321 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1323 /* Collision, build the thunk */
1324 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1327 result = imt_thunk_builder (vtable, domain,
1328 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1329 for (i = 0; i < imt_ir->len; ++i)
1330 g_free (g_ptr_array_index (imt_ir, i));
1331 g_ptr_array_free (imt_ir, TRUE);
1343 static MonoImtBuilderEntry*
1344 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1347 * LOCKING: requires the loader and domain locks.
1351 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1353 MONO_REQ_GC_NEUTRAL_MODE;
1357 guint32 imt_collisions_bitmap = 0;
1358 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1359 int method_count = 0;
1360 gboolean record_method_count_for_max_collisions = FALSE;
1361 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1364 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1366 for (i = 0; i < klass->interface_offsets_count; ++i) {
1367 MonoClass *iface = klass->interfaces_packed [i];
1368 int interface_offset = klass->interface_offsets_packed [i];
1369 int method_slot_in_interface, vt_slot;
1371 if (mono_class_has_variant_generic_params (iface))
1372 has_variant_iface = TRUE;
1374 mono_class_setup_methods (iface);
1375 vt_slot = interface_offset;
1376 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1379 if (slot_num >= 0 && iface->is_inflated) {
1381 * The imt slot of the method is the same as for its declaring method,
1382 * see the comment in mono_method_get_imt_slot (), so we can
1383 * avoid inflating methods which will be discarded by
1384 * add_imt_builder_entry anyway.
1386 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1387 if (mono_method_get_imt_slot (method) != slot_num) {
1392 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1393 if (method->is_generic) {
1394 has_generic_virtual = TRUE;
1399 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1400 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1405 if (extra_interfaces) {
1406 int interface_offset = klass->vtable_size;
1408 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1409 MonoClass* iface = (MonoClass *)list_item->data;
1410 int method_slot_in_interface;
1411 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1412 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1414 if (method->is_generic)
1415 has_generic_virtual = TRUE;
1416 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1418 interface_offset += iface->method.count;
1421 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1422 /* overwrite the imt slot only if we're building all the entries or if
1423 * we're building this specific one
1425 if (slot_num < 0 || i == slot_num) {
1426 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1429 if (imt_builder [i]) {
1430 MonoImtBuilderEntry *entry;
1432 /* Link entries with imt_builder [i] */
1433 for (entry = entries; entry->next; entry = entry->next) {
1435 MonoMethod *method = (MonoMethod*)entry->key;
1436 char *method_name = mono_method_full_name (method, TRUE);
1437 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1438 g_free (method_name);
1441 entry->next = imt_builder [i];
1442 entries->children += imt_builder [i]->children + 1;
1444 imt_builder [i] = entries;
1447 if (has_generic_virtual || has_variant_iface) {
1449 * There might be collisions later when the the thunk is expanded.
1451 imt_collisions_bitmap |= (1 << i);
1454 * The IMT thunk might be called with an instance of one of the
1455 * generic virtual methods, so has to fallback to the IMT trampoline.
1457 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1459 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1462 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1466 if (imt_builder [i] != NULL) {
1467 int methods_in_slot = imt_builder [i]->children + 1;
1468 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1469 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1470 record_method_count_for_max_collisions = TRUE;
1472 method_count += methods_in_slot;
1476 mono_stats.imt_number_of_methods += method_count;
1477 if (record_method_count_for_max_collisions) {
1478 mono_stats.imt_method_count_when_max_collisions = method_count;
1481 for (i = 0; i < MONO_IMT_SIZE; i++) {
1482 MonoImtBuilderEntry* entry = imt_builder [i];
1483 while (entry != NULL) {
1484 MonoImtBuilderEntry* next = entry->next;
1490 /* we OR the bitmap since we may build just a single imt slot at a time */
1491 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1495 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1496 MONO_REQ_GC_NEUTRAL_MODE;
1498 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1502 * mono_vtable_build_imt_slot:
1503 * @vtable: virtual object table struct
1504 * @imt_slot: slot in the IMT table
1506 * Fill the given @imt_slot in the IMT table of @vtable with
1507 * a trampoline or a thunk for the case of collisions.
1508 * This is part of the internal mono API.
1510 * LOCKING: Take the domain lock.
1513 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1515 MONO_REQ_GC_NEUTRAL_MODE;
1517 gpointer *imt = (gpointer*)vtable;
1518 imt -= MONO_IMT_SIZE;
1519 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1521 /* no support for extra interfaces: the proxy objects will need
1522 * to build the complete IMT
1523 * Update and heck needs to ahppen inside the proper domain lock, as all
1524 * the changes made to a MonoVTable.
1526 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1527 mono_domain_lock (vtable->domain);
1528 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1529 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1530 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1531 mono_domain_unlock (vtable->domain);
1532 mono_loader_unlock ();
1537 * The first two free list entries both belong to the wait list: The
1538 * first entry is the pointer to the head of the list and the second
1539 * entry points to the last element. That way appending and removing
1540 * the first element are both O(1) operations.
1542 #ifdef MONO_SMALL_CONFIG
1543 #define NUM_FREE_LISTS 6
1545 #define NUM_FREE_LISTS 12
1547 #define FIRST_FREE_LIST_SIZE 64
1548 #define MAX_WAIT_LENGTH 50
1549 #define THUNK_THRESHOLD 10
1552 * LOCKING: The domain lock must be held.
1555 init_thunk_free_lists (MonoDomain *domain)
1557 MONO_REQ_GC_NEUTRAL_MODE;
1559 if (domain->thunk_free_lists)
1561 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1565 list_index_for_size (int item_size)
1568 int size = FIRST_FREE_LIST_SIZE;
1570 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1579 * mono_method_alloc_generic_virtual_thunk:
1581 * @size: size in bytes
1583 * Allocs size bytes to be used for the code of a generic virtual
1584 * thunk. It's either allocated from the domain's code manager or
1585 * reused from a previously invalidated piece.
1587 * LOCKING: The domain lock must be held.
1590 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1592 MONO_REQ_GC_NEUTRAL_MODE;
1594 static gboolean inited = FALSE;
1595 static int generic_virtual_thunks_size = 0;
1599 MonoThunkFreeList **l;
1601 init_thunk_free_lists (domain);
1603 size += sizeof (guint32);
1604 if (size < sizeof (MonoThunkFreeList))
1605 size = sizeof (MonoThunkFreeList);
1607 i = list_index_for_size (size);
1608 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1609 if ((*l)->size >= size) {
1610 MonoThunkFreeList *item = *l;
1612 return ((guint32*)item) + 1;
1616 /* no suitable item found - search lists of larger sizes */
1617 while (++i < NUM_FREE_LISTS) {
1618 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1621 g_assert (item->size > size);
1622 domain->thunk_free_lists [i] = item->next;
1623 return ((guint32*)item) + 1;
1626 /* still nothing found - allocate it */
1628 mono_counters_register ("Generic virtual thunk bytes",
1629 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1632 generic_virtual_thunks_size += size;
1634 p = (guint32 *)mono_domain_code_reserve (domain, size);
1637 mono_domain_lock (domain);
1638 if (!domain->generic_virtual_thunks)
1639 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1640 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1641 mono_domain_unlock (domain);
1647 * LOCKING: The domain lock must be held.
1650 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1652 MONO_REQ_GC_NEUTRAL_MODE;
1654 guint32 *p = (guint32 *)code;
1655 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1656 gboolean found = FALSE;
1658 mono_domain_lock (domain);
1659 if (!domain->generic_virtual_thunks)
1660 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1661 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1663 mono_domain_unlock (domain);
1666 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1668 init_thunk_free_lists (domain);
1670 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1671 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1672 int length = item->length;
1675 /* unlink the first item from the wait list */
1676 domain->thunk_free_lists [0] = item->next;
1677 domain->thunk_free_lists [0]->length = length - 1;
1679 i = list_index_for_size (item->size);
1681 /* put it in the free list */
1682 item->next = domain->thunk_free_lists [i];
1683 domain->thunk_free_lists [i] = item;
1687 if (domain->thunk_free_lists [1]) {
1688 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1689 domain->thunk_free_lists [0]->length++;
1691 g_assert (!domain->thunk_free_lists [0]);
1693 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1694 domain->thunk_free_lists [0]->length = 1;
1698 typedef struct _GenericVirtualCase {
1702 struct _GenericVirtualCase *next;
1703 } GenericVirtualCase;
1706 * get_generic_virtual_entries:
1708 * Return IMT entries for the generic virtual method instances and
1709 * variant interface methods for vtable slot
1712 static MonoImtBuilderEntry*
1713 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1715 MONO_REQ_GC_NEUTRAL_MODE;
1717 GenericVirtualCase *list;
1718 MonoImtBuilderEntry *entries;
1720 mono_domain_lock (domain);
1721 if (!domain->generic_virtual_cases)
1722 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1724 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1727 for (; list; list = list->next) {
1728 MonoImtBuilderEntry *entry;
1730 if (list->count < THUNK_THRESHOLD)
1733 entry = g_new0 (MonoImtBuilderEntry, 1);
1734 entry->key = list->method;
1735 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1736 entry->has_target_code = 1;
1738 entry->children = entries->children + 1;
1739 entry->next = entries;
1743 mono_domain_unlock (domain);
1745 /* FIXME: Leaking memory ? */
1750 * mono_method_add_generic_virtual_invocation:
1752 * @vtable_slot: pointer to the vtable slot
1753 * @method: the inflated generic virtual method
1754 * @code: the method's code
1756 * Registers a call via unmanaged code to a generic virtual method
1757 * instantiation or variant interface method. If the number of calls reaches a threshold
1758 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1759 * virtual method thunk.
1762 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1763 gpointer *vtable_slot,
1764 MonoMethod *method, gpointer code)
1766 MONO_REQ_GC_NEUTRAL_MODE;
1768 static gboolean inited = FALSE;
1769 static int num_added = 0;
1771 GenericVirtualCase *gvc, *list;
1772 MonoImtBuilderEntry *entries;
1776 mono_domain_lock (domain);
1777 if (!domain->generic_virtual_cases)
1778 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1780 /* Check whether the case was already added */
1781 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1784 if (gvc->method == method)
1789 /* If not found, make a new one */
1791 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1792 gvc->method = method;
1795 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1797 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1800 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1806 if (++gvc->count == THUNK_THRESHOLD) {
1807 gpointer *old_thunk = (void **)*vtable_slot;
1808 gpointer vtable_trampoline = NULL;
1809 gpointer imt_trampoline = NULL;
1811 if ((gpointer)vtable_slot < (gpointer)vtable) {
1812 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1813 int imt_slot = MONO_IMT_SIZE + displacement;
1815 /* Force the rebuild of the thunk at the next call */
1816 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1817 *vtable_slot = imt_trampoline;
1819 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1821 entries = get_generic_virtual_entries (domain, vtable_slot);
1823 sorted = imt_sort_slot_entries (entries);
1825 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1829 MonoImtBuilderEntry *next = entries->next;
1834 for (i = 0; i < sorted->len; ++i)
1835 g_free (g_ptr_array_index (sorted, i));
1836 g_ptr_array_free (sorted, TRUE);
1839 #ifndef __native_client__
1840 /* We don't re-use any thunks as there is a lot of overhead */
1841 /* to deleting and re-using code in Native Client. */
1842 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1843 invalidate_generic_virtual_thunk (domain, old_thunk);
1847 mono_domain_unlock (domain);
1850 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1853 * mono_class_vtable:
1854 * @domain: the application domain
1855 * @class: the class to initialize
1857 * VTables are domain specific because we create domain specific code, and
1858 * they contain the domain specific static class data.
1859 * On failure, NULL is returned, and class->exception_type is set.
1862 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1865 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1866 mono_error_cleanup (&error);
1871 * mono_class_vtable_full:
1872 * @domain: the application domain
1873 * @class: the class to initialize
1874 * @error set on failure.
1876 * VTables are domain specific because we create domain specific code, and
1877 * they contain the domain specific static class data.
1880 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1882 MONO_REQ_GC_UNSAFE_MODE;
1884 MonoClassRuntimeInfo *runtime_info;
1886 mono_error_init (error);
1890 if (mono_class_has_failure (klass)) {
1891 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1895 /* this check can be inlined in jitted code, too */
1896 runtime_info = klass->runtime_info;
1897 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1898 return runtime_info->domain_vtables [domain->domain_id];
1899 return mono_class_create_runtime_vtable (domain, klass, error);
1903 * mono_class_try_get_vtable:
1904 * @domain: the application domain
1905 * @class: the class to initialize
1907 * This function tries to get the associated vtable from @class if
1908 * it was already created.
1911 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1913 MONO_REQ_GC_NEUTRAL_MODE;
1915 MonoClassRuntimeInfo *runtime_info;
1919 runtime_info = klass->runtime_info;
1920 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1921 return runtime_info->domain_vtables [domain->domain_id];
1926 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1928 MONO_REQ_GC_NEUTRAL_MODE;
1930 size_t alloc_offset;
1933 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1934 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1935 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1937 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1938 g_assert ((imt_table_bytes & 7) == 4);
1945 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1949 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1951 MONO_REQ_GC_UNSAFE_MODE;
1954 MonoClassRuntimeInfo *runtime_info, *old_info;
1955 MonoClassField *field;
1957 int i, vtable_slots;
1958 size_t imt_table_bytes;
1960 guint32 vtable_size, class_size;
1962 gpointer *interface_offsets;
1964 mono_error_init (error);
1966 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1967 mono_domain_lock (domain);
1968 runtime_info = klass->runtime_info;
1969 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1970 mono_domain_unlock (domain);
1971 mono_loader_unlock ();
1972 return runtime_info->domain_vtables [domain->domain_id];
1974 if (!klass->inited || mono_class_has_failure (klass)) {
1975 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1976 mono_domain_unlock (domain);
1977 mono_loader_unlock ();
1978 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1983 /* Array types require that their element type be valid*/
1984 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1985 MonoClass *element_class = klass->element_class;
1986 if (!element_class->inited)
1987 mono_class_init (element_class);
1989 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1990 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1991 mono_class_setup_vtable (element_class);
1993 if (mono_class_has_failure (element_class)) {
1994 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1995 if (!mono_class_has_failure (klass))
1996 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1997 mono_domain_unlock (domain);
1998 mono_loader_unlock ();
1999 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2005 * For some classes, mono_class_init () already computed klass->vtable_size, and
2006 * that is all that is needed because of the vtable trampolines.
2008 if (!klass->vtable_size)
2009 mono_class_setup_vtable (klass);
2011 if (klass->generic_class && !klass->vtable)
2012 mono_class_check_vtable_constraints (klass, NULL);
2014 /* Initialize klass->has_finalize */
2015 mono_class_has_finalizer (klass);
2017 if (mono_class_has_failure (klass)) {
2018 mono_domain_unlock (domain);
2019 mono_loader_unlock ();
2020 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2024 vtable_slots = klass->vtable_size;
2025 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2026 class_size = mono_class_data_size (klass);
2030 if (klass->interface_offsets_count) {
2031 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2032 mono_stats.imt_number_of_tables++;
2033 mono_stats.imt_tables_size += imt_table_bytes;
2035 imt_table_bytes = 0;
2038 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2040 mono_stats.used_class_count++;
2041 mono_stats.class_vtable_size += vtable_size;
2043 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2044 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2045 g_assert (!((gsize)vt & 7));
2048 vt->rank = klass->rank;
2049 vt->domain = domain;
2051 mono_class_compute_gc_descriptor (klass);
2053 * We can't use typed allocation in the non-root domains, since the
2054 * collector needs the GC descriptor stored in the vtable even after
2055 * the mempool containing the vtable is destroyed when the domain is
2056 * unloaded. An alternative might be to allocate vtables in the GC
2057 * heap, but this does not seem to work (it leads to crashes inside
2058 * libgc). If that approach is tried, two gc descriptors need to be
2059 * allocated for each class: one for the root domain, and one for all
2060 * other domains. The second descriptor should contain a bit for the
2061 * vtable field in MonoObject, since we can no longer assume the
2062 * vtable is reachable by other roots after the appdomain is unloaded.
2064 #ifdef HAVE_BOEHM_GC
2065 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2066 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2069 vt->gc_descr = klass->gc_descr;
2071 gc_bits = mono_gc_get_vtable_bits (klass);
2072 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2074 vt->gc_bits = gc_bits;
2077 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2078 if (klass->has_static_refs) {
2079 MonoGCDescriptor statics_gc_descr;
2081 gsize default_bitmap [4] = {0};
2084 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2085 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2086 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2087 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2088 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2089 if (bitmap != default_bitmap)
2092 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2094 vt->has_static_fields = TRUE;
2095 mono_stats.class_static_data_size += class_size;
2099 while ((field = mono_class_get_fields (klass, &iter))) {
2100 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2102 if (mono_field_is_deleted (field))
2104 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2105 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2106 if (special_static != SPECIAL_STATIC_NONE) {
2107 guint32 size, offset;
2109 gsize default_bitmap [4] = {0};
2114 if (mono_type_is_reference (field->type)) {
2115 default_bitmap [0] = 1;
2117 bitmap = default_bitmap;
2118 } else if (mono_type_is_struct (field->type)) {
2119 fclass = mono_class_from_mono_type (field->type);
2120 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2121 numbits = max_set + 1;
2123 default_bitmap [0] = 0;
2125 bitmap = default_bitmap;
2127 size = mono_type_size (field->type, &align);
2128 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2129 if (!domain->special_static_fields)
2130 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2131 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2132 if (bitmap != default_bitmap)
2135 * This marks the field as special static to speed up the
2136 * checks in mono_field_static_get/set_value ().
2142 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2143 MonoClass *fklass = mono_class_from_mono_type (field->type);
2144 const char *data = mono_field_get_data (field);
2146 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2147 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2148 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2151 if (fklass->valuetype) {
2152 memcpy (t, data, mono_class_value_size (fklass, NULL));
2154 /* it's a pointer type: add check */
2155 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2162 vt->max_interface_id = klass->max_interface_id;
2163 vt->interface_bitmap = klass->interface_bitmap;
2165 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2166 // class->name, klass->interface_offsets_count);
2168 /* Initialize vtable */
2169 if (callbacks.get_vtable_trampoline) {
2170 // This also covers the AOT case
2171 for (i = 0; i < klass->vtable_size; ++i) {
2172 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2175 mono_class_setup_vtable (klass);
2177 for (i = 0; i < klass->vtable_size; ++i) {
2180 cm = klass->vtable [i];
2182 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2183 if (!is_ok (error)) {
2184 mono_domain_unlock (domain);
2185 mono_loader_unlock ();
2192 if (imt_table_bytes) {
2193 /* Now that the vtable is full, we can actually fill up the IMT */
2194 for (i = 0; i < MONO_IMT_SIZE; ++i)
2195 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2199 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2200 * re-acquire them and check if another thread has created the vtable in the meantime.
2202 /* Special case System.MonoType to avoid infinite recursion */
2203 if (klass != mono_defaults.monotype_class) {
2204 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2205 if (!is_ok (error)) {
2206 mono_domain_unlock (domain);
2207 mono_loader_unlock ();
2211 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2212 /* This is unregistered in
2213 unregister_vtable_reflection_type() in
2215 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2218 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2220 /* class_vtable_array keeps an array of created vtables
2222 g_ptr_array_add (domain->class_vtable_array, vt);
2223 /* klass->runtime_info is protected by the loader lock, both when
2224 * it it enlarged and when it is stored info.
2228 * Store the vtable in klass->runtime_info.
2229 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2231 mono_memory_barrier ();
2233 old_info = klass->runtime_info;
2234 if (old_info && old_info->max_domain >= domain->domain_id) {
2235 /* someone already created a large enough runtime info */
2236 old_info->domain_vtables [domain->domain_id] = vt;
2238 int new_size = domain->domain_id;
2240 new_size = MAX (new_size, old_info->max_domain);
2242 /* make the new size a power of two */
2244 while (new_size > i)
2247 /* this is a bounded memory retention issue: may want to
2248 * handle it differently when we'll have a rcu-like system.
2250 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2251 runtime_info->max_domain = new_size - 1;
2252 /* copy the stuff from the older info */
2254 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2256 runtime_info->domain_vtables [domain->domain_id] = vt;
2258 mono_memory_barrier ();
2259 klass->runtime_info = runtime_info;
2262 if (klass == mono_defaults.monotype_class) {
2263 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2264 if (!is_ok (error)) {
2265 mono_domain_unlock (domain);
2266 mono_loader_unlock ();
2270 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2271 /* This is unregistered in
2272 unregister_vtable_reflection_type() in
2274 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2277 mono_domain_unlock (domain);
2278 mono_loader_unlock ();
2280 /* make sure the parent is initialized */
2281 /*FIXME shouldn't this fail the current type?*/
2283 mono_class_vtable_full (domain, klass->parent, error);
2288 #ifndef DISABLE_REMOTING
2290 * mono_class_proxy_vtable:
2291 * @domain: the application domain
2292 * @remove_class: the remote class
2294 * Creates a vtable for transparent proxies. It is basically
2295 * a copy of the real vtable of the class wrapped in @remote_class,
2296 * but all function pointers invoke the remoting functions, and
2297 * vtable->klass points to the transparent proxy class, and not to @class.
2300 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2302 MONO_REQ_GC_UNSAFE_MODE;
2305 MonoVTable *vt, *pvt;
2306 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2308 GSList *extra_interfaces = NULL;
2309 MonoClass *klass = remote_class->proxy_class;
2310 gpointer *interface_offsets;
2313 size_t imt_table_bytes;
2315 #ifdef COMPRESSED_INTERFACE_BITMAP
2319 vt = mono_class_vtable (domain, klass);
2320 g_assert (vt); /*FIXME property handle failure*/
2321 max_interface_id = vt->max_interface_id;
2323 /* Calculate vtable space for extra interfaces */
2324 for (j = 0; j < remote_class->interface_count; j++) {
2325 MonoClass* iclass = remote_class->interfaces[j];
2329 /*FIXME test for interfaces with variant generic arguments*/
2330 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2331 continue; /* interface implemented by the class */
2332 if (g_slist_find (extra_interfaces, iclass))
2335 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2337 method_count = mono_class_num_methods (iclass);
2339 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2340 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2342 for (i = 0; i < ifaces->len; ++i) {
2343 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2344 /*FIXME test for interfaces with variant generic arguments*/
2345 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2346 continue; /* interface implemented by the class */
2347 if (g_slist_find (extra_interfaces, ic))
2349 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2350 method_count += mono_class_num_methods (ic);
2352 g_ptr_array_free (ifaces, TRUE);
2355 extra_interface_vtsize += method_count * sizeof (gpointer);
2356 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2359 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2360 mono_stats.imt_number_of_tables++;
2361 mono_stats.imt_tables_size += imt_table_bytes;
2363 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2365 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2367 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2368 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2369 g_assert (!((gsize)pvt & 7));
2371 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2373 pvt->klass = mono_defaults.transparent_proxy_class;
2374 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2375 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2377 /* initialize vtable */
2378 mono_class_setup_vtable (klass);
2379 for (i = 0; i < klass->vtable_size; ++i) {
2382 if ((cm = klass->vtable [i]))
2383 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2385 pvt->vtable [i] = NULL;
2388 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2389 /* create trampolines for abstract methods */
2390 for (k = klass; k; k = k->parent) {
2392 gpointer iter = NULL;
2393 while ((m = mono_class_get_methods (k, &iter)))
2394 if (!pvt->vtable [m->slot])
2395 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2399 pvt->max_interface_id = max_interface_id;
2400 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2401 #ifdef COMPRESSED_INTERFACE_BITMAP
2402 bitmap = (uint8_t *)g_malloc0 (bsize);
2404 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2407 for (i = 0; i < klass->interface_offsets_count; ++i) {
2408 int interface_id = klass->interfaces_packed [i]->interface_id;
2409 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2412 if (extra_interfaces) {
2413 int slot = klass->vtable_size;
2419 /* Create trampolines for the methods of the interfaces */
2420 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2421 interf = (MonoClass *)list_item->data;
2423 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2427 while ((cm = mono_class_get_methods (interf, &iter)))
2428 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2430 slot += mono_class_num_methods (interf);
2434 /* Now that the vtable is full, we can actually fill up the IMT */
2435 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2436 if (extra_interfaces) {
2437 g_slist_free (extra_interfaces);
2440 #ifdef COMPRESSED_INTERFACE_BITMAP
2441 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2442 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2443 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2446 pvt->interface_bitmap = bitmap;
2451 #endif /* DISABLE_REMOTING */
2454 * mono_class_field_is_special_static:
2456 * Returns whether @field is a thread/context static field.
2459 mono_class_field_is_special_static (MonoClassField *field)
2461 MONO_REQ_GC_NEUTRAL_MODE
2463 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2465 if (mono_field_is_deleted (field))
2467 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2468 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2475 * mono_class_field_get_special_static_type:
2476 * @field: The MonoClassField describing the field.
2478 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2479 * SPECIAL_STATIC_NONE otherwise.
2482 mono_class_field_get_special_static_type (MonoClassField *field)
2484 MONO_REQ_GC_NEUTRAL_MODE
2486 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2487 return SPECIAL_STATIC_NONE;
2488 if (mono_field_is_deleted (field))
2489 return SPECIAL_STATIC_NONE;
2490 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2491 return field_is_special_static (field->parent, field);
2492 return SPECIAL_STATIC_NONE;
2496 * mono_class_has_special_static_fields:
2498 * Returns whenever @klass has any thread/context static fields.
2501 mono_class_has_special_static_fields (MonoClass *klass)
2503 MONO_REQ_GC_NEUTRAL_MODE
2505 MonoClassField *field;
2509 while ((field = mono_class_get_fields (klass, &iter))) {
2510 g_assert (field->parent == klass);
2511 if (mono_class_field_is_special_static (field))
2518 #ifndef DISABLE_REMOTING
2520 * create_remote_class_key:
2521 * Creates an array of pointers that can be used as a hash key for a remote class.
2522 * The first element of the array is the number of pointers.
2525 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2527 MONO_REQ_GC_NEUTRAL_MODE;
2532 if (remote_class == NULL) {
2533 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2534 key = (void **)g_malloc (sizeof(gpointer) * 3);
2535 key [0] = GINT_TO_POINTER (2);
2536 key [1] = mono_defaults.marshalbyrefobject_class;
2537 key [2] = extra_class;
2539 key = (void **)g_malloc (sizeof(gpointer) * 2);
2540 key [0] = GINT_TO_POINTER (1);
2541 key [1] = extra_class;
2544 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2545 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2546 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2547 key [1] = remote_class->proxy_class;
2549 // Keep the list of interfaces sorted
2550 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2551 if (extra_class && remote_class->interfaces [i] > extra_class) {
2552 key [j++] = extra_class;
2555 key [j] = remote_class->interfaces [i];
2558 key [j] = extra_class;
2560 // Replace the old class. The interface list is the same
2561 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2562 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2563 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2564 for (i = 0; i < remote_class->interface_count; i++)
2565 key [2 + i] = remote_class->interfaces [i];
2573 * copy_remote_class_key:
2575 * Make a copy of KEY in the domain and return the copy.
2578 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2580 MONO_REQ_GC_NEUTRAL_MODE
2582 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2583 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2585 memcpy (mp_key, key, key_size);
2591 * mono_remote_class:
2592 * @domain: the application domain
2593 * @class_name: name of the remote class
2594 * @error: set on error
2596 * Creates and initializes a MonoRemoteClass object for a remote type.
2598 * On failure returns NULL and sets @error
2601 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2603 MONO_REQ_GC_UNSAFE_MODE;
2605 MonoRemoteClass *rc;
2606 gpointer* key, *mp_key;
2609 mono_error_init (error);
2611 key = create_remote_class_key (NULL, proxy_class);
2613 mono_domain_lock (domain);
2614 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2618 mono_domain_unlock (domain);
2622 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2623 if (!is_ok (error)) {
2625 mono_domain_unlock (domain);
2629 mp_key = copy_remote_class_key (domain, key);
2633 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2634 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2635 rc->interface_count = 1;
2636 rc->interfaces [0] = proxy_class;
2637 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2639 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2640 rc->interface_count = 0;
2641 rc->proxy_class = proxy_class;
2644 rc->default_vtable = NULL;
2645 rc->xdomain_vtable = NULL;
2646 rc->proxy_class_name = name;
2647 #ifndef DISABLE_PERFCOUNTERS
2648 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2651 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2653 mono_domain_unlock (domain);
2658 * clone_remote_class:
2659 * Creates a copy of the remote_class, adding the provided class or interface
2661 static MonoRemoteClass*
2662 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2664 MONO_REQ_GC_NEUTRAL_MODE;
2666 MonoRemoteClass *rc;
2667 gpointer* key, *mp_key;
2669 key = create_remote_class_key (remote_class, extra_class);
2670 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2676 mp_key = copy_remote_class_key (domain, key);
2680 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2682 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2683 rc->proxy_class = remote_class->proxy_class;
2684 rc->interface_count = remote_class->interface_count + 1;
2686 // Keep the list of interfaces sorted, since the hash key of
2687 // the remote class depends on this
2688 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2689 if (remote_class->interfaces [i] > extra_class && i == j)
2690 rc->interfaces [j++] = extra_class;
2691 rc->interfaces [j] = remote_class->interfaces [i];
2694 rc->interfaces [j] = extra_class;
2696 // Replace the old class. The interface array is the same
2697 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2698 rc->proxy_class = extra_class;
2699 rc->interface_count = remote_class->interface_count;
2700 if (rc->interface_count > 0)
2701 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2704 rc->default_vtable = NULL;
2705 rc->xdomain_vtable = NULL;
2706 rc->proxy_class_name = remote_class->proxy_class_name;
2708 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2714 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2716 MONO_REQ_GC_UNSAFE_MODE;
2718 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2719 mono_domain_lock (domain);
2720 if (rp->target_domain_id != -1) {
2721 if (remote_class->xdomain_vtable == NULL)
2722 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2723 mono_domain_unlock (domain);
2724 mono_loader_unlock ();
2725 return remote_class->xdomain_vtable;
2727 if (remote_class->default_vtable == NULL) {
2730 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2731 klass = mono_class_from_mono_type (type);
2733 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)))
2734 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2737 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2740 mono_domain_unlock (domain);
2741 mono_loader_unlock ();
2742 return remote_class->default_vtable;
2746 * mono_upgrade_remote_class:
2747 * @domain: the application domain
2748 * @tproxy: the proxy whose remote class has to be upgraded.
2749 * @klass: class to which the remote class can be casted.
2751 * Updates the vtable of the remote class by adding the necessary method slots
2752 * and interface offsets so it can be safely casted to klass. klass can be a
2753 * class or an interface.
2756 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2758 MONO_REQ_GC_UNSAFE_MODE;
2760 MonoTransparentProxy *tproxy;
2761 MonoRemoteClass *remote_class;
2762 gboolean redo_vtable;
2764 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2765 mono_domain_lock (domain);
2767 tproxy = (MonoTransparentProxy*) proxy_object;
2768 remote_class = tproxy->remote_class;
2770 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2773 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2774 if (remote_class->interfaces [i] == klass)
2775 redo_vtable = FALSE;
2778 redo_vtable = (remote_class->proxy_class != klass);
2782 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2783 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2786 mono_domain_unlock (domain);
2787 mono_loader_unlock ();
2789 #endif /* DISABLE_REMOTING */
2793 * mono_object_get_virtual_method:
2794 * @obj: object to operate on.
2797 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2798 * the instance of a callvirt of method.
2801 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2803 MONO_REQ_GC_UNSAFE_MODE;
2806 MonoMethod **vtable;
2807 gboolean is_proxy = FALSE;
2808 MonoMethod *res = NULL;
2810 klass = mono_object_class (obj);
2811 #ifndef DISABLE_REMOTING
2812 if (klass == mono_defaults.transparent_proxy_class) {
2813 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2818 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2821 mono_class_setup_vtable (klass);
2822 vtable = klass->vtable;
2824 if (method->slot == -1) {
2825 /* method->slot might not be set for instances of generic methods */
2826 if (method->is_inflated) {
2827 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2828 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2831 g_assert_not_reached ();
2835 /* check method->slot is a valid index: perform isinstance? */
2836 if (method->slot != -1) {
2837 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2839 gboolean variance_used = FALSE;
2840 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2841 g_assert (iface_offset > 0);
2842 res = vtable [iface_offset + method->slot];
2845 res = vtable [method->slot];
2849 #ifndef DISABLE_REMOTING
2851 /* It may be an interface, abstract class method or generic method */
2852 if (!res || mono_method_signature (res)->generic_param_count)
2855 /* generic methods demand invoke_with_check */
2856 if (mono_method_signature (res)->generic_param_count)
2857 res = mono_marshal_get_remoting_invoke_with_check (res);
2860 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2861 res = mono_cominterop_get_invoke (res);
2864 res = mono_marshal_get_remoting_invoke (res);
2869 if (method->is_inflated) {
2871 /* Have to inflate the result */
2872 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2873 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2883 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2885 MONO_REQ_GC_UNSAFE_MODE;
2887 MonoObject *result = NULL;
2889 g_assert (callbacks.runtime_invoke);
2891 mono_error_init (error);
2893 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2894 mono_profiler_method_start_invoke (method);
2896 MONO_PREPARE_RESET_BLOCKING;
2898 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2900 MONO_FINISH_RESET_BLOCKING;
2902 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2903 mono_profiler_method_end_invoke (method);
2905 if (!mono_error_ok (error))
2912 * mono_runtime_invoke:
2913 * @method: method to invoke
2914 * @obJ: object instance
2915 * @params: arguments to the method
2916 * @exc: exception information.
2918 * Invokes the method represented by @method on the object @obj.
2920 * obj is the 'this' pointer, it should be NULL for static
2921 * methods, a MonoObject* for object instances and a pointer to
2922 * the value type for value types.
2924 * The params array contains the arguments to the method with the
2925 * same convention: MonoObject* pointers for object instances and
2926 * pointers to the value type otherwise.
2928 * From unmanaged code you'll usually use the
2929 * mono_runtime_invoke() variant.
2931 * Note that this function doesn't handle virtual methods for
2932 * you, it will exec the exact method you pass: we still need to
2933 * expose a function to lookup the derived class implementation
2934 * of a virtual method (there are examples of this in the code,
2937 * You can pass NULL as the exc argument if you don't want to
2938 * catch exceptions, otherwise, *exc will be set to the exception
2939 * thrown, if any. if an exception is thrown, you can't use the
2940 * MonoObject* result from the function.
2942 * If the method returns a value type, it is boxed in an object
2946 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2951 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2952 if (*exc == NULL && !mono_error_ok(&error)) {
2953 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2955 mono_error_cleanup (&error);
2957 res = mono_runtime_invoke_checked (method, obj, params, &error);
2958 mono_error_raise_exception (&error);
2964 * mono_runtime_try_invoke:
2965 * @method: method to invoke
2966 * @obJ: object instance
2967 * @params: arguments to the method
2968 * @exc: exception information.
2969 * @error: set on error
2971 * Invokes the method represented by @method on the object @obj.
2973 * obj is the 'this' pointer, it should be NULL for static
2974 * methods, a MonoObject* for object instances and a pointer to
2975 * the value type for value types.
2977 * The params array contains the arguments to the method with the
2978 * same convention: MonoObject* pointers for object instances and
2979 * pointers to the value type otherwise.
2981 * From unmanaged code you'll usually use the
2982 * mono_runtime_invoke() variant.
2984 * Note that this function doesn't handle virtual methods for
2985 * you, it will exec the exact method you pass: we still need to
2986 * expose a function to lookup the derived class implementation
2987 * of a virtual method (there are examples of this in the code,
2990 * For this function, you must not pass NULL as the exc argument if
2991 * you don't want to catch exceptions, use
2992 * mono_runtime_invoke_checked(). If an exception is thrown, you
2993 * can't use the MonoObject* result from the function.
2995 * If this method cannot be invoked, @error will be set and @exc and
2996 * the return value must not be used.
2998 * If the method returns a value type, it is boxed in an object
3002 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3004 MONO_REQ_GC_UNSAFE_MODE;
3006 g_assert (exc != NULL);
3008 if (mono_runtime_get_no_exec ())
3009 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3011 return do_runtime_invoke (method, obj, params, exc, error);
3015 * mono_runtime_invoke_checked:
3016 * @method: method to invoke
3017 * @obJ: object instance
3018 * @params: arguments to the method
3019 * @error: set on error
3021 * Invokes the method represented by @method on the object @obj.
3023 * obj is the 'this' pointer, it should be NULL for static
3024 * methods, a MonoObject* for object instances and a pointer to
3025 * the value type for value types.
3027 * The params array contains the arguments to the method with the
3028 * same convention: MonoObject* pointers for object instances and
3029 * pointers to the value type otherwise.
3031 * From unmanaged code you'll usually use the
3032 * mono_runtime_invoke() variant.
3034 * Note that this function doesn't handle virtual methods for
3035 * you, it will exec the exact method you pass: we still need to
3036 * expose a function to lookup the derived class implementation
3037 * of a virtual method (there are examples of this in the code,
3040 * If an exception is thrown, you can't use the MonoObject* result
3041 * from the function.
3043 * If this method cannot be invoked, @error will be set. If the
3044 * method throws an exception (and we're in coop mode) the exception
3045 * will be set in @error.
3047 * If the method returns a value type, it is boxed in an object
3051 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3053 MONO_REQ_GC_UNSAFE_MODE;
3055 if (mono_runtime_get_no_exec ())
3056 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3058 return do_runtime_invoke (method, obj, params, NULL, error);
3062 * mono_method_get_unmanaged_thunk:
3063 * @method: method to generate a thunk for.
3065 * Returns an unmanaged->managed thunk that can be used to call
3066 * a managed method directly from C.
3068 * The thunk's C signature closely matches the managed signature:
3070 * C#: public bool Equals (object obj);
3071 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3072 * MonoObject*, MonoException**);
3074 * The 1st ("this") parameter must not be used with static methods:
3076 * C#: public static bool ReferenceEquals (object a, object b);
3077 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3080 * The last argument must be a non-null pointer of a MonoException* pointer.
3081 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3082 * exception has been thrown in managed code. Otherwise it will point
3083 * to the MonoException* caught by the thunk. In this case, the result of
3084 * the thunk is undefined:
3086 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3087 * MonoException *ex = NULL;
3088 * Equals func = mono_method_get_unmanaged_thunk (method);
3089 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3091 * // handle exception
3094 * The calling convention of the thunk matches the platform's default
3095 * convention. This means that under Windows, C declarations must
3096 * contain the __stdcall attribute:
3098 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3099 * MonoObject*, MonoException**);
3103 * Value type arguments and return values are treated as they were objects:
3105 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3106 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3108 * Arguments must be properly boxed upon trunk's invocation, while return
3109 * values must be unboxed.
3112 mono_method_get_unmanaged_thunk (MonoMethod *method)
3114 MONO_REQ_GC_NEUTRAL_MODE;
3115 MONO_REQ_API_ENTRYPOINT;
3119 MONO_PREPARE_RESET_BLOCKING;
3120 method = mono_marshal_get_thunk_invoke_wrapper (method);
3121 res = mono_compile_method (method);
3122 MONO_FINISH_RESET_BLOCKING;
3128 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3130 MONO_REQ_GC_UNSAFE_MODE;
3134 /* object fields cannot be byref, so we don't need a
3136 gpointer *p = (gpointer*)dest;
3143 case MONO_TYPE_BOOLEAN:
3145 case MONO_TYPE_U1: {
3146 guint8 *p = (guint8*)dest;
3147 *p = value ? *(guint8*)value : 0;
3152 case MONO_TYPE_CHAR: {
3153 guint16 *p = (guint16*)dest;
3154 *p = value ? *(guint16*)value : 0;
3157 #if SIZEOF_VOID_P == 4
3162 case MONO_TYPE_U4: {
3163 gint32 *p = (gint32*)dest;
3164 *p = value ? *(gint32*)value : 0;
3167 #if SIZEOF_VOID_P == 8
3172 case MONO_TYPE_U8: {
3173 gint64 *p = (gint64*)dest;
3174 *p = value ? *(gint64*)value : 0;
3177 case MONO_TYPE_R4: {
3178 float *p = (float*)dest;
3179 *p = value ? *(float*)value : 0;
3182 case MONO_TYPE_R8: {
3183 double *p = (double*)dest;
3184 *p = value ? *(double*)value : 0;
3187 case MONO_TYPE_STRING:
3188 case MONO_TYPE_SZARRAY:
3189 case MONO_TYPE_CLASS:
3190 case MONO_TYPE_OBJECT:
3191 case MONO_TYPE_ARRAY:
3192 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3194 case MONO_TYPE_FNPTR:
3195 case MONO_TYPE_PTR: {
3196 gpointer *p = (gpointer*)dest;
3197 *p = deref_pointer? *(gpointer*)value: value;
3200 case MONO_TYPE_VALUETYPE:
3201 /* note that 't' and 'type->type' can be different */
3202 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3203 t = mono_class_enum_basetype (type->data.klass)->type;
3206 MonoClass *klass = mono_class_from_mono_type (type);
3207 int size = mono_class_value_size (klass, NULL);
3209 mono_gc_bzero_atomic (dest, size);
3211 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3214 case MONO_TYPE_GENERICINST:
3215 t = type->data.generic_class->container_class->byval_arg.type;
3218 g_error ("got type %x", type->type);
3223 * mono_field_set_value:
3224 * @obj: Instance object
3225 * @field: MonoClassField describing the field to set
3226 * @value: The value to be set
3228 * Sets the value of the field described by @field in the object instance @obj
3229 * to the value passed in @value. This method should only be used for instance
3230 * fields. For static fields, use mono_field_static_set_value.
3232 * The value must be on the native format of the field type.
3235 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3237 MONO_REQ_GC_UNSAFE_MODE;
3241 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3243 dest = (char*)obj + field->offset;
3244 mono_copy_value (field->type, dest, value, FALSE);
3248 * mono_field_static_set_value:
3249 * @field: MonoClassField describing the field to set
3250 * @value: The value to be set
3252 * Sets the value of the static field described by @field
3253 * to the value passed in @value.
3255 * The value must be on the native format of the field type.
3258 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3260 MONO_REQ_GC_UNSAFE_MODE;
3264 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3265 /* you cant set a constant! */
3266 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3268 if (field->offset == -1) {
3269 /* Special static */
3272 mono_domain_lock (vt->domain);
3273 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3274 mono_domain_unlock (vt->domain);
3275 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3277 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3279 mono_copy_value (field->type, dest, value, FALSE);
3283 * mono_vtable_get_static_field_data:
3285 * Internal use function: return a pointer to the memory holding the static fields
3286 * for a class or NULL if there are no static fields.
3287 * This is exported only for use by the debugger.
3290 mono_vtable_get_static_field_data (MonoVTable *vt)
3292 MONO_REQ_GC_NEUTRAL_MODE
3294 if (!vt->has_static_fields)
3296 return vt->vtable [vt->klass->vtable_size];
3300 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3302 MONO_REQ_GC_UNSAFE_MODE;
3306 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3307 if (field->offset == -1) {
3308 /* Special static */
3311 mono_domain_lock (vt->domain);
3312 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3313 mono_domain_unlock (vt->domain);
3314 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3316 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3319 src = (guint8*)obj + field->offset;
3326 * mono_field_get_value:
3327 * @obj: Object instance
3328 * @field: MonoClassField describing the field to fetch information from
3329 * @value: pointer to the location where the value will be stored
3331 * Use this routine to get the value of the field @field in the object
3334 * The pointer provided by value must be of the field type, for reference
3335 * types this is a MonoObject*, for value types its the actual pointer to
3340 * mono_field_get_value (obj, int_field, &i);
3343 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3345 MONO_REQ_GC_UNSAFE_MODE;
3351 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3353 src = (char*)obj + field->offset;
3354 mono_copy_value (field->type, value, src, TRUE);
3358 * mono_field_get_value_object:
3359 * @domain: domain where the object will be created (if boxing)
3360 * @field: MonoClassField describing the field to fetch information from
3361 * @obj: The object instance for the field.
3363 * Returns: a new MonoObject with the value from the given field. If the
3364 * field represents a value type, the value is boxed.
3368 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3371 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3372 mono_error_assert_ok (&error);
3377 * mono_field_get_value_object_checked:
3378 * @domain: domain where the object will be created (if boxing)
3379 * @field: MonoClassField describing the field to fetch information from
3380 * @obj: The object instance for the field.
3381 * @error: Set on error.
3383 * Returns: a new MonoObject with the value from the given field. If the
3384 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3388 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3390 MONO_REQ_GC_UNSAFE_MODE;
3392 mono_error_init (error);
3396 MonoVTable *vtable = NULL;
3398 gboolean is_static = FALSE;
3399 gboolean is_ref = FALSE;
3400 gboolean is_literal = FALSE;
3401 gboolean is_ptr = FALSE;
3402 MonoType *type = mono_field_get_type_checked (field, error);
3404 return_val_if_nok (error, NULL);
3406 switch (type->type) {
3407 case MONO_TYPE_STRING:
3408 case MONO_TYPE_OBJECT:
3409 case MONO_TYPE_CLASS:
3410 case MONO_TYPE_ARRAY:
3411 case MONO_TYPE_SZARRAY:
3416 case MONO_TYPE_BOOLEAN:
3419 case MONO_TYPE_CHAR:
3428 case MONO_TYPE_VALUETYPE:
3429 is_ref = type->byref;
3431 case MONO_TYPE_GENERICINST:
3432 is_ref = !mono_type_generic_inst_is_valuetype (type);
3438 g_error ("type 0x%x not handled in "
3439 "mono_field_get_value_object", type->type);
3443 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3446 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3450 vtable = mono_class_vtable_full (domain, field->parent, error);
3451 return_val_if_nok (error, NULL);
3453 if (!vtable->initialized) {
3454 mono_runtime_class_init_full (vtable, error);
3455 return_val_if_nok (error, NULL);
3464 get_default_field_value (domain, field, &o);
3465 } else if (is_static) {
3466 mono_field_static_get_value (vtable, field, &o);
3468 mono_field_get_value (obj, field, &o);
3474 static MonoMethod *m;
3480 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3481 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3487 get_default_field_value (domain, field, v);
3488 } else if (is_static) {
3489 mono_field_static_get_value (vtable, field, v);
3491 mono_field_get_value (obj, field, v);
3494 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3495 args [0] = ptr ? *ptr : NULL;
3496 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3497 return_val_if_nok (error, NULL);
3499 o = mono_runtime_invoke_checked (m, NULL, args, error);
3500 return_val_if_nok (error, NULL);
3505 /* boxed value type */
3506 klass = mono_class_from_mono_type (type);
3508 if (mono_class_is_nullable (klass))
3509 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3511 o = mono_object_new_checked (domain, klass, error);
3512 return_val_if_nok (error, NULL);
3513 v = ((gchar *) o) + sizeof (MonoObject);
3516 get_default_field_value (domain, field, v);
3517 } else if (is_static) {
3518 mono_field_static_get_value (vtable, field, v);
3520 mono_field_get_value (obj, field, v);
3527 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3529 MONO_REQ_GC_UNSAFE_MODE;
3532 const char *p = blob;
3533 mono_metadata_decode_blob_size (p, &p);
3536 case MONO_TYPE_BOOLEAN:
3539 *(guint8 *) value = *p;
3541 case MONO_TYPE_CHAR:
3544 *(guint16*) value = read16 (p);
3548 *(guint32*) value = read32 (p);
3552 *(guint64*) value = read64 (p);
3555 readr4 (p, (float*) value);
3558 readr8 (p, (double*) value);
3560 case MONO_TYPE_STRING:
3561 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3563 case MONO_TYPE_CLASS:
3564 *(gpointer*) value = NULL;
3568 g_warning ("type 0x%02x should not be in constant table", type);
3574 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3576 MONO_REQ_GC_NEUTRAL_MODE;
3578 MonoTypeEnum def_type;
3581 data = mono_class_get_field_default_value (field, &def_type);
3582 mono_get_constant_value_from_blob (domain, def_type, data, value);
3586 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3588 MONO_REQ_GC_UNSAFE_MODE;
3592 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3594 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3595 get_default_field_value (vt->domain, field, value);
3599 if (field->offset == -1) {
3600 /* Special static */
3601 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3602 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3604 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3606 mono_copy_value (field->type, value, src, TRUE);
3610 * mono_field_static_get_value:
3611 * @vt: vtable to the object
3612 * @field: MonoClassField describing the field to fetch information from
3613 * @value: where the value is returned
3615 * Use this routine to get the value of the static field @field value.
3617 * The pointer provided by value must be of the field type, for reference
3618 * types this is a MonoObject*, for value types its the actual pointer to
3623 * mono_field_static_get_value (vt, int_field, &i);
3626 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3628 MONO_REQ_GC_NEUTRAL_MODE;
3630 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3634 * mono_property_set_value:
3635 * @prop: MonoProperty to set
3636 * @obj: instance object on which to act
3637 * @params: parameters to pass to the propery
3638 * @exc: optional exception
3640 * Invokes the property's set method with the given arguments on the
3641 * object instance obj (or NULL for static properties).
3643 * You can pass NULL as the exc argument if you don't want to
3644 * catch exceptions, otherwise, *exc will be set to the exception
3645 * thrown, if any. if an exception is thrown, you can't use the
3646 * MonoObject* result from the function.
3649 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3651 MONO_REQ_GC_UNSAFE_MODE;
3654 do_runtime_invoke (prop->set, obj, params, exc, &error);
3655 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3656 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3658 mono_error_raise_exception (&error); /* FIXME don't raise here */
3663 * mono_property_get_value:
3664 * @prop: MonoProperty to fetch
3665 * @obj: instance object on which to act
3666 * @params: parameters to pass to the propery
3667 * @exc: optional exception
3669 * Invokes the property's get method with the given arguments on the
3670 * object instance obj (or NULL for static properties).
3672 * You can pass NULL as the exc argument if you don't want to
3673 * catch exceptions, otherwise, *exc will be set to the exception
3674 * thrown, if any. if an exception is thrown, you can't use the
3675 * MonoObject* result from the function.
3677 * Returns: the value from invoking the get method on the property.
3680 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3682 MONO_REQ_GC_UNSAFE_MODE;
3685 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3686 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3687 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3689 mono_error_raise_exception (&error); /* FIXME don't raise here */
3696 * mono_nullable_init:
3697 * @buf: The nullable structure to initialize.
3698 * @value: the value to initialize from
3699 * @klass: the type for the object
3701 * Initialize the nullable structure pointed to by @buf from @value which
3702 * should be a boxed value type. The size of @buf should be able to hold
3703 * as much data as the @klass->instance_size (which is the number of bytes
3704 * that will be copies).
3706 * Since Nullables have variable structure, we can not define a C
3707 * structure for them.
3710 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3712 MONO_REQ_GC_UNSAFE_MODE;
3714 MonoClass *param_class = klass->cast_class;
3716 mono_class_setup_fields_locking (klass);
3717 g_assert (klass->fields_inited);
3719 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3720 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3722 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3724 if (param_class->has_references)
3725 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3727 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3729 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3734 * mono_nullable_box:
3735 * @buf: The buffer representing the data to be boxed
3736 * @klass: the type to box it as.
3737 * @error: set on oerr
3739 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3740 * @buf. On failure returns NULL and sets @error
3743 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3745 MONO_REQ_GC_UNSAFE_MODE;
3747 mono_error_init (error);
3748 MonoClass *param_class = klass->cast_class;
3750 mono_class_setup_fields_locking (klass);
3751 g_assert (klass->fields_inited);
3753 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3754 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3756 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3757 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3758 return_val_if_nok (error, NULL);
3759 if (param_class->has_references)
3760 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3762 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3770 * mono_get_delegate_invoke:
3771 * @klass: The delegate class
3773 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3776 mono_get_delegate_invoke (MonoClass *klass)
3778 MONO_REQ_GC_NEUTRAL_MODE;
3782 /* This is called at runtime, so avoid the slower search in metadata */
3783 mono_class_setup_methods (klass);
3784 if (mono_class_has_failure (klass))
3786 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3791 * mono_get_delegate_begin_invoke:
3792 * @klass: The delegate class
3794 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3797 mono_get_delegate_begin_invoke (MonoClass *klass)
3799 MONO_REQ_GC_NEUTRAL_MODE;
3803 /* This is called at runtime, so avoid the slower search in metadata */
3804 mono_class_setup_methods (klass);
3805 if (mono_class_has_failure (klass))
3807 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3812 * mono_get_delegate_end_invoke:
3813 * @klass: The delegate class
3815 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3818 mono_get_delegate_end_invoke (MonoClass *klass)
3820 MONO_REQ_GC_NEUTRAL_MODE;
3824 /* This is called at runtime, so avoid the slower search in metadata */
3825 mono_class_setup_methods (klass);
3826 if (mono_class_has_failure (klass))
3828 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3833 * mono_runtime_delegate_invoke:
3834 * @delegate: pointer to a delegate object.
3835 * @params: parameters for the delegate.
3836 * @exc: Pointer to the exception result.
3838 * Invokes the delegate method @delegate with the parameters provided.
3840 * You can pass NULL as the exc argument if you don't want to
3841 * catch exceptions, otherwise, *exc will be set to the exception
3842 * thrown, if any. if an exception is thrown, you can't use the
3843 * MonoObject* result from the function.
3846 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3848 MONO_REQ_GC_UNSAFE_MODE;
3852 MonoClass *klass = delegate->vtable->klass;
3855 im = mono_get_delegate_invoke (klass);
3857 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3860 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3861 if (*exc == NULL && !mono_error_ok (&error))
3862 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3864 mono_error_cleanup (&error);
3866 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3867 mono_error_raise_exception (&error); /* FIXME don't raise here */
3873 static char **main_args = NULL;
3874 static int num_main_args = 0;
3877 * mono_runtime_get_main_args:
3879 * Returns: a MonoArray with the arguments passed to the main program
3882 mono_runtime_get_main_args (void)
3884 MONO_REQ_GC_UNSAFE_MODE;
3888 MonoDomain *domain = mono_domain_get ();
3890 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3892 for (i = 0; i < num_main_args; ++i)
3893 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3899 free_main_args (void)
3901 MONO_REQ_GC_NEUTRAL_MODE;
3905 for (i = 0; i < num_main_args; ++i)
3906 g_free (main_args [i]);
3913 * mono_runtime_set_main_args:
3914 * @argc: number of arguments from the command line
3915 * @argv: array of strings from the command line
3917 * Set the command line arguments from an embedding application that doesn't otherwise call
3918 * mono_runtime_run_main ().
3921 mono_runtime_set_main_args (int argc, char* argv[])
3923 MONO_REQ_GC_NEUTRAL_MODE;
3928 main_args = g_new0 (char*, argc);
3929 num_main_args = argc;
3931 for (i = 0; i < argc; ++i) {
3934 utf8_arg = mono_utf8_from_external (argv[i]);
3935 if (utf8_arg == NULL) {
3936 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3937 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3941 main_args [i] = utf8_arg;
3948 * mono_runtime_run_main:
3949 * @method: the method to start the application with (usually Main)
3950 * @argc: number of arguments from the command line
3951 * @argv: array of strings from the command line
3952 * @exc: excetption results
3954 * Execute a standard Main() method (argc/argv contains the
3955 * executable name). This method also sets the command line argument value
3956 * needed by System.Environment.
3961 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3964 MONO_REQ_GC_UNSAFE_MODE;
3967 MonoArray *args = NULL;
3968 MonoDomain *domain = mono_domain_get ();
3969 gchar *utf8_fullpath;
3970 MonoMethodSignature *sig;
3972 g_assert (method != NULL);
3974 mono_thread_set_main (mono_thread_current ());
3976 main_args = g_new0 (char*, argc);
3977 num_main_args = argc;
3979 if (!g_path_is_absolute (argv [0])) {
3980 gchar *basename = g_path_get_basename (argv [0]);
3981 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3985 utf8_fullpath = mono_utf8_from_external (fullpath);
3986 if(utf8_fullpath == NULL) {
3987 /* Printing the arg text will cause glib to
3988 * whinge about "Invalid UTF-8", but at least
3989 * its relevant, and shows the problem text
3992 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3993 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4000 utf8_fullpath = mono_utf8_from_external (argv[0]);
4001 if(utf8_fullpath == NULL) {
4002 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4003 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4008 main_args [0] = utf8_fullpath;
4010 for (i = 1; i < argc; ++i) {
4013 utf8_arg=mono_utf8_from_external (argv[i]);
4014 if(utf8_arg==NULL) {
4015 /* Ditto the comment about Invalid UTF-8 here */
4016 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4017 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4021 main_args [i] = utf8_arg;
4026 sig = mono_method_signature (method);
4028 g_print ("Unable to load Main method.\n");
4032 if (sig->param_count) {
4033 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
4034 for (i = 0; i < argc; ++i) {
4035 /* The encodings should all work, given that
4036 * we've checked all these args for the
4039 gchar *str = mono_utf8_from_external (argv [i]);
4040 MonoString *arg = mono_string_new (domain, str);
4041 mono_array_setref (args, i, arg);
4045 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4048 mono_assembly_set_main (method->klass->image->assembly);
4050 return mono_runtime_exec_main (method, args, exc);
4054 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4056 static MonoMethod *serialize_method;
4062 if (!serialize_method) {
4063 MonoClass *klass = mono_class_get_remoting_services_class ();
4064 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4067 if (!serialize_method) {
4072 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4077 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4078 if (*exc == NULL && !mono_error_ok (&error))
4079 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4081 mono_error_cleanup (&error);
4090 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4092 MONO_REQ_GC_UNSAFE_MODE;
4094 static MonoMethod *deserialize_method;
4100 if (!deserialize_method) {
4101 MonoClass *klass = mono_class_get_remoting_services_class ();
4102 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4104 if (!deserialize_method) {
4112 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4113 if (*exc == NULL && !mono_error_ok (&error))
4114 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4116 mono_error_cleanup (&error);
4124 #ifndef DISABLE_REMOTING
4126 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4128 MONO_REQ_GC_UNSAFE_MODE;
4130 static MonoMethod *get_proxy_method;
4133 MonoDomain *domain = mono_domain_get ();
4134 MonoRealProxy *real_proxy;
4135 MonoReflectionType *reflection_type;
4136 MonoTransparentProxy *transparent_proxy;
4138 if (!get_proxy_method)
4139 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4141 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4143 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4144 mono_error_raise_exception (&error); /* FIXME don't raise here */
4145 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4146 mono_error_raise_exception (&error); /* FIXME don't raise here */
4148 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4149 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4153 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4154 if (*exc == NULL && !mono_error_ok (&error))
4155 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4157 mono_error_cleanup (&error);
4161 return (MonoObject*) transparent_proxy;
4163 #endif /* DISABLE_REMOTING */
4166 * mono_object_xdomain_representation
4168 * @target_domain: a domain
4169 * @exc: pointer to a MonoObject*
4171 * Creates a representation of obj in the domain target_domain. This
4172 * is either a copy of obj arrived through via serialization and
4173 * deserialization or a proxy, depending on whether the object is
4174 * serializable or marshal by ref. obj must not be in target_domain.
4176 * If the object cannot be represented in target_domain, NULL is
4177 * returned and *exc is set to an appropriate exception.
4180 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4182 MONO_REQ_GC_UNSAFE_MODE;
4184 MonoObject *deserialized = NULL;
4185 gboolean failure = FALSE;
4187 g_assert (exc != NULL);
4190 #ifndef DISABLE_REMOTING
4191 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4192 deserialized = make_transparent_proxy (obj, &failure, exc);
4197 MonoDomain *domain = mono_domain_get ();
4198 MonoObject *serialized;
4200 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4201 serialized = serialize_object (obj, &failure, exc);
4202 mono_domain_set_internal_with_options (target_domain, FALSE);
4204 deserialized = deserialize_object (serialized, &failure, exc);
4205 if (domain != target_domain)
4206 mono_domain_set_internal_with_options (domain, FALSE);
4209 return deserialized;
4212 /* Used in call_unhandled_exception_delegate */
4214 create_unhandled_exception_eventargs (MonoObject *exc)
4216 MONO_REQ_GC_UNSAFE_MODE;
4221 MonoMethod *method = NULL;
4222 MonoBoolean is_terminating = TRUE;
4225 klass = mono_class_get_unhandled_exception_event_args_class ();
4226 mono_class_init (klass);
4228 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4229 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4233 args [1] = &is_terminating;
4235 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4236 mono_error_raise_exception (&error); /* FIXME don't raise here */
4238 mono_runtime_invoke_checked (method, obj, args, &error);
4239 mono_error_raise_exception (&error); /* FIXME don't raise here */
4244 /* Used in mono_unhandled_exception */
4246 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4247 MONO_REQ_GC_UNSAFE_MODE;
4249 MonoObject *e = NULL;
4251 MonoDomain *current_domain = mono_domain_get ();
4253 if (domain != current_domain)
4254 mono_domain_set_internal_with_options (domain, FALSE);
4256 g_assert (domain == mono_object_domain (domain->domain));
4258 if (mono_object_domain (exc) != domain) {
4259 MonoObject *serialization_exc;
4261 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4263 if (serialization_exc) {
4265 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4268 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4269 "System.Runtime.Serialization", "SerializationException",
4270 "Could not serialize unhandled exception.");
4274 g_assert (mono_object_domain (exc) == domain);
4276 pa [0] = domain->domain;
4277 pa [1] = create_unhandled_exception_eventargs (exc);
4278 mono_runtime_delegate_invoke (delegate, pa, &e);
4280 if (domain != current_domain)
4281 mono_domain_set_internal_with_options (current_domain, FALSE);
4285 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4286 if (!mono_error_ok (&error)) {
4287 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4288 mono_error_cleanup (&error);
4290 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4296 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4299 * mono_runtime_unhandled_exception_policy_set:
4300 * @policy: the new policy
4302 * This is a VM internal routine.
4304 * Sets the runtime policy for handling unhandled exceptions.
4307 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4308 runtime_unhandled_exception_policy = policy;
4312 * mono_runtime_unhandled_exception_policy_get:
4314 * This is a VM internal routine.
4316 * Gets the runtime policy for handling unhandled exceptions.
4318 MonoRuntimeUnhandledExceptionPolicy
4319 mono_runtime_unhandled_exception_policy_get (void) {
4320 return runtime_unhandled_exception_policy;
4324 * mono_unhandled_exception:
4325 * @exc: exception thrown
4327 * This is a VM internal routine.
4329 * We call this function when we detect an unhandled exception
4330 * in the default domain.
4332 * It invokes the * UnhandledException event in AppDomain or prints
4333 * a warning to the console
4336 mono_unhandled_exception (MonoObject *exc)
4338 MONO_REQ_GC_UNSAFE_MODE;
4341 MonoClassField *field;
4342 MonoDomain *current_domain, *root_domain;
4343 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4345 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4348 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4351 current_domain = mono_domain_get ();
4352 root_domain = mono_get_root_domain ();
4354 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4355 mono_error_raise_exception (&error); /* FIXME don't raise here */
4356 if (current_domain != root_domain) {
4357 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4358 mono_error_raise_exception (&error); /* FIXME don't raise here */
4361 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4362 mono_print_unhandled_exception (exc);
4364 if (root_appdomain_delegate)
4365 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4366 if (current_appdomain_delegate)
4367 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4370 /* set exitcode only if we will abort the process */
4371 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4372 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4374 mono_environment_exitcode_set (1);
4379 * mono_runtime_exec_managed_code:
4380 * @domain: Application domain
4381 * @main_func: function to invoke from the execution thread
4382 * @main_args: parameter to the main_func
4384 * Launch a new thread to execute a function
4386 * main_func is called back from the thread with main_args as the
4387 * parameter. The callback function is expected to start Main()
4388 * eventually. This function then waits for all managed threads to
4390 * It is not necesseray anymore to execute managed code in a subthread,
4391 * so this function should not be used anymore by default: just
4392 * execute the code and then call mono_thread_manage ().
4395 mono_runtime_exec_managed_code (MonoDomain *domain,
4396 MonoMainThreadFunc main_func,
4399 mono_thread_create (domain, main_func, main_args);
4401 mono_thread_manage ();
4405 * Execute a standard Main() method (args doesn't contain the
4409 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4411 MONO_REQ_GC_UNSAFE_MODE;
4417 MonoCustomAttrInfo* cinfo;
4418 gboolean has_stathread_attribute;
4419 MonoInternalThread* thread = mono_thread_internal_current ();
4425 domain = mono_object_domain (args);
4426 if (!domain->entry_assembly) {
4428 MonoAssembly *assembly;
4430 assembly = method->klass->image->assembly;
4431 domain->entry_assembly = assembly;
4432 /* Domains created from another domain already have application_base and configuration_file set */
4433 if (domain->setup->application_base == NULL) {
4434 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4437 if (domain->setup->configuration_file == NULL) {
4438 str = g_strconcat (assembly->image->name, ".config", NULL);
4439 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4441 mono_domain_set_options_from_config (domain);
4445 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4446 mono_error_cleanup (&error); /* FIXME warn here? */
4448 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4450 mono_custom_attrs_free (cinfo);
4452 has_stathread_attribute = FALSE;
4454 if (has_stathread_attribute) {
4455 thread->apartment_state = ThreadApartmentState_STA;
4457 thread->apartment_state = ThreadApartmentState_MTA;
4459 mono_thread_init_apartment_state ();
4461 /* FIXME: check signature of method */
4462 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4465 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4466 if (*exc == NULL && !mono_error_ok (&error))
4467 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4469 mono_error_cleanup (&error);
4471 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4472 mono_error_raise_exception (&error); /* FIXME don't raise here */
4476 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4480 mono_environment_exitcode_set (rval);
4483 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4484 if (*exc == NULL && !mono_error_ok (&error))
4485 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4487 mono_error_cleanup (&error);
4489 mono_runtime_invoke_checked (method, NULL, pa, &error);
4490 mono_error_raise_exception (&error); /* FIXME don't raise here */
4496 /* If the return type of Main is void, only
4497 * set the exitcode if an exception was thrown
4498 * (we don't want to blow away an
4499 * explicitly-set exit code)
4502 mono_environment_exitcode_set (rval);
4510 * mono_runtime_invoke_array:
4511 * @method: method to invoke
4512 * @obJ: object instance
4513 * @params: arguments to the method
4514 * @exc: exception information.
4516 * Invokes the method represented by @method on the object @obj.
4518 * obj is the 'this' pointer, it should be NULL for static
4519 * methods, a MonoObject* for object instances and a pointer to
4520 * the value type for value types.
4522 * The params array contains the arguments to the method with the
4523 * same convention: MonoObject* pointers for object instances and
4524 * pointers to the value type otherwise. The _invoke_array
4525 * variant takes a C# object[] as the params argument (MonoArray
4526 * *params): in this case the value types are boxed inside the
4527 * respective reference representation.
4529 * From unmanaged code you'll usually use the
4530 * mono_runtime_invoke_checked() variant.
4532 * Note that this function doesn't handle virtual methods for
4533 * you, it will exec the exact method you pass: we still need to
4534 * expose a function to lookup the derived class implementation
4535 * of a virtual method (there are examples of this in the code,
4538 * You can pass NULL as the exc argument if you don't want to
4539 * catch exceptions, otherwise, *exc will be set to the exception
4540 * thrown, if any. if an exception is thrown, you can't use the
4541 * MonoObject* result from the function.
4543 * If the method returns a value type, it is boxed in an object
4547 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4550 MONO_REQ_GC_UNSAFE_MODE;
4553 MonoMethodSignature *sig = mono_method_signature (method);
4554 gpointer *pa = NULL;
4557 gboolean has_byref_nullables = FALSE;
4559 if (NULL != params) {
4560 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4561 for (i = 0; i < mono_array_length (params); i++) {
4562 MonoType *t = sig->params [i];
4568 case MONO_TYPE_BOOLEAN:
4571 case MONO_TYPE_CHAR:
4580 case MONO_TYPE_VALUETYPE:
4581 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4582 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4583 pa [i] = mono_array_get (params, MonoObject*, i);
4585 has_byref_nullables = TRUE;
4587 /* MS seems to create the objects if a null is passed in */
4588 if (!mono_array_get (params, MonoObject*, i)) {
4589 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4590 mono_error_raise_exception (&error); /* FIXME don't raise here */
4591 mono_array_setref (params, i, o);
4596 * We can't pass the unboxed vtype byref to the callee, since
4597 * that would mean the callee would be able to modify boxed
4598 * primitive types. So we (and MS) make a copy of the boxed
4599 * object, pass that to the callee, and replace the original
4600 * boxed object in the arg array with the copy.
4602 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4603 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), &error);
4604 mono_error_raise_exception (&error); /* FIXME don't raise here */
4605 mono_array_setref (params, i, copy);
4608 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4611 case MONO_TYPE_STRING:
4612 case MONO_TYPE_OBJECT:
4613 case MONO_TYPE_CLASS:
4614 case MONO_TYPE_ARRAY:
4615 case MONO_TYPE_SZARRAY:
4617 pa [i] = mono_array_addr (params, MonoObject*, i);
4618 // FIXME: I need to check this code path
4620 pa [i] = mono_array_get (params, MonoObject*, i);
4622 case MONO_TYPE_GENERICINST:
4624 t = &t->data.generic_class->container_class->this_arg;
4626 t = &t->data.generic_class->container_class->byval_arg;
4628 case MONO_TYPE_PTR: {
4631 /* The argument should be an IntPtr */
4632 arg = mono_array_get (params, MonoObject*, i);
4636 g_assert (arg->vtable->klass == mono_defaults.int_class);
4637 pa [i] = ((MonoIntPtr*)arg)->m_value;
4642 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4647 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4650 if (mono_class_is_nullable (method->klass)) {
4651 /* Need to create a boxed vtype instead */
4657 MonoObject *result = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], &error);
4658 mono_error_raise_exception (&error); /* FIXME don't raise here */
4664 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4665 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4666 #ifndef DISABLE_REMOTING
4667 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4668 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4671 if (method->klass->valuetype)
4672 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4675 } else if (method->klass->valuetype) {
4676 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, &error);
4677 mono_error_raise_exception (&error); /* FIXME don't raise here */
4681 mono_runtime_try_invoke (method, o, pa, exc, &error);
4682 if (*exc == NULL && !mono_error_ok (&error))
4683 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4685 mono_error_cleanup (&error);
4687 mono_runtime_invoke_checked (method, o, pa, &error);
4688 mono_error_raise_exception (&error); /* FIXME don't raise here */
4691 return (MonoObject *)obj;
4693 if (mono_class_is_nullable (method->klass)) {
4694 MonoObject *nullable;
4696 /* Convert the unboxed vtype into a Nullable structure */
4697 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4698 mono_error_raise_exception (&error); /* FIXME don't raise here */
4700 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, &error);
4701 mono_error_raise_exception (&error); /* FIXME don't raise here */
4702 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
4703 obj = mono_object_unbox (nullable);
4706 /* obj must be already unboxed if needed */
4708 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4709 if (*exc == NULL && !mono_error_ok (&error))
4710 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4712 mono_error_cleanup (&error);
4714 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4715 mono_error_raise_exception (&error); /* FIXME don't raise here */
4718 if (sig->ret->type == MONO_TYPE_PTR) {
4719 MonoClass *pointer_class;
4720 static MonoMethod *box_method;
4722 MonoObject *box_exc;
4725 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4726 * convert it to a Pointer object.
4728 pointer_class = mono_class_get_pointer_class ();
4730 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4732 g_assert (res->vtable->klass == mono_defaults.int_class);
4733 box_args [0] = ((MonoIntPtr*)res)->m_value;
4734 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4735 mono_error_raise_exception (&error); /* FIXME don't raise here */
4737 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4738 g_assert (box_exc == NULL);
4739 mono_error_assert_ok (&error);
4742 if (has_byref_nullables) {
4744 * The runtime invoke wrapper already converted byref nullables back,
4745 * and stored them in pa, we just need to copy them back to the
4748 for (i = 0; i < mono_array_length (params); i++) {
4749 MonoType *t = sig->params [i];
4751 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4752 mono_array_setref (params, i, pa [i]);
4762 * @klass: the class of the object that we want to create
4764 * Returns: a newly created object whose definition is
4765 * looked up using @klass. This will not invoke any constructors,
4766 * so the consumer of this routine has to invoke any constructors on
4767 * its own to initialize the object.
4769 * It returns NULL on failure.
4772 mono_object_new (MonoDomain *domain, MonoClass *klass)
4774 MONO_REQ_GC_UNSAFE_MODE;
4778 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4780 mono_error_raise_exception (&error);
4785 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4787 MONO_REQ_GC_UNSAFE_MODE;
4791 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4793 mono_error_raise_exception (&error);
4798 * mono_object_new_checked:
4799 * @klass: the class of the object that we want to create
4800 * @error: set on error
4802 * Returns: a newly created object whose definition is
4803 * looked up using @klass. This will not invoke any constructors,
4804 * so the consumer of this routine has to invoke any constructors on
4805 * its own to initialize the object.
4807 * It returns NULL on failure and sets @error.
4810 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4812 MONO_REQ_GC_UNSAFE_MODE;
4816 vtable = mono_class_vtable (domain, klass);
4817 g_assert (vtable); /* FIXME don't swallow the error */
4819 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4824 * mono_object_new_pinned:
4826 * Same as mono_object_new, but the returned object will be pinned.
4827 * For SGEN, these objects will only be freed at appdomain unload.
4830 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4832 MONO_REQ_GC_UNSAFE_MODE;
4836 mono_error_init (error);
4838 vtable = mono_class_vtable (domain, klass);
4839 g_assert (vtable); /* FIXME don't swallow the error */
4841 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4843 if (G_UNLIKELY (!o))
4844 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4845 else if (G_UNLIKELY (vtable->klass->has_finalize))
4846 mono_object_register_finalizer (o, error);
4852 * mono_object_new_specific:
4853 * @vtable: the vtable of the object that we want to create
4855 * Returns: A newly created object with class and domain specified
4859 mono_object_new_specific (MonoVTable *vtable)
4862 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4863 mono_error_raise_exception (&error);
4869 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4871 MONO_REQ_GC_UNSAFE_MODE;
4875 mono_error_init (error);
4877 /* check for is_com_object for COM Interop */
4878 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4881 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4884 MonoClass *klass = mono_class_get_activation_services_class ();
4887 mono_class_init (klass);
4889 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4891 mono_error_set_not_supported (error, "Linked away.");
4894 vtable->domain->create_proxy_for_type_method = im;
4897 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4898 if (!mono_error_ok (error))
4901 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4902 if (!mono_error_ok (error))
4909 return mono_object_new_alloc_specific_checked (vtable, error);
4913 ves_icall_object_new_specific (MonoVTable *vtable)
4916 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4917 mono_error_raise_exception (&error);
4923 * mono_object_new_alloc_specific:
4924 * @vtable: virtual table for the object.
4926 * This function allocates a new `MonoObject` with the type derived
4927 * from the @vtable information. If the class of this object has a
4928 * finalizer, then the object will be tracked for finalization.
4930 * This method might raise an exception on errors. Use the
4931 * `mono_object_new_fast_checked` method if you want to manually raise
4934 * Returns: the allocated object.
4937 mono_object_new_alloc_specific (MonoVTable *vtable)
4940 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4941 mono_error_raise_exception (&error);
4947 * mono_object_new_alloc_specific_checked:
4948 * @vtable: virtual table for the object.
4949 * @error: holds the error return value.
4951 * This function allocates a new `MonoObject` with the type derived
4952 * from the @vtable information. If the class of this object has a
4953 * finalizer, then the object will be tracked for finalization.
4955 * If there is not enough memory, the @error parameter will be set
4956 * and will contain a user-visible message with the amount of bytes
4957 * that were requested.
4959 * Returns: the allocated object, or NULL if there is not enough memory
4963 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4965 MONO_REQ_GC_UNSAFE_MODE;
4969 mono_error_init (error);
4971 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4973 if (G_UNLIKELY (!o))
4974 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4975 else if (G_UNLIKELY (vtable->klass->has_finalize))
4976 mono_object_register_finalizer (o, error);
4982 * mono_object_new_fast:
4983 * @vtable: virtual table for the object.
4985 * This function allocates a new `MonoObject` with the type derived
4986 * from the @vtable information. The returned object is not tracked
4987 * for finalization. If your object implements a finalizer, you should
4988 * use `mono_object_new_alloc_specific` instead.
4990 * This method might raise an exception on errors. Use the
4991 * `mono_object_new_fast_checked` method if you want to manually raise
4994 * Returns: the allocated object.
4997 mono_object_new_fast (MonoVTable *vtable)
5000 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5001 mono_error_raise_exception (&error);
5007 * mono_object_new_fast_checked:
5008 * @vtable: virtual table for the object.
5009 * @error: holds the error return value.
5011 * This function allocates a new `MonoObject` with the type derived
5012 * from the @vtable information. The returned object is not tracked
5013 * for finalization. If your object implements a finalizer, you should
5014 * use `mono_object_new_alloc_specific_checked` instead.
5016 * If there is not enough memory, the @error parameter will be set
5017 * and will contain a user-visible message with the amount of bytes
5018 * that were requested.
5020 * Returns: the allocated object, or NULL if there is not enough memory
5024 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5026 MONO_REQ_GC_UNSAFE_MODE;
5030 mono_error_init (error);
5032 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5034 if (G_UNLIKELY (!o))
5035 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5041 ves_icall_object_new_fast (MonoVTable *vtable)
5044 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5045 mono_error_raise_exception (&error);
5051 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5053 MONO_REQ_GC_UNSAFE_MODE;
5057 mono_error_init (error);
5059 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5061 if (G_UNLIKELY (!o))
5062 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5063 else if (G_UNLIKELY (vtable->klass->has_finalize))
5064 mono_object_register_finalizer (o, error);
5070 * mono_class_get_allocation_ftn:
5072 * @for_box: the object will be used for boxing
5073 * @pass_size_in_words:
5075 * Return the allocation function appropriate for the given class.
5079 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5081 MONO_REQ_GC_NEUTRAL_MODE;
5083 *pass_size_in_words = FALSE;
5085 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5086 return ves_icall_object_new_specific;
5088 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5090 return ves_icall_object_new_fast;
5093 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5094 * of the overhead of parameter passing.
5097 *pass_size_in_words = TRUE;
5098 #ifdef GC_REDIRECT_TO_LOCAL
5099 return GC_local_gcj_fast_malloc;
5101 return GC_gcj_fast_malloc;
5106 return ves_icall_object_new_specific;
5110 * mono_object_new_from_token:
5111 * @image: Context where the type_token is hosted
5112 * @token: a token of the type that we want to create
5114 * Returns: A newly created object whose definition is
5115 * looked up using @token in the @image image
5118 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5120 MONO_REQ_GC_UNSAFE_MODE;
5126 klass = mono_class_get_checked (image, token, &error);
5127 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5129 result = mono_object_new_checked (domain, klass, &error);
5131 mono_error_raise_exception (&error); /* FIXME don't raise here */
5138 * mono_object_clone:
5139 * @obj: the object to clone
5141 * Returns: A newly created object who is a shallow copy of @obj
5144 mono_object_clone (MonoObject *obj)
5147 MonoObject *o = mono_object_clone_checked (obj, &error);
5148 mono_error_raise_exception (&error);
5154 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5156 MONO_REQ_GC_UNSAFE_MODE;
5161 mono_error_init (error);
5163 size = obj->vtable->klass->instance_size;
5165 if (obj->vtable->klass->rank)
5166 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5168 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5170 if (G_UNLIKELY (!o)) {
5171 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5175 /* If the object doesn't contain references this will do a simple memmove. */
5176 mono_gc_wbarrier_object_copy (o, obj);
5178 if (obj->vtable->klass->has_finalize)
5179 mono_object_register_finalizer (o, error);
5184 * mono_array_full_copy:
5185 * @src: source array to copy
5186 * @dest: destination array
5188 * Copies the content of one array to another with exactly the same type and size.
5191 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5193 MONO_REQ_GC_UNSAFE_MODE;
5196 MonoClass *klass = src->obj.vtable->klass;
5198 g_assert (klass == dest->obj.vtable->klass);
5200 size = mono_array_length (src);
5201 g_assert (size == mono_array_length (dest));
5202 size *= mono_array_element_size (klass);
5204 if (klass->element_class->valuetype) {
5205 if (klass->element_class->has_references)
5206 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5208 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5210 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5213 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5218 * mono_array_clone_in_domain:
5219 * @domain: the domain in which the array will be cloned into
5220 * @array: the array to clone
5222 * This routine returns a copy of the array that is hosted on the
5223 * specified MonoDomain.
5226 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5228 MONO_REQ_GC_UNSAFE_MODE;
5234 MonoClass *klass = array->obj.vtable->klass;
5236 if (array->bounds == NULL) {
5237 size = mono_array_length (array);
5238 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5239 mono_error_raise_exception (&error); /* FIXME don't raise here */
5241 size *= mono_array_element_size (klass);
5243 if (klass->element_class->valuetype) {
5244 if (klass->element_class->has_references)
5245 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5247 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5249 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5252 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5257 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5258 size = mono_array_element_size (klass);
5259 for (i = 0; i < klass->rank; ++i) {
5260 sizes [i] = array->bounds [i].length;
5261 size *= array->bounds [i].length;
5262 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5264 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5265 mono_error_raise_exception (&error); /* FIXME don't raise here */
5267 if (klass->element_class->valuetype) {
5268 if (klass->element_class->has_references)
5269 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5271 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5273 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5276 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5284 * @array: the array to clone
5286 * Returns: A newly created array who is a shallow copy of @array
5289 mono_array_clone (MonoArray *array)
5291 MONO_REQ_GC_UNSAFE_MODE;
5293 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5296 /* helper macros to check for overflow when calculating the size of arrays */
5297 #ifdef MONO_BIG_ARRAYS
5298 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5299 #define MYGUINT_MAX MYGUINT64_MAX
5300 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5301 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5302 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5303 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5304 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5306 #define MYGUINT32_MAX 4294967295U
5307 #define MYGUINT_MAX MYGUINT32_MAX
5308 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5309 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5310 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5311 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5312 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5316 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5318 MONO_REQ_GC_NEUTRAL_MODE;
5322 byte_len = mono_array_element_size (klass);
5323 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5326 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5328 byte_len += MONO_SIZEOF_MONO_ARRAY;
5336 * mono_array_new_full:
5337 * @domain: domain where the object is created
5338 * @array_class: array class
5339 * @lengths: lengths for each dimension in the array
5340 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5342 * This routine creates a new array objects with the given dimensions,
5343 * lower bounds and type.
5346 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5349 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5350 mono_error_raise_exception (&error);
5356 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5358 MONO_REQ_GC_UNSAFE_MODE;
5360 uintptr_t byte_len = 0, len, bounds_size;
5363 MonoArrayBounds *bounds;
5367 mono_error_init (error);
5369 if (!array_class->inited)
5370 mono_class_init (array_class);
5374 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5375 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5377 if (len > MONO_ARRAY_MAX_INDEX) {
5378 mono_error_set_generic_error (error, "System", "OverflowException", "");
5383 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5385 for (i = 0; i < array_class->rank; ++i) {
5386 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5387 mono_error_set_generic_error (error, "System", "OverflowException", "");
5390 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5391 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5398 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5399 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5405 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5406 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5409 byte_len = (byte_len + 3) & ~3;
5410 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5411 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5414 byte_len += bounds_size;
5417 * Following three lines almost taken from mono_object_new ():
5418 * they need to be kept in sync.
5420 vtable = mono_class_vtable_full (domain, array_class, error);
5421 return_val_if_nok (error, NULL);
5424 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5426 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5428 if (G_UNLIKELY (!o)) {
5429 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5433 array = (MonoArray*)o;
5435 bounds = array->bounds;
5438 for (i = 0; i < array_class->rank; ++i) {
5439 bounds [i].length = lengths [i];
5441 bounds [i].lower_bound = lower_bounds [i];
5450 * @domain: domain where the object is created
5451 * @eclass: element class
5452 * @n: number of array elements
5454 * This routine creates a new szarray with @n elements of type @eclass.
5457 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5459 MONO_REQ_GC_UNSAFE_MODE;
5465 ac = mono_array_class_get (eclass, 1);
5468 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5469 mono_error_raise_exception (&error); /* FIXME don't raise here */
5471 arr = mono_array_new_specific_checked (vtable, n, &error);
5472 mono_error_raise_exception (&error); /* FIXME don't raise here */
5478 * mono_array_new_specific:
5479 * @vtable: a vtable in the appropriate domain for an initialized class
5480 * @n: number of array elements
5482 * This routine is a fast alternative to mono_array_new() for code which
5483 * can be sure about the domain it operates in.
5486 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5489 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5490 mono_error_raise_exception (&error); /* FIXME don't raise here */
5496 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5498 MONO_REQ_GC_UNSAFE_MODE;
5503 mono_error_init (error);
5505 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5506 mono_error_set_generic_error (error, "System", "OverflowException", "");
5510 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5511 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5514 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5516 if (G_UNLIKELY (!o)) {
5517 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5521 return (MonoArray*)o;
5525 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5528 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5529 mono_error_raise_exception (&error);
5535 * mono_string_new_utf16:
5536 * @text: a pointer to an utf16 string
5537 * @len: the length of the string
5539 * Returns: A newly created string object which contains @text.
5542 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5544 MONO_REQ_GC_UNSAFE_MODE;
5547 MonoString *res = NULL;
5548 res = mono_string_new_utf16_checked (domain, text, len, &error);
5549 mono_error_raise_exception (&error);
5555 * mono_string_new_utf16_checked:
5556 * @text: a pointer to an utf16 string
5557 * @len: the length of the string
5558 * @error: written on error.
5560 * Returns: A newly created string object which contains @text.
5561 * On error, returns NULL and sets @error.
5564 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5566 MONO_REQ_GC_UNSAFE_MODE;
5570 mono_error_init (error);
5572 s = mono_string_new_size_checked (domain, len, error);
5574 memcpy (mono_string_chars (s), text, len * 2);
5580 * mono_string_new_utf32:
5581 * @text: a pointer to an utf32 string
5582 * @len: the length of the string
5584 * Returns: A newly created string object which contains @text.
5587 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5589 MONO_REQ_GC_UNSAFE_MODE;
5593 mono_unichar2 *utf16_output = NULL;
5594 gint32 utf16_len = 0;
5595 GError *gerror = NULL;
5596 glong items_written;
5598 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5601 g_error_free (gerror);
5603 while (utf16_output [utf16_len]) utf16_len++;
5605 s = mono_string_new_size_checked (domain, utf16_len, &error);
5606 mono_error_raise_exception (&error); /* FIXME don't raise here */
5608 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5610 g_free (utf16_output);
5616 * mono_string_new_size:
5617 * @text: a pointer to an utf16 string
5618 * @len: the length of the string
5620 * Returns: A newly created string object of @len
5623 mono_string_new_size (MonoDomain *domain, gint32 len)
5626 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5627 mono_error_raise_exception (&error);
5633 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5635 MONO_REQ_GC_UNSAFE_MODE;
5641 mono_error_init (error);
5643 /* check for overflow */
5644 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5645 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5649 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5650 g_assert (size > 0);
5652 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5655 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5657 if (G_UNLIKELY (!s)) {
5658 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5666 * mono_string_new_len:
5667 * @text: a pointer to an utf8 string
5668 * @length: number of bytes in @text to consider
5670 * Returns: A newly created string object which contains @text.
5673 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5675 MONO_REQ_GC_UNSAFE_MODE;
5678 GError *eg_error = NULL;
5679 MonoString *o = NULL;
5681 glong items_written;
5683 mono_error_init (&error);
5685 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5688 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5690 g_error_free (eg_error);
5694 mono_error_raise_exception (&error); /* FIXME don't raise here */
5700 * @text: a pointer to an utf8 string
5702 * Returns: A newly created string object which contains @text.
5704 * This function asserts if it cannot allocate a new string.
5706 * @deprecated Use mono_string_new_checked in new code.
5709 mono_string_new (MonoDomain *domain, const char *text)
5712 MonoString *res = NULL;
5713 res = mono_string_new_checked (domain, text, &error);
5714 mono_error_assert_ok (&error);
5719 * mono_string_new_checked:
5720 * @text: a pointer to an utf8 string
5721 * @merror: set on error
5723 * Returns: A newly created string object which contains @text.
5724 * On error returns NULL and sets @merror.
5727 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5729 MONO_REQ_GC_UNSAFE_MODE;
5731 GError *eg_error = NULL;
5732 MonoString *o = NULL;
5734 glong items_written;
5737 mono_error_init (error);
5741 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5744 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5746 g_error_free (eg_error);
5749 mono_error_raise_exception (error);
5751 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5756 MonoString *o = NULL;
5758 if (!g_utf8_validate (text, -1, &end)) {
5759 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5763 len = g_utf8_strlen (text, -1);
5764 o = mono_string_new_size_checked (domain, len, error);
5767 str = mono_string_chars (o);
5769 while (text < end) {
5770 *str++ = g_utf8_get_char (text);
5771 text = g_utf8_next_char (text);
5780 * mono_string_new_wrapper:
5781 * @text: pointer to utf8 characters.
5783 * Helper function to create a string object from @text in the current domain.
5786 mono_string_new_wrapper (const char *text)
5788 MONO_REQ_GC_UNSAFE_MODE;
5790 MonoDomain *domain = mono_domain_get ();
5793 return mono_string_new (domain, text);
5800 * @class: the class of the value
5801 * @value: a pointer to the unboxed data
5803 * Returns: A newly created object which contains @value.
5806 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5809 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
5810 mono_error_cleanup (&error);
5815 * mono_value_box_checked:
5816 * @domain: the domain of the new object
5817 * @class: the class of the value
5818 * @value: a pointer to the unboxed data
5819 * @error: set on error
5821 * Returns: A newly created object which contains @value. On failure
5822 * returns NULL and sets @error.
5825 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
5827 MONO_REQ_GC_UNSAFE_MODE;
5832 mono_error_init (error);
5834 g_assert (klass->valuetype);
5835 if (mono_class_is_nullable (klass))
5836 return mono_nullable_box ((guint8 *)value, klass, error);
5838 vtable = mono_class_vtable (domain, klass);
5841 size = mono_class_instance_size (klass);
5842 res = mono_object_new_alloc_specific_checked (vtable, error);
5843 return_val_if_nok (error, NULL);
5845 size = size - sizeof (MonoObject);
5848 g_assert (size == mono_class_value_size (klass, NULL));
5849 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5851 #if NO_UNALIGNED_ACCESS
5852 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5856 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5859 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5862 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5865 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5868 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5872 if (klass->has_finalize) {
5873 mono_object_register_finalizer (res, error);
5874 return_val_if_nok (error, NULL);
5881 * @dest: destination pointer
5882 * @src: source pointer
5883 * @klass: a valuetype class
5885 * Copy a valuetype from @src to @dest. This function must be used
5886 * when @klass contains references fields.
5889 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5891 MONO_REQ_GC_UNSAFE_MODE;
5893 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5897 * mono_value_copy_array:
5898 * @dest: destination array
5899 * @dest_idx: index in the @dest array
5900 * @src: source pointer
5901 * @count: number of items
5903 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5904 * This function must be used when @klass contains references fields.
5905 * Overlap is handled.
5908 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5910 MONO_REQ_GC_UNSAFE_MODE;
5912 int size = mono_array_element_size (dest->obj.vtable->klass);
5913 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5914 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5915 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5919 * mono_object_get_domain:
5920 * @obj: object to query
5922 * Returns: the MonoDomain where the object is hosted
5925 mono_object_get_domain (MonoObject *obj)
5927 MONO_REQ_GC_UNSAFE_MODE;
5929 return mono_object_domain (obj);
5933 * mono_object_get_class:
5934 * @obj: object to query
5936 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5938 * Returns: the MonoClass of the object.
5941 mono_object_get_class (MonoObject *obj)
5943 MONO_REQ_GC_UNSAFE_MODE;
5945 return mono_object_class (obj);
5948 * mono_object_get_size:
5949 * @o: object to query
5951 * Returns: the size, in bytes, of @o
5954 mono_object_get_size (MonoObject* o)
5956 MONO_REQ_GC_UNSAFE_MODE;
5958 MonoClass* klass = mono_object_class (o);
5959 if (klass == mono_defaults.string_class) {
5960 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5961 } else if (o->vtable->rank) {
5962 MonoArray *array = (MonoArray*)o;
5963 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5964 if (array->bounds) {
5967 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5971 return mono_class_instance_size (klass);
5976 * mono_object_unbox:
5977 * @obj: object to unbox
5979 * Returns: a pointer to the start of the valuetype boxed in this
5982 * This method will assert if the object passed is not a valuetype.
5985 mono_object_unbox (MonoObject *obj)
5987 MONO_REQ_GC_UNSAFE_MODE;
5989 /* add assert for valuetypes? */
5990 g_assert (obj->vtable->klass->valuetype);
5991 return ((char*)obj) + sizeof (MonoObject);
5995 * mono_object_isinst:
5997 * @klass: a pointer to a class
5999 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6002 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6004 MONO_REQ_GC_UNSAFE_MODE;
6007 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6008 mono_error_cleanup (&error);
6014 * mono_object_isinst_checked:
6016 * @klass: a pointer to a class
6017 * @error: set on error
6019 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6020 * On failure returns NULL and sets @error.
6023 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6025 MONO_REQ_GC_UNSAFE_MODE;
6027 mono_error_init (error);
6029 MonoObject *result = NULL;
6032 mono_class_init (klass);
6034 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6035 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6042 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6046 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6048 MONO_REQ_GC_UNSAFE_MODE;
6051 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6052 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6057 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6059 MONO_REQ_GC_UNSAFE_MODE;
6063 mono_error_init (error);
6070 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6071 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6075 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6076 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6079 MonoClass *oklass = vt->klass;
6080 if (mono_class_is_transparent_proxy (oklass))
6081 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6083 mono_class_setup_supertypes (klass);
6084 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6087 #ifndef DISABLE_REMOTING
6088 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6090 MonoDomain *domain = mono_domain_get ();
6092 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6093 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6094 MonoMethod *im = NULL;
6097 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6099 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6100 im = mono_object_get_virtual_method (rp, im);
6103 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6104 return_val_if_nok (error, NULL);
6107 res = mono_runtime_invoke_checked (im, rp, pa, error);
6108 return_val_if_nok (error, NULL);
6110 if (*(MonoBoolean *) mono_object_unbox(res)) {
6111 /* Update the vtable of the remote type, so it can safely cast to this new type */
6112 mono_upgrade_remote_class (domain, obj, klass);
6116 #endif /* DISABLE_REMOTING */
6121 * mono_object_castclass_mbyref:
6123 * @klass: a pointer to a class
6125 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6128 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6130 MONO_REQ_GC_UNSAFE_MODE;
6133 if (!obj) return NULL;
6134 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6135 mono_error_cleanup (&error);
6140 MonoDomain *orig_domain;
6146 str_lookup (MonoDomain *domain, gpointer user_data)
6148 MONO_REQ_GC_UNSAFE_MODE;
6150 LDStrInfo *info = (LDStrInfo *)user_data;
6151 if (info->res || domain == info->orig_domain)
6153 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6157 mono_string_get_pinned (MonoString *str, MonoError *error)
6159 MONO_REQ_GC_UNSAFE_MODE;
6161 mono_error_init (error);
6163 /* We only need to make a pinned version of a string if this is a moving GC */
6164 if (!mono_gc_is_moving ())
6168 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6169 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6171 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6172 news->length = mono_string_length (str);
6174 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6180 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6182 MONO_REQ_GC_UNSAFE_MODE;
6184 MonoGHashTable *ldstr_table;
6185 MonoString *s, *res;
6188 mono_error_init (error);
6190 domain = ((MonoObject *)str)->vtable->domain;
6191 ldstr_table = domain->ldstr_table;
6193 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6199 /* Allocate outside the lock */
6201 s = mono_string_get_pinned (str, error);
6202 return_val_if_nok (error, NULL);
6205 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6210 mono_g_hash_table_insert (ldstr_table, s, s);
6215 LDStrInfo ldstr_info;
6216 ldstr_info.orig_domain = domain;
6217 ldstr_info.ins = str;
6218 ldstr_info.res = NULL;
6220 mono_domain_foreach (str_lookup, &ldstr_info);
6221 if (ldstr_info.res) {
6223 * the string was already interned in some other domain:
6224 * intern it in the current one as well.
6226 mono_g_hash_table_insert (ldstr_table, str, str);
6236 * mono_string_is_interned:
6237 * @o: String to probe
6239 * Returns whether the string has been interned.
6242 mono_string_is_interned (MonoString *o)
6245 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6246 /* This function does not fail. */
6247 mono_error_assert_ok (&error);
6252 * mono_string_intern:
6253 * @o: String to intern
6255 * Interns the string passed.
6256 * Returns: The interned string.
6259 mono_string_intern (MonoString *str)
6262 MonoString *result = mono_string_intern_checked (str, &error);
6263 mono_error_assert_ok (&error);
6268 * mono_string_intern_checked:
6269 * @o: String to intern
6270 * @error: set on error.
6272 * Interns the string passed.
6273 * Returns: The interned string. On failure returns NULL and sets @error
6276 mono_string_intern_checked (MonoString *str, MonoError *error)
6278 MONO_REQ_GC_UNSAFE_MODE;
6280 mono_error_init (error);
6282 return mono_string_is_interned_lookup (str, TRUE, error);
6287 * @domain: the domain where the string will be used.
6288 * @image: a metadata context
6289 * @idx: index into the user string table.
6291 * Implementation for the ldstr opcode.
6292 * Returns: a loaded string from the @image/@idx combination.
6295 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6297 MONO_REQ_GC_UNSAFE_MODE;
6299 if (image->dynamic) {
6300 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6303 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6304 return NULL; /*FIXME we should probably be raising an exception here*/
6305 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6310 * mono_ldstr_metadata_sig
6311 * @domain: the domain for the string
6312 * @sig: the signature of a metadata string
6314 * Returns: a MonoString for a string stored in the metadata
6317 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6319 MONO_REQ_GC_UNSAFE_MODE;
6322 const char *str = sig;
6323 MonoString *o, *interned;
6326 len2 = mono_metadata_decode_blob_size (str, &str);
6329 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6330 mono_error_raise_exception (&error); /* FIXME don't raise here */
6331 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6334 guint16 *p2 = (guint16*)mono_string_chars (o);
6335 for (i = 0; i < len2; ++i) {
6336 *p2 = GUINT16_FROM_LE (*p2);
6342 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6345 return interned; /* o will get garbage collected */
6347 o = mono_string_get_pinned (o, &error);
6348 mono_error_raise_exception (&error); /* FIXME don't raise here */
6351 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6353 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6363 * mono_string_to_utf8:
6364 * @s: a System.String
6366 * Returns the UTF8 representation for @s.
6367 * The resulting buffer needs to be freed with mono_free().
6369 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6372 mono_string_to_utf8 (MonoString *s)
6374 MONO_REQ_GC_UNSAFE_MODE;
6377 char *result = mono_string_to_utf8_checked (s, &error);
6379 if (!mono_error_ok (&error))
6380 mono_error_raise_exception (&error);
6385 * mono_string_to_utf8_checked:
6386 * @s: a System.String
6387 * @error: a MonoError.
6389 * Converts a MonoString to its UTF8 representation. May fail; check
6390 * @error to determine whether the conversion was successful.
6391 * The resulting buffer should be freed with mono_free().
6394 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6396 MONO_REQ_GC_UNSAFE_MODE;
6400 GError *gerror = NULL;
6402 mono_error_init (error);
6408 return g_strdup ("");
6410 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6412 mono_error_set_argument (error, "string", "%s", gerror->message);
6413 g_error_free (gerror);
6416 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6417 if (s->length > written) {
6418 /* allocate the total length and copy the part of the string that has been converted */
6419 char *as2 = (char *)g_malloc0 (s->length);
6420 memcpy (as2, as, written);
6429 * mono_string_to_utf8_ignore:
6432 * Converts a MonoString to its UTF8 representation. Will ignore
6433 * invalid surrogate pairs.
6434 * The resulting buffer should be freed with mono_free().
6438 mono_string_to_utf8_ignore (MonoString *s)
6440 MONO_REQ_GC_UNSAFE_MODE;
6449 return g_strdup ("");
6451 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6453 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6454 if (s->length > written) {
6455 /* allocate the total length and copy the part of the string that has been converted */
6456 char *as2 = (char *)g_malloc0 (s->length);
6457 memcpy (as2, as, written);
6466 * mono_string_to_utf8_image_ignore:
6467 * @s: a System.String
6469 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6472 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6474 MONO_REQ_GC_UNSAFE_MODE;
6476 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6480 * mono_string_to_utf8_mp_ignore:
6481 * @s: a System.String
6483 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6486 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6488 MONO_REQ_GC_UNSAFE_MODE;
6490 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6495 * mono_string_to_utf16:
6498 * Return an null-terminated array of the utf-16 chars
6499 * contained in @s. The result must be freed with g_free().
6500 * This is a temporary helper until our string implementation
6501 * is reworked to always include the null terminating char.
6504 mono_string_to_utf16 (MonoString *s)
6506 MONO_REQ_GC_UNSAFE_MODE;
6513 as = (char *)g_malloc ((s->length * 2) + 2);
6514 as [(s->length * 2)] = '\0';
6515 as [(s->length * 2) + 1] = '\0';
6518 return (gunichar2 *)(as);
6521 memcpy (as, mono_string_chars(s), s->length * 2);
6522 return (gunichar2 *)(as);
6526 * mono_string_to_utf32:
6529 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6530 * contained in @s. The result must be freed with g_free().
6533 mono_string_to_utf32 (MonoString *s)
6535 MONO_REQ_GC_UNSAFE_MODE;
6537 mono_unichar4 *utf32_output = NULL;
6538 GError *error = NULL;
6539 glong items_written;
6544 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6547 g_error_free (error);
6549 return utf32_output;
6553 * mono_string_from_utf16:
6554 * @data: the UTF16 string (LPWSTR) to convert
6556 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6558 * Returns: a MonoString.
6561 mono_string_from_utf16 (gunichar2 *data)
6563 MONO_REQ_GC_UNSAFE_MODE;
6566 MonoString *res = NULL;
6567 MonoDomain *domain = mono_domain_get ();
6573 while (data [len]) len++;
6575 res = mono_string_new_utf16_checked (domain, data, len, &error);
6576 mono_error_raise_exception (&error); /* FIXME don't raise here */
6581 * mono_string_from_utf32:
6582 * @data: the UTF32 string (LPWSTR) to convert
6584 * Converts a UTF32 (UCS-4)to a MonoString.
6586 * Returns: a MonoString.
6589 mono_string_from_utf32 (mono_unichar4 *data)
6591 MONO_REQ_GC_UNSAFE_MODE;
6593 MonoString* result = NULL;
6594 mono_unichar2 *utf16_output = NULL;
6595 GError *error = NULL;
6596 glong items_written;
6602 while (data [len]) len++;
6604 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6607 g_error_free (error);
6609 result = mono_string_from_utf16 (utf16_output);
6610 g_free (utf16_output);
6615 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6617 MONO_REQ_GC_UNSAFE_MODE;
6624 r = mono_string_to_utf8_ignore (s);
6626 r = mono_string_to_utf8_checked (s, error);
6627 if (!mono_error_ok (error))
6634 len = strlen (r) + 1;
6636 mp_s = (char *)mono_mempool_alloc (mp, len);
6638 mp_s = (char *)mono_image_alloc (image, len);
6640 memcpy (mp_s, r, len);
6648 * mono_string_to_utf8_image:
6649 * @s: a System.String
6651 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6654 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6656 MONO_REQ_GC_UNSAFE_MODE;
6658 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6662 * mono_string_to_utf8_mp:
6663 * @s: a System.String
6665 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6668 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6670 MONO_REQ_GC_UNSAFE_MODE;
6672 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6676 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6679 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6681 eh_callbacks = *cbs;
6684 MonoRuntimeExceptionHandlingCallbacks *
6685 mono_get_eh_callbacks (void)
6687 return &eh_callbacks;
6691 * mono_raise_exception:
6692 * @ex: exception object
6694 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6697 mono_raise_exception (MonoException *ex)
6699 MONO_REQ_GC_UNSAFE_MODE;
6702 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6703 * that will cause gcc to omit the function epilog, causing problems when
6704 * the JIT tries to walk the stack, since the return address on the stack
6705 * will point into the next function in the executable, not this one.
6707 eh_callbacks.mono_raise_exception (ex);
6711 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6713 MONO_REQ_GC_UNSAFE_MODE;
6715 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6719 * mono_wait_handle_new:
6720 * @domain: Domain where the object will be created
6721 * @handle: Handle for the wait handle
6723 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6726 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6728 MONO_REQ_GC_UNSAFE_MODE;
6731 MonoWaitHandle *res;
6732 gpointer params [1];
6733 static MonoMethod *handle_set;
6735 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6736 mono_error_raise_exception (&error); /* FIXME don't raise here */
6738 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6740 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6742 params [0] = &handle;
6744 mono_runtime_invoke_checked (handle_set, res, params, &error);
6745 mono_error_raise_exception (&error); /* FIXME don't raise here */
6751 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6753 MONO_REQ_GC_UNSAFE_MODE;
6755 static MonoClassField *f_safe_handle = NULL;
6758 if (!f_safe_handle) {
6759 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6760 g_assert (f_safe_handle);
6763 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6769 mono_runtime_capture_context (MonoDomain *domain)
6771 MONO_REQ_GC_UNSAFE_MODE;
6773 RuntimeInvokeFunction runtime_invoke;
6775 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6776 MonoMethod *method = mono_get_context_capture_method ();
6777 MonoMethod *wrapper;
6780 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6781 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6782 domain->capture_context_method = mono_compile_method (method);
6785 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6787 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6790 * mono_async_result_new:
6791 * @domain:domain where the object will be created.
6792 * @handle: wait handle.
6793 * @state: state to pass to AsyncResult
6794 * @data: C closure data.
6796 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6797 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6801 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6803 MONO_REQ_GC_UNSAFE_MODE;
6806 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6807 mono_error_raise_exception (&error); /* FIXME don't raise here */
6808 MonoObject *context = mono_runtime_capture_context (domain);
6809 /* we must capture the execution context from the original thread */
6811 MONO_OBJECT_SETREF (res, execution_context, context);
6812 /* note: result may be null if the flow is suppressed */
6815 res->data = (void **)data;
6816 MONO_OBJECT_SETREF (res, object_data, object_data);
6817 MONO_OBJECT_SETREF (res, async_state, state);
6819 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6821 res->sync_completed = FALSE;
6822 res->completed = FALSE;
6828 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6830 MONO_REQ_GC_UNSAFE_MODE;
6837 g_assert (ares->async_delegate);
6839 ac = (MonoAsyncCall*) ares->object_data;
6841 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6843 gpointer wait_event = NULL;
6845 ac->msg->exc = NULL;
6846 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6847 MONO_OBJECT_SETREF (ac, res, res);
6849 mono_monitor_enter ((MonoObject*) ares);
6850 ares->completed = 1;
6852 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6853 mono_monitor_exit ((MonoObject*) ares);
6855 if (wait_event != NULL)
6856 SetEvent (wait_event);
6858 if (ac->cb_method) {
6859 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6860 mono_error_raise_exception (&error);
6868 mono_message_init (MonoDomain *domain,
6869 MonoMethodMessage *this_obj,
6870 MonoReflectionMethod *method,
6871 MonoArray *out_args)
6873 MONO_REQ_GC_UNSAFE_MODE;
6875 static MonoClass *object_array_klass;
6876 static MonoClass *byte_array_klass;
6877 static MonoClass *string_array_klass;
6879 MonoMethodSignature *sig = mono_method_signature (method->method);
6886 if (!object_array_klass) {
6889 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6891 byte_array_klass = klass;
6893 klass = mono_array_class_get (mono_defaults.string_class, 1);
6895 string_array_klass = klass;
6897 klass = mono_array_class_get (mono_defaults.object_class, 1);
6900 mono_atomic_store_release (&object_array_klass, klass);
6903 MONO_OBJECT_SETREF (this_obj, method, method);
6905 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6906 mono_error_raise_exception (&error); /* FIXME don't raise here */
6908 MONO_OBJECT_SETREF (this_obj, args, arr);
6910 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6911 mono_error_raise_exception (&error); /* FIXME don't raise here */
6913 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6915 this_obj->async_result = NULL;
6916 this_obj->call_type = CallType_Sync;
6918 names = g_new (char *, sig->param_count);
6919 mono_method_get_param_names (method->method, (const char **) names);
6921 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6922 mono_error_raise_exception (&error); /* FIXME don't raise here */
6924 MONO_OBJECT_SETREF (this_obj, names, arr);
6926 for (i = 0; i < sig->param_count; i++) {
6927 name = mono_string_new (domain, names [i]);
6928 mono_array_setref (this_obj->names, i, name);
6932 for (i = 0, j = 0; i < sig->param_count; i++) {
6933 if (sig->params [i]->byref) {
6935 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6936 mono_array_setref (this_obj->args, i, arg);
6940 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6944 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6947 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6951 #ifndef DISABLE_REMOTING
6953 * mono_remoting_invoke:
6954 * @real_proxy: pointer to a RealProxy object
6955 * @msg: The MonoMethodMessage to execute
6956 * @exc: used to store exceptions
6957 * @out_args: used to store output arguments
6959 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6960 * IMessage interface and it is not trivial to extract results from there. So
6961 * we call an helper method PrivateInvoke instead of calling
6962 * RealProxy::Invoke() directly.
6964 * Returns: the result object.
6967 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
6969 MONO_REQ_GC_UNSAFE_MODE;
6972 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6977 mono_error_init (error);
6979 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6982 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6984 mono_error_set_not_supported (error, "Linked away.");
6987 real_proxy->vtable->domain->private_invoke_method = im;
6990 pa [0] = real_proxy;
6995 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
6996 return_val_if_nok (error, NULL);
7003 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7004 MonoObject **exc, MonoArray **out_args)
7006 MONO_REQ_GC_UNSAFE_MODE;
7008 static MonoClass *object_array_klass;
7012 MonoMethodSignature *sig;
7015 int i, j, outarg_count = 0;
7017 #ifndef DISABLE_REMOTING
7018 if (target && mono_object_is_transparent_proxy (target)) {
7019 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7020 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7021 target = tp->rp->unwrapped_server;
7023 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
7024 mono_error_raise_exception (&error); /* FIXME don't raise here */
7031 domain = mono_domain_get ();
7032 method = msg->method->method;
7033 sig = mono_method_signature (method);
7035 for (i = 0; i < sig->param_count; i++) {
7036 if (sig->params [i]->byref)
7040 if (!object_array_klass) {
7043 klass = mono_array_class_get (mono_defaults.object_class, 1);
7046 mono_memory_barrier ();
7047 object_array_klass = klass;
7050 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
7051 mono_error_raise_exception (&error); /* FIXME don't raise here */
7053 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7056 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
7058 for (i = 0, j = 0; i < sig->param_count; i++) {
7059 if (sig->params [i]->byref) {
7061 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7062 mono_array_setref (*out_args, j, arg);
7071 * mono_object_to_string:
7073 * @exc: Any exception thrown by ToString (). May be NULL.
7075 * Returns: the result of calling ToString () on an object.
7078 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7080 MONO_REQ_GC_UNSAFE_MODE;
7082 static MonoMethod *to_string = NULL;
7091 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7093 method = mono_object_get_virtual_method (obj, to_string);
7095 // Unbox value type if needed
7096 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7097 target = mono_object_unbox (obj);
7101 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7102 if (*exc == NULL && !mono_error_ok (&error))
7103 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7105 mono_error_cleanup (&error);
7107 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7108 mono_error_raise_exception (&error); /* FIXME don't raise here */
7115 * mono_print_unhandled_exception:
7116 * @exc: The exception
7118 * Prints the unhandled exception.
7121 mono_print_unhandled_exception (MonoObject *exc)
7123 MONO_REQ_GC_UNSAFE_MODE;
7126 char *message = (char*)"";
7127 gboolean free_message = FALSE;
7130 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7131 message = g_strdup ("OutOfMemoryException");
7132 free_message = TRUE;
7133 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7134 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7135 free_message = TRUE;
7138 if (((MonoException*)exc)->native_trace_ips) {
7139 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7140 free_message = TRUE;
7142 MonoObject *other_exc = NULL;
7143 str = mono_object_to_string (exc, &other_exc);
7145 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7146 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7148 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7149 original_backtrace, nested_backtrace);
7151 g_free (original_backtrace);
7152 g_free (nested_backtrace);
7153 free_message = TRUE;
7155 message = mono_string_to_utf8_checked (str, &error);
7156 if (!mono_error_ok (&error)) {
7157 mono_error_cleanup (&error);
7158 message = (char *) "";
7160 free_message = TRUE;
7167 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7168 * exc->vtable->klass->name, message);
7170 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7177 * mono_delegate_ctor:
7178 * @this: pointer to an uninitialized delegate object
7179 * @target: target object
7180 * @addr: pointer to native code
7183 * Initialize a delegate and sets a specific method, not the one
7184 * associated with addr. This is useful when sharing generic code.
7185 * In that case addr will most probably not be associated with the
7186 * correct instantiation of the method.
7189 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7191 MONO_REQ_GC_UNSAFE_MODE;
7193 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7195 g_assert (this_obj);
7198 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7201 delegate->method = method;
7203 mono_stats.delegate_creations++;
7205 #ifndef DISABLE_REMOTING
7206 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7208 method = mono_marshal_get_remoting_invoke (method);
7209 delegate->method_ptr = mono_compile_method (method);
7210 MONO_OBJECT_SETREF (delegate, target, target);
7214 delegate->method_ptr = addr;
7215 MONO_OBJECT_SETREF (delegate, target, target);
7218 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7219 if (callbacks.init_delegate)
7220 callbacks.init_delegate (delegate);
7224 * mono_delegate_ctor:
7225 * @this: pointer to an uninitialized delegate object
7226 * @target: target object
7227 * @addr: pointer to native code
7229 * This is used to initialize a delegate.
7232 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7234 MONO_REQ_GC_UNSAFE_MODE;
7236 MonoDomain *domain = mono_domain_get ();
7238 MonoMethod *method = NULL;
7242 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7244 if (!ji && domain != mono_get_root_domain ())
7245 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7247 method = mono_jit_info_get_method (ji);
7248 g_assert (!method->klass->generic_container);
7251 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7255 * mono_method_call_message_new:
7256 * @method: method to encapsulate
7257 * @params: parameters to the method
7258 * @invoke: optional, delegate invoke.
7259 * @cb: async callback delegate.
7260 * @state: state passed to the async callback.
7262 * Translates arguments pointers into a MonoMethodMessage.
7265 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7266 MonoDelegate **cb, MonoObject **state)
7268 MONO_REQ_GC_UNSAFE_MODE;
7272 MonoDomain *domain = mono_domain_get ();
7273 MonoMethodSignature *sig = mono_method_signature (method);
7274 MonoMethodMessage *msg;
7277 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7278 mono_error_raise_exception (&error); /* FIXME don't raise here */
7281 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7282 mono_error_raise_exception (&error); /* FIXME don't raise here */
7283 mono_message_init (domain, msg, rm, NULL);
7284 count = sig->param_count - 2;
7286 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7287 mono_error_raise_exception (&error); /* FIXME don't raise here */
7288 mono_message_init (domain, msg, rm, NULL);
7289 count = sig->param_count;
7292 for (i = 0; i < count; i++) {
7297 if (sig->params [i]->byref)
7298 vpos = *((gpointer *)params [i]);
7302 klass = mono_class_from_mono_type (sig->params [i]);
7304 if (klass->valuetype) {
7305 arg = mono_value_box_checked (domain, klass, vpos, &error);
7306 mono_error_raise_exception (&error); /* FIXME don't raise here */
7308 arg = *((MonoObject **)vpos);
7310 mono_array_setref (msg->args, i, arg);
7313 if (cb != NULL && state != NULL) {
7314 *cb = *((MonoDelegate **)params [i]);
7316 *state = *((MonoObject **)params [i]);
7323 * mono_method_return_message_restore:
7325 * Restore results from message based processing back to arguments pointers
7328 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7330 MONO_REQ_GC_UNSAFE_MODE;
7332 MonoMethodSignature *sig = mono_method_signature (method);
7333 int i, j, type, size, out_len;
7335 if (out_args == NULL)
7337 out_len = mono_array_length (out_args);
7341 for (i = 0, j = 0; i < sig->param_count; i++) {
7342 MonoType *pt = sig->params [i];
7347 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7349 arg = (char *)mono_array_get (out_args, gpointer, j);
7352 g_assert (type != MONO_TYPE_VOID);
7354 if (MONO_TYPE_IS_REFERENCE (pt)) {
7355 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7358 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7359 size = mono_class_value_size (klass, NULL);
7360 if (klass->has_references)
7361 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7363 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7365 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7366 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7375 #ifndef DISABLE_REMOTING
7378 * mono_load_remote_field:
7379 * @this: pointer to an object
7380 * @klass: klass of the object containing @field
7381 * @field: the field to load
7382 * @res: a storage to store the result
7384 * This method is called by the runtime on attempts to load fields of
7385 * transparent proxy objects. @this points to such TP, @klass is the class of
7386 * the object containing @field. @res is a storage location which can be
7387 * used to store the result.
7389 * Returns: an address pointing to the value of field.
7392 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7394 MONO_REQ_GC_UNSAFE_MODE;
7398 static MonoMethod *getter = NULL;
7399 MonoDomain *domain = mono_domain_get ();
7400 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7401 MonoClass *field_class;
7402 MonoMethodMessage *msg;
7403 MonoArray *out_args;
7407 g_assert (mono_object_is_transparent_proxy (this_obj));
7408 g_assert (res != NULL);
7410 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7411 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7416 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7418 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7421 field_class = mono_class_from_mono_type (field->type);
7423 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7424 mono_error_raise_exception (&error); /* FIXME don't raise here */
7425 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7426 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7427 mono_error_raise_exception (&error); /* FIXME don't raise here */
7428 mono_message_init (domain, msg, rm, out_args);
7430 full_name = mono_type_get_full_name (klass);
7431 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7432 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7435 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7436 mono_error_raise_exception (&error); /* FIXME don't raise here */
7438 if (exc) mono_raise_exception ((MonoException *)exc);
7440 if (mono_array_length (out_args) == 0)
7443 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7445 if (field_class->valuetype) {
7446 return ((char *)*res) + sizeof (MonoObject);
7452 * mono_load_remote_field_new:
7457 * Missing documentation.
7460 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7462 MONO_REQ_GC_UNSAFE_MODE;
7466 static MonoMethod *getter = NULL;
7467 MonoDomain *domain = mono_domain_get ();
7468 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7469 MonoClass *field_class;
7470 MonoMethodMessage *msg;
7471 MonoArray *out_args;
7472 MonoObject *exc, *res;
7475 g_assert (mono_object_is_transparent_proxy (this_obj));
7477 field_class = mono_class_from_mono_type (field->type);
7479 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7481 if (field_class->valuetype) {
7482 res = mono_object_new_checked (domain, field_class, &error);
7483 mono_error_raise_exception (&error); /* FIXME don't raise here */
7484 val = ((gchar *) res) + sizeof (MonoObject);
7488 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7493 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7495 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7498 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7499 mono_error_raise_exception (&error); /* FIXME don't raise here */
7500 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7502 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7503 mono_error_raise_exception (&error); /* FIXME don't raise here */
7504 mono_message_init (domain, msg, rm, out_args);
7506 full_name = mono_type_get_full_name (klass);
7507 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7508 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7511 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7512 mono_error_raise_exception (&error); /* FIXME don't raise here */
7514 if (exc) mono_raise_exception ((MonoException *)exc);
7516 if (mono_array_length (out_args) == 0)
7519 res = mono_array_get (out_args, MonoObject *, 0);
7525 * mono_store_remote_field:
7526 * @this_obj: pointer to an object
7527 * @klass: klass of the object containing @field
7528 * @field: the field to load
7529 * @val: the value/object to store
7531 * This method is called by the runtime on attempts to store fields of
7532 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7533 * the object containing @field. @val is the new value to store in @field.
7536 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7538 MONO_REQ_GC_UNSAFE_MODE;
7542 static MonoMethod *setter = NULL;
7543 MonoDomain *domain = mono_domain_get ();
7544 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7545 MonoClass *field_class;
7546 MonoMethodMessage *msg;
7547 MonoArray *out_args;
7552 g_assert (mono_object_is_transparent_proxy (this_obj));
7554 field_class = mono_class_from_mono_type (field->type);
7556 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7557 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7558 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7563 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7565 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7568 if (field_class->valuetype) {
7569 arg = mono_value_box_checked (domain, field_class, val, &error);
7570 mono_error_raise_exception (&error); /* FIXME don't raise here */
7572 arg = *((MonoObject **)val);
7575 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7576 mono_error_raise_exception (&error); /* FIXME don't raise here */
7577 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7578 mono_error_raise_exception (&error); /* FIXME don't raise here */
7579 mono_message_init (domain, msg, rm, NULL);
7581 full_name = mono_type_get_full_name (klass);
7582 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7583 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7584 mono_array_setref (msg->args, 2, arg);
7587 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7588 mono_error_raise_exception (&error); /* FIXME don't raise here */
7590 if (exc) mono_raise_exception ((MonoException *)exc);
7594 * mono_store_remote_field_new:
7600 * Missing documentation
7603 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7605 MONO_REQ_GC_UNSAFE_MODE;
7609 static MonoMethod *setter = NULL;
7610 MonoDomain *domain = mono_domain_get ();
7611 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7612 MonoClass *field_class;
7613 MonoMethodMessage *msg;
7614 MonoArray *out_args;
7618 g_assert (mono_object_is_transparent_proxy (this_obj));
7620 field_class = mono_class_from_mono_type (field->type);
7622 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7623 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7624 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7629 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7631 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7634 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7635 mono_error_raise_exception (&error); /* FIXME don't raise here */
7636 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7637 mono_error_raise_exception (&error); /* FIXME don't raise here */
7638 mono_message_init (domain, msg, rm, NULL);
7640 full_name = mono_type_get_full_name (klass);
7641 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7642 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7643 mono_array_setref (msg->args, 2, arg);
7646 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7647 mono_error_raise_exception (&error); /* FIXME don't raise here */
7649 if (exc) mono_raise_exception ((MonoException *)exc);
7654 * mono_create_ftnptr:
7656 * Given a function address, create a function descriptor for it.
7657 * This is only needed on some platforms.
7660 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7662 return callbacks.create_ftnptr (domain, addr);
7666 * mono_get_addr_from_ftnptr:
7668 * Given a pointer to a function descriptor, return the function address.
7669 * This is only needed on some platforms.
7672 mono_get_addr_from_ftnptr (gpointer descr)
7674 return callbacks.get_addr_from_ftnptr (descr);
7678 * mono_string_chars:
7681 * Returns a pointer to the UCS16 characters stored in the MonoString
7684 mono_string_chars (MonoString *s)
7686 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7692 * mono_string_length:
7695 * Returns the lenght in characters of the string
7698 mono_string_length (MonoString *s)
7700 MONO_REQ_GC_UNSAFE_MODE;
7706 * mono_array_length:
7707 * @array: a MonoArray*
7709 * Returns the total number of elements in the array. This works for
7710 * both vectors and multidimensional arrays.
7713 mono_array_length (MonoArray *array)
7715 MONO_REQ_GC_UNSAFE_MODE;
7717 return array->max_length;
7721 * mono_array_addr_with_size:
7722 * @array: a MonoArray*
7723 * @size: size of the array elements
7724 * @idx: index into the array
7726 * Use this function to obtain the address for the @idx item on the
7727 * @array containing elements of size @size.
7729 * This method performs no bounds checking or type checking.
7731 * Returns the address of the @idx element in the array.
7734 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7736 MONO_REQ_GC_UNSAFE_MODE;
7738 return ((char*)(array)->vector) + size * idx;
7743 mono_glist_to_array (GList *list, MonoClass *eclass)
7745 MonoDomain *domain = mono_domain_get ();
7752 len = g_list_length (list);
7753 res = mono_array_new (domain, eclass, len);
7755 for (i = 0; list; list = list->next, i++)
7756 mono_array_set (res, gpointer, i, list->data);
7763 * The following section is purely to declare prototypes and
7764 * document the API, as these C files are processed by our
7770 * @array: array to alter
7771 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7772 * @index: index into the array
7773 * @value: value to set
7775 * Value Type version: This sets the @index's element of the @array
7776 * with elements of size sizeof(type) to the provided @value.
7778 * This macro does not attempt to perform type checking or bounds checking.
7780 * Use this to set value types in a `MonoArray`.
7782 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7787 * mono_array_setref:
7788 * @array: array to alter
7789 * @index: index into the array
7790 * @value: value to set
7792 * Reference Type version: This sets the @index's element of the
7793 * @array with elements of size sizeof(type) to the provided @value.
7795 * This macro does not attempt to perform type checking or bounds checking.
7797 * Use this to reference types in a `MonoArray`.
7799 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7805 * @array: array on which to operate on
7806 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7807 * @index: index into the array
7809 * Use this macro to retrieve the @index element of an @array and
7810 * extract the value assuming that the elements of the array match
7811 * the provided type value.
7813 * This method can be used with both arrays holding value types and
7814 * reference types. For reference types, the @type parameter should
7815 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7817 * This macro does not attempt to perform type checking or bounds checking.
7819 * Returns: The element at the @index position in the @array.
7821 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)