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)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/utils/strenc.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-memory-model.h>
48 #include <mono/utils/checked-build.h>
49 #include <mono/utils/mono-threads.h>
50 #include "cominterop.h"
53 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
56 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
59 free_main_args (void);
62 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
64 /* Class lazy loading functions */
65 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
66 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
67 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
68 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
69 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
72 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
73 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
74 static mono_mutex_t ldstr_section;
77 * mono_runtime_object_init:
78 * @this_obj: the object to initialize
80 * This function calls the zero-argument constructor (which must
81 * exist) for the given object.
84 mono_runtime_object_init (MonoObject *this_obj)
87 mono_runtime_object_init_checked (this_obj, &error);
88 mono_error_assert_ok (&error);
92 * mono_runtime_object_init_checked:
93 * @this_obj: the object to initialize
94 * @error: set on error.
96 * This function calls the zero-argument constructor (which must
97 * exist) for the given object and returns TRUE on success, or FALSE
98 * on error and sets @error.
101 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
103 MONO_REQ_GC_UNSAFE_MODE;
105 MonoMethod *method = NULL;
106 MonoClass *klass = this_obj->vtable->klass;
108 mono_error_init (error);
109 method = mono_class_get_method_from_name (klass, ".ctor", 0);
111 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
113 if (method->klass->valuetype)
114 this_obj = (MonoObject *)mono_object_unbox (this_obj);
116 mono_runtime_invoke_checked (method, this_obj, NULL, error);
117 return is_ok (error);
120 /* The pseudo algorithm for type initialization from the spec
121 Note it doesn't say anything about domains - only threads.
123 2. If the type is initialized you are done.
124 2.1. If the type is not yet initialized, try to take an
126 2.2. If successful, record this thread as responsible for
127 initializing the type and proceed to step 2.3.
128 2.2.1. If not, see whether this thread or any thread
129 waiting for this thread to complete already holds the lock.
130 2.2.2. If so, return since blocking would create a deadlock. This thread
131 will now see an incompletely initialized state for the type,
132 but no deadlock will arise.
133 2.2.3 If not, block until the type is initialized then return.
134 2.3 Initialize the parent type and then all interfaces implemented
136 2.4 Execute the type initialization code for this type.
137 2.5 Mark the type as initialized, release the initialization lock,
138 awaken any threads waiting for this type to be initialized,
145 MonoNativeThreadId initializing_tid;
146 guint32 waiting_count;
148 MonoCoopMutex initialization_section;
149 } TypeInitializationLock;
151 /* for locking access to type_initialization_hash and blocked_thread_hash */
152 static MonoCoopMutex type_initialization_section;
155 mono_type_initialization_lock (void)
157 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
158 mono_coop_mutex_lock (&type_initialization_section);
162 mono_type_initialization_unlock (void)
164 mono_coop_mutex_unlock (&type_initialization_section);
168 mono_type_init_lock (TypeInitializationLock *lock)
170 MONO_REQ_GC_NEUTRAL_MODE;
172 mono_coop_mutex_lock (&lock->initialization_section);
176 mono_type_init_unlock (TypeInitializationLock *lock)
178 mono_coop_mutex_unlock (&lock->initialization_section);
181 /* from vtable to lock */
182 static GHashTable *type_initialization_hash;
184 /* from thread id to thread id being waited on */
185 static GHashTable *blocked_thread_hash;
188 static MonoThread *main_thread;
190 /* Functions supplied by the runtime */
191 static MonoRuntimeCallbacks callbacks;
194 * mono_thread_set_main:
195 * @thread: thread to set as the main thread
197 * This function can be used to instruct the runtime to treat @thread
198 * as the main thread, ie, the thread that would normally execute the Main()
199 * method. This basically means that at the end of @thread, the runtime will
200 * wait for the existing foreground threads to quit and other such details.
203 mono_thread_set_main (MonoThread *thread)
205 MONO_REQ_GC_UNSAFE_MODE;
207 static gboolean registered = FALSE;
210 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
214 main_thread = thread;
218 mono_thread_get_main (void)
220 MONO_REQ_GC_UNSAFE_MODE;
226 mono_type_initialization_init (void)
228 mono_coop_mutex_init_recursive (&type_initialization_section);
229 type_initialization_hash = g_hash_table_new (NULL, NULL);
230 blocked_thread_hash = g_hash_table_new (NULL, NULL);
231 mono_os_mutex_init_recursive (&ldstr_section);
235 mono_type_initialization_cleanup (void)
238 /* This is causing race conditions with
239 * mono_release_type_locks
241 mono_coop_mutex_destroy (&type_initialization_section);
242 g_hash_table_destroy (type_initialization_hash);
243 type_initialization_hash = NULL;
245 mono_os_mutex_destroy (&ldstr_section);
246 g_hash_table_destroy (blocked_thread_hash);
247 blocked_thread_hash = NULL;
253 * get_type_init_exception_for_vtable:
255 * Return the stored type initialization exception for VTABLE.
257 static MonoException*
258 get_type_init_exception_for_vtable (MonoVTable *vtable)
260 MONO_REQ_GC_UNSAFE_MODE;
263 MonoDomain *domain = vtable->domain;
264 MonoClass *klass = vtable->klass;
268 if (!vtable->init_failed)
269 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
272 * If the initializing thread was rudely aborted, the exception is not stored
276 mono_domain_lock (domain);
277 if (domain->type_init_exception_hash)
278 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
279 mono_domain_unlock (domain);
282 if (klass->name_space && *klass->name_space)
283 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
285 full_name = g_strdup (klass->name);
286 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
288 return_val_if_nok (&error, NULL);
295 * mono_runtime_class_init:
296 * @vtable: vtable that needs to be initialized
298 * This routine calls the class constructor for @vtable.
301 mono_runtime_class_init (MonoVTable *vtable)
303 MONO_REQ_GC_UNSAFE_MODE;
306 mono_runtime_class_init_full (vtable, &error);
307 mono_error_assert_ok (&error);
311 * mono_runtime_class_init_full:
312 * @vtable that neeeds to be initialized
313 * @error set on error
315 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
319 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
321 MONO_REQ_GC_UNSAFE_MODE;
323 MonoMethod *method = NULL;
326 MonoDomain *domain = vtable->domain;
327 TypeInitializationLock *lock;
328 MonoNativeThreadId tid;
329 int do_initialization = 0;
330 MonoDomain *last_domain = NULL;
332 mono_error_init (error);
334 if (vtable->initialized)
337 klass = vtable->klass;
339 if (!klass->image->checked_module_cctor) {
340 mono_image_check_for_module_cctor (klass->image);
341 if (klass->image->has_module_cctor) {
342 MonoClass *module_klass;
343 MonoVTable *module_vtable;
345 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
350 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
353 if (!mono_runtime_class_init_full (module_vtable, error))
357 method = mono_class_get_cctor (klass);
359 vtable->initialized = 1;
363 tid = mono_native_thread_id_get ();
365 mono_type_initialization_lock ();
366 /* double check... */
367 if (vtable->initialized) {
368 mono_type_initialization_unlock ();
371 if (vtable->init_failed) {
372 mono_type_initialization_unlock ();
374 /* The type initialization already failed once, rethrow the same exception */
375 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
378 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
380 /* This thread will get to do the initialization */
381 if (mono_domain_get () != domain) {
382 /* Transfer into the target domain */
383 last_domain = mono_domain_get ();
384 if (!mono_domain_set (domain, FALSE)) {
385 vtable->initialized = 1;
386 mono_type_initialization_unlock ();
387 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
391 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
392 mono_coop_mutex_init_recursive (&lock->initialization_section);
393 lock->initializing_tid = tid;
394 lock->waiting_count = 1;
396 /* grab the vtable lock while this thread still owns type_initialization_section */
397 /* This is why type_initialization_lock needs to enter blocking mode */
398 mono_type_init_lock (lock);
399 g_hash_table_insert (type_initialization_hash, vtable, lock);
400 do_initialization = 1;
403 TypeInitializationLock *pending_lock;
405 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
406 mono_type_initialization_unlock ();
409 /* see if the thread doing the initialization is already blocked on this thread */
410 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
411 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
412 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
413 if (!pending_lock->done) {
414 mono_type_initialization_unlock ();
417 /* the thread doing the initialization is blocked on this thread,
418 but on a lock that has already been freed. It just hasn't got
423 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
425 ++lock->waiting_count;
426 /* record the fact that we are waiting on the initializing thread */
427 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
429 mono_type_initialization_unlock ();
431 if (do_initialization) {
432 MonoException *exc = NULL;
433 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
434 if (exc != NULL && mono_error_ok (error)) {
435 mono_error_set_exception_instance (error, exc);
438 /* If the initialization failed, mark the class as unusable. */
439 /* Avoid infinite loops */
440 if (!(mono_error_ok(error) ||
441 (klass->image == mono_defaults.corlib &&
442 !strcmp (klass->name_space, "System") &&
443 !strcmp (klass->name, "TypeInitializationException")))) {
444 vtable->init_failed = 1;
446 if (klass->name_space && *klass->name_space)
447 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
449 full_name = g_strdup (klass->name);
451 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
453 return_val_if_nok (error, FALSE);
455 mono_error_set_exception_instance (error, exc_to_throw);
457 MonoException *exc_to_store = mono_error_convert_to_exception (error);
458 /* What we really want to do here is clone the error object and store one copy in the
459 * domain's exception hash and use the other one to error out here. */
460 mono_error_set_exception_instance (error, exc_to_store);
462 * Store the exception object so it could be thrown on subsequent
465 mono_domain_lock (domain);
466 if (!domain->type_init_exception_hash)
467 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");
468 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
469 mono_domain_unlock (domain);
473 mono_domain_set (last_domain, TRUE);
475 mono_type_init_unlock (lock);
477 /* this just blocks until the initializing thread is done */
478 mono_type_init_lock (lock);
479 mono_type_init_unlock (lock);
482 mono_type_initialization_lock ();
483 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
484 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
485 --lock->waiting_count;
486 if (lock->waiting_count == 0) {
487 mono_coop_mutex_destroy (&lock->initialization_section);
488 g_hash_table_remove (type_initialization_hash, vtable);
491 mono_memory_barrier ();
492 if (!vtable->init_failed)
493 vtable->initialized = 1;
494 mono_type_initialization_unlock ();
496 if (vtable->init_failed) {
497 /* Either we were the initializing thread or we waited for the initialization */
498 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
505 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
507 MONO_REQ_GC_NEUTRAL_MODE;
509 MonoVTable *vtable = (MonoVTable*)key;
511 TypeInitializationLock *lock = (TypeInitializationLock*) value;
512 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
515 * Have to set this since it cannot be set by the normal code in
516 * mono_runtime_class_init (). In this case, the exception object is not stored,
517 * and get_type_init_exception_for_class () needs to be aware of this.
519 vtable->init_failed = 1;
520 mono_type_init_unlock (lock);
521 --lock->waiting_count;
522 if (lock->waiting_count == 0) {
523 mono_coop_mutex_destroy (&lock->initialization_section);
532 mono_release_type_locks (MonoInternalThread *thread)
534 MONO_REQ_GC_UNSAFE_MODE;
536 mono_type_initialization_lock ();
537 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
538 mono_type_initialization_unlock ();
541 #ifndef DISABLE_REMOTING
544 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
546 g_error ("remoting not installed");
550 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
554 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
556 g_assert_not_reached ();
560 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
561 static MonoImtThunkBuilder imt_thunk_builder;
562 static gboolean always_build_imt_thunks;
564 #if (MONO_IMT_SIZE > 32)
565 #error "MONO_IMT_SIZE cannot be larger than 32"
569 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
571 memcpy (&callbacks, cbs, sizeof (*cbs));
574 MonoRuntimeCallbacks*
575 mono_get_runtime_callbacks (void)
580 #ifndef DISABLE_REMOTING
582 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
584 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
589 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
591 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
595 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
596 imt_thunk_builder = func;
600 mono_set_always_build_imt_thunks (gboolean value)
602 always_build_imt_thunks = value;
606 * mono_compile_method:
607 * @method: The method to compile.
609 * This JIT-compiles the method, and returns the pointer to the native code
613 mono_compile_method (MonoMethod *method)
618 MONO_REQ_GC_NEUTRAL_MODE
620 if (!callbacks.compile_method) {
621 g_error ("compile method called on uninitialized runtime");
624 res = callbacks.compile_method (method, &error);
625 if (!mono_error_ok (&error))
626 mono_error_raise_exception (&error);
631 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
636 MONO_REQ_GC_NEUTRAL_MODE;
638 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, &error);
639 if (!mono_error_ok (&error))
640 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
645 mono_runtime_create_delegate_trampoline (MonoClass *klass)
647 MONO_REQ_GC_NEUTRAL_MODE
649 return arch_create_delegate_trampoline (mono_domain_get (), klass);
652 static MonoFreeMethodFunc default_mono_free_method = NULL;
655 * mono_install_free_method:
656 * @func: pointer to the MonoFreeMethodFunc used to release a method
658 * This is an internal VM routine, it is used for the engines to
659 * register a handler to release the resources associated with a method.
661 * Methods are freed when no more references to the delegate that holds
665 mono_install_free_method (MonoFreeMethodFunc func)
667 default_mono_free_method = func;
671 * mono_runtime_free_method:
672 * @domain; domain where the method is hosted
673 * @method: method to release
675 * This routine is invoked to free the resources associated with
676 * a method that has been JIT compiled. This is used to discard
677 * methods that were used only temporarily (for example, used in marshalling)
681 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
683 MONO_REQ_GC_NEUTRAL_MODE
685 if (default_mono_free_method != NULL)
686 default_mono_free_method (domain, method);
688 mono_method_clear_object (domain, method);
690 mono_free_method (method);
694 * The vtables in the root appdomain are assumed to be reachable by other
695 * roots, and we don't use typed allocation in the other domains.
698 /* The sync block is no longer a GC pointer */
699 #define GC_HEADER_BITMAP (0)
701 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
704 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
706 MONO_REQ_GC_NEUTRAL_MODE;
708 MonoClassField *field;
714 max_size = mono_class_data_size (klass) / sizeof (gpointer);
716 max_size = klass->instance_size / sizeof (gpointer);
717 if (max_size > size) {
718 g_assert (offset <= 0);
719 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
724 /*An Ephemeron cannot be marked by sgen*/
725 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
727 memset (bitmap, 0, size / 8);
732 for (p = klass; p != NULL; p = p->parent) {
733 gpointer iter = NULL;
734 while ((field = mono_class_get_fields (p, &iter))) {
738 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
740 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
743 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
746 /* FIXME: should not happen, flag as type load error */
747 if (field->type->byref)
750 if (static_fields && field->offset == -1)
754 pos = field->offset / sizeof (gpointer);
757 type = mono_type_get_underlying_type (field->type);
758 switch (type->type) {
761 case MONO_TYPE_FNPTR:
763 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
768 if (klass->image != mono_defaults.corlib)
771 case MONO_TYPE_STRING:
772 case MONO_TYPE_SZARRAY:
773 case MONO_TYPE_CLASS:
774 case MONO_TYPE_OBJECT:
775 case MONO_TYPE_ARRAY:
776 g_assert ((field->offset % sizeof(gpointer)) == 0);
778 g_assert (pos < size || pos <= max_size);
779 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
780 *max_set = MAX (*max_set, pos);
782 case MONO_TYPE_GENERICINST:
783 if (!mono_type_generic_inst_is_valuetype (type)) {
784 g_assert ((field->offset % sizeof(gpointer)) == 0);
786 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
787 *max_set = MAX (*max_set, pos);
792 case MONO_TYPE_VALUETYPE: {
793 MonoClass *fclass = mono_class_from_mono_type (field->type);
794 if (fclass->has_references) {
795 /* remove the object header */
796 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
810 case MONO_TYPE_BOOLEAN:
814 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
825 * mono_class_compute_bitmap:
827 * Mono internal function to compute a bitmap of reference fields in a class.
830 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
832 MONO_REQ_GC_NEUTRAL_MODE;
834 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
839 * similar to the above, but sets the bits in the bitmap for any non-ref field
840 * and ignores static fields
843 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
845 MonoClassField *field;
850 max_size = class->instance_size / sizeof (gpointer);
851 if (max_size >= size) {
852 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
855 for (p = class; p != NULL; p = p->parent) {
856 gpointer iter = NULL;
857 while ((field = mono_class_get_fields (p, &iter))) {
860 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
862 /* FIXME: should not happen, flag as type load error */
863 if (field->type->byref)
866 pos = field->offset / sizeof (gpointer);
869 type = mono_type_get_underlying_type (field->type);
870 switch (type->type) {
871 #if SIZEOF_VOID_P == 8
875 case MONO_TYPE_FNPTR:
880 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
881 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
882 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
885 #if SIZEOF_VOID_P == 4
889 case MONO_TYPE_FNPTR:
894 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
895 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
896 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
902 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
903 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
904 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
907 case MONO_TYPE_BOOLEAN:
910 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
912 case MONO_TYPE_STRING:
913 case MONO_TYPE_SZARRAY:
914 case MONO_TYPE_CLASS:
915 case MONO_TYPE_OBJECT:
916 case MONO_TYPE_ARRAY:
918 case MONO_TYPE_GENERICINST:
919 if (!mono_type_generic_inst_is_valuetype (type)) {
924 case MONO_TYPE_VALUETYPE: {
925 MonoClass *fclass = mono_class_from_mono_type (field->type);
926 /* remove the object header */
927 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
931 g_assert_not_reached ();
940 * mono_class_insecure_overlapping:
941 * check if a class with explicit layout has references and non-references
942 * fields overlapping.
944 * Returns: TRUE if it is insecure to load the type.
947 mono_class_insecure_overlapping (MonoClass *klass)
951 gsize default_bitmap [4] = {0};
953 gsize default_nrbitmap [4] = {0};
954 int i, insecure = FALSE;
957 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
958 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
960 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
961 int idx = i % (sizeof (bitmap [0]) * 8);
962 if (bitmap [idx] & nrbitmap [idx]) {
967 if (bitmap != default_bitmap)
969 if (nrbitmap != default_nrbitmap)
972 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
980 ves_icall_string_alloc (int length)
983 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
984 mono_error_raise_exception (&error);
990 mono_class_compute_gc_descriptor (MonoClass *klass)
992 MONO_REQ_GC_NEUTRAL_MODE;
996 gsize default_bitmap [4] = {0};
997 static gboolean gcj_inited = FALSE;
1000 mono_loader_lock ();
1002 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1003 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1006 mono_loader_unlock ();
1010 mono_class_init (klass);
1012 if (klass->gc_descr_inited)
1015 klass->gc_descr_inited = TRUE;
1016 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1018 bitmap = default_bitmap;
1019 if (klass == mono_defaults.string_class) {
1020 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1021 } else if (klass->rank) {
1022 mono_class_compute_gc_descriptor (klass->element_class);
1023 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1025 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1026 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1027 class->name_space, class->name);*/
1029 /* remove the object header */
1030 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1031 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));
1032 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1033 class->name_space, class->name);*/
1034 if (bitmap != default_bitmap)
1038 /*static int count = 0;
1041 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1042 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1044 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1045 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1047 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1048 if (bitmap != default_bitmap)
1054 * field_is_special_static:
1055 * @fklass: The MonoClass to look up.
1056 * @field: The MonoClassField describing the field.
1058 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1059 * SPECIAL_STATIC_NONE otherwise.
1062 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1064 MONO_REQ_GC_NEUTRAL_MODE;
1067 MonoCustomAttrInfo *ainfo;
1069 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1070 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1073 for (i = 0; i < ainfo->num_attrs; ++i) {
1074 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1075 if (klass->image == mono_defaults.corlib) {
1076 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1077 mono_custom_attrs_free (ainfo);
1078 return SPECIAL_STATIC_THREAD;
1080 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1081 mono_custom_attrs_free (ainfo);
1082 return SPECIAL_STATIC_CONTEXT;
1086 mono_custom_attrs_free (ainfo);
1087 return SPECIAL_STATIC_NONE;
1090 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1091 #define mix(a,b,c) { \
1092 a -= c; a ^= rot(c, 4); c += b; \
1093 b -= a; b ^= rot(a, 6); a += c; \
1094 c -= b; c ^= rot(b, 8); b += a; \
1095 a -= c; a ^= rot(c,16); c += b; \
1096 b -= a; b ^= rot(a,19); a += c; \
1097 c -= b; c ^= rot(b, 4); b += a; \
1099 #define final(a,b,c) { \
1100 c ^= b; c -= rot(b,14); \
1101 a ^= c; a -= rot(c,11); \
1102 b ^= a; b -= rot(a,25); \
1103 c ^= b; c -= rot(b,16); \
1104 a ^= c; a -= rot(c,4); \
1105 b ^= a; b -= rot(a,14); \
1106 c ^= b; c -= rot(b,24); \
1110 * mono_method_get_imt_slot:
1112 * The IMT slot is embedded into AOTed code, so this must return the same value
1113 * for the same method across all executions. This means:
1114 * - pointers shouldn't be used as hash values.
1115 * - mono_metadata_str_hash () should be used for hashing strings.
1118 mono_method_get_imt_slot (MonoMethod *method)
1120 MONO_REQ_GC_NEUTRAL_MODE;
1122 MonoMethodSignature *sig;
1124 guint32 *hashes_start, *hashes;
1128 /* This can be used to stress tests the collision code */
1132 * We do this to simplify generic sharing. It will hurt
1133 * performance in cases where a class implements two different
1134 * instantiations of the same generic interface.
1135 * The code in build_imt_slots () depends on this.
1137 if (method->is_inflated)
1138 method = ((MonoMethodInflated*)method)->declaring;
1140 sig = mono_method_signature (method);
1141 hashes_count = sig->param_count + 4;
1142 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1143 hashes = hashes_start;
1145 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1146 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1147 method->klass->name_space, method->klass->name, method->name);
1150 /* Initialize hashes */
1151 hashes [0] = mono_metadata_str_hash (method->klass->name);
1152 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1153 hashes [2] = mono_metadata_str_hash (method->name);
1154 hashes [3] = mono_metadata_type_hash (sig->ret);
1155 for (i = 0; i < sig->param_count; i++) {
1156 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1159 /* Setup internal state */
1160 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1162 /* Handle most of the hashes */
1163 while (hashes_count > 3) {
1172 /* Handle the last 3 hashes (all the case statements fall through) */
1173 switch (hashes_count) {
1174 case 3 : c += hashes [2];
1175 case 2 : b += hashes [1];
1176 case 1 : a += hashes [0];
1178 case 0: /* nothing left to add */
1182 free (hashes_start);
1183 /* Report the result */
1184 return c % MONO_IMT_SIZE;
1193 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1194 MONO_REQ_GC_NEUTRAL_MODE;
1196 guint32 imt_slot = mono_method_get_imt_slot (method);
1197 MonoImtBuilderEntry *entry;
1199 if (slot_num >= 0 && imt_slot != slot_num) {
1200 /* we build just a single imt slot and this is not it */
1204 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1205 entry->key = method;
1206 entry->value.vtable_slot = vtable_slot;
1207 entry->next = imt_builder [imt_slot];
1208 if (imt_builder [imt_slot] != NULL) {
1209 entry->children = imt_builder [imt_slot]->children + 1;
1210 if (entry->children == 1) {
1211 mono_stats.imt_slots_with_collisions++;
1212 *imt_collisions_bitmap |= (1 << imt_slot);
1215 entry->children = 0;
1216 mono_stats.imt_used_slots++;
1218 imt_builder [imt_slot] = entry;
1221 char *method_name = mono_method_full_name (method, TRUE);
1222 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1223 method, method_name, imt_slot, vtable_slot, entry->children);
1224 g_free (method_name);
1231 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1233 MonoMethod *method = e->key;
1234 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1238 method->klass->name_space,
1239 method->klass->name,
1242 printf (" * %s: NULL\n", message);
1248 compare_imt_builder_entries (const void *p1, const void *p2) {
1249 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1250 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1252 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1256 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1258 MONO_REQ_GC_NEUTRAL_MODE;
1260 int count = end - start;
1261 int chunk_start = out_array->len;
1264 for (i = start; i < end; ++i) {
1265 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1266 item->key = sorted_array [i]->key;
1267 item->value = sorted_array [i]->value;
1268 item->has_target_code = sorted_array [i]->has_target_code;
1269 item->is_equals = TRUE;
1271 item->check_target_idx = out_array->len + 1;
1273 item->check_target_idx = 0;
1274 g_ptr_array_add (out_array, item);
1277 int middle = start + count / 2;
1278 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1280 item->key = sorted_array [middle]->key;
1281 item->is_equals = FALSE;
1282 g_ptr_array_add (out_array, item);
1283 imt_emit_ir (sorted_array, start, middle, out_array);
1284 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1290 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1291 MONO_REQ_GC_NEUTRAL_MODE;
1293 int number_of_entries = entries->children + 1;
1294 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1295 GPtrArray *result = g_ptr_array_new ();
1296 MonoImtBuilderEntry *current_entry;
1299 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1300 sorted_array [i] = current_entry;
1302 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1304 /*for (i = 0; i < number_of_entries; i++) {
1305 print_imt_entry (" sorted array:", sorted_array [i], i);
1308 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1310 free (sorted_array);
1315 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1317 MONO_REQ_GC_NEUTRAL_MODE;
1319 if (imt_builder_entry != NULL) {
1320 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1321 /* No collision, return the vtable slot contents */
1322 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1324 /* Collision, build the thunk */
1325 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1328 result = imt_thunk_builder (vtable, domain,
1329 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1330 for (i = 0; i < imt_ir->len; ++i)
1331 g_free (g_ptr_array_index (imt_ir, i));
1332 g_ptr_array_free (imt_ir, TRUE);
1344 static MonoImtBuilderEntry*
1345 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1348 * LOCKING: requires the loader and domain locks.
1352 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1354 MONO_REQ_GC_NEUTRAL_MODE;
1358 guint32 imt_collisions_bitmap = 0;
1359 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1360 int method_count = 0;
1361 gboolean record_method_count_for_max_collisions = FALSE;
1362 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1365 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1367 for (i = 0; i < klass->interface_offsets_count; ++i) {
1368 MonoClass *iface = klass->interfaces_packed [i];
1369 int interface_offset = klass->interface_offsets_packed [i];
1370 int method_slot_in_interface, vt_slot;
1372 if (mono_class_has_variant_generic_params (iface))
1373 has_variant_iface = TRUE;
1375 mono_class_setup_methods (iface);
1376 vt_slot = interface_offset;
1377 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1380 if (slot_num >= 0 && iface->is_inflated) {
1382 * The imt slot of the method is the same as for its declaring method,
1383 * see the comment in mono_method_get_imt_slot (), so we can
1384 * avoid inflating methods which will be discarded by
1385 * add_imt_builder_entry anyway.
1387 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1388 if (mono_method_get_imt_slot (method) != slot_num) {
1393 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1394 if (method->is_generic) {
1395 has_generic_virtual = TRUE;
1400 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1401 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1406 if (extra_interfaces) {
1407 int interface_offset = klass->vtable_size;
1409 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1410 MonoClass* iface = (MonoClass *)list_item->data;
1411 int method_slot_in_interface;
1412 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1413 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1415 if (method->is_generic)
1416 has_generic_virtual = TRUE;
1417 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1419 interface_offset += iface->method.count;
1422 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1423 /* overwrite the imt slot only if we're building all the entries or if
1424 * we're building this specific one
1426 if (slot_num < 0 || i == slot_num) {
1427 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1430 if (imt_builder [i]) {
1431 MonoImtBuilderEntry *entry;
1433 /* Link entries with imt_builder [i] */
1434 for (entry = entries; entry->next; entry = entry->next) {
1436 MonoMethod *method = (MonoMethod*)entry->key;
1437 char *method_name = mono_method_full_name (method, TRUE);
1438 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1439 g_free (method_name);
1442 entry->next = imt_builder [i];
1443 entries->children += imt_builder [i]->children + 1;
1445 imt_builder [i] = entries;
1448 if (has_generic_virtual || has_variant_iface) {
1450 * There might be collisions later when the the thunk is expanded.
1452 imt_collisions_bitmap |= (1 << i);
1455 * The IMT thunk might be called with an instance of one of the
1456 * generic virtual methods, so has to fallback to the IMT trampoline.
1458 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1460 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1463 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1467 if (imt_builder [i] != NULL) {
1468 int methods_in_slot = imt_builder [i]->children + 1;
1469 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1470 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1471 record_method_count_for_max_collisions = TRUE;
1473 method_count += methods_in_slot;
1477 mono_stats.imt_number_of_methods += method_count;
1478 if (record_method_count_for_max_collisions) {
1479 mono_stats.imt_method_count_when_max_collisions = method_count;
1482 for (i = 0; i < MONO_IMT_SIZE; i++) {
1483 MonoImtBuilderEntry* entry = imt_builder [i];
1484 while (entry != NULL) {
1485 MonoImtBuilderEntry* next = entry->next;
1491 /* we OR the bitmap since we may build just a single imt slot at a time */
1492 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1496 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1497 MONO_REQ_GC_NEUTRAL_MODE;
1499 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1503 * mono_vtable_build_imt_slot:
1504 * @vtable: virtual object table struct
1505 * @imt_slot: slot in the IMT table
1507 * Fill the given @imt_slot in the IMT table of @vtable with
1508 * a trampoline or a thunk for the case of collisions.
1509 * This is part of the internal mono API.
1511 * LOCKING: Take the domain lock.
1514 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1516 MONO_REQ_GC_NEUTRAL_MODE;
1518 gpointer *imt = (gpointer*)vtable;
1519 imt -= MONO_IMT_SIZE;
1520 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1522 /* no support for extra interfaces: the proxy objects will need
1523 * to build the complete IMT
1524 * Update and heck needs to ahppen inside the proper domain lock, as all
1525 * the changes made to a MonoVTable.
1527 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1528 mono_domain_lock (vtable->domain);
1529 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1530 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1531 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1532 mono_domain_unlock (vtable->domain);
1533 mono_loader_unlock ();
1538 * The first two free list entries both belong to the wait list: The
1539 * first entry is the pointer to the head of the list and the second
1540 * entry points to the last element. That way appending and removing
1541 * the first element are both O(1) operations.
1543 #ifdef MONO_SMALL_CONFIG
1544 #define NUM_FREE_LISTS 6
1546 #define NUM_FREE_LISTS 12
1548 #define FIRST_FREE_LIST_SIZE 64
1549 #define MAX_WAIT_LENGTH 50
1550 #define THUNK_THRESHOLD 10
1553 * LOCKING: The domain lock must be held.
1556 init_thunk_free_lists (MonoDomain *domain)
1558 MONO_REQ_GC_NEUTRAL_MODE;
1560 if (domain->thunk_free_lists)
1562 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1566 list_index_for_size (int item_size)
1569 int size = FIRST_FREE_LIST_SIZE;
1571 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1580 * mono_method_alloc_generic_virtual_thunk:
1582 * @size: size in bytes
1584 * Allocs size bytes to be used for the code of a generic virtual
1585 * thunk. It's either allocated from the domain's code manager or
1586 * reused from a previously invalidated piece.
1588 * LOCKING: The domain lock must be held.
1591 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1593 MONO_REQ_GC_NEUTRAL_MODE;
1595 static gboolean inited = FALSE;
1596 static int generic_virtual_thunks_size = 0;
1600 MonoThunkFreeList **l;
1602 init_thunk_free_lists (domain);
1604 size += sizeof (guint32);
1605 if (size < sizeof (MonoThunkFreeList))
1606 size = sizeof (MonoThunkFreeList);
1608 i = list_index_for_size (size);
1609 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1610 if ((*l)->size >= size) {
1611 MonoThunkFreeList *item = *l;
1613 return ((guint32*)item) + 1;
1617 /* no suitable item found - search lists of larger sizes */
1618 while (++i < NUM_FREE_LISTS) {
1619 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1622 g_assert (item->size > size);
1623 domain->thunk_free_lists [i] = item->next;
1624 return ((guint32*)item) + 1;
1627 /* still nothing found - allocate it */
1629 mono_counters_register ("Generic virtual thunk bytes",
1630 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1633 generic_virtual_thunks_size += size;
1635 p = (guint32 *)mono_domain_code_reserve (domain, size);
1638 mono_domain_lock (domain);
1639 if (!domain->generic_virtual_thunks)
1640 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1641 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1642 mono_domain_unlock (domain);
1648 * LOCKING: The domain lock must be held.
1651 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1653 MONO_REQ_GC_NEUTRAL_MODE;
1655 guint32 *p = (guint32 *)code;
1656 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1657 gboolean found = FALSE;
1659 mono_domain_lock (domain);
1660 if (!domain->generic_virtual_thunks)
1661 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1662 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1664 mono_domain_unlock (domain);
1667 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1669 init_thunk_free_lists (domain);
1671 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1672 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1673 int length = item->length;
1676 /* unlink the first item from the wait list */
1677 domain->thunk_free_lists [0] = item->next;
1678 domain->thunk_free_lists [0]->length = length - 1;
1680 i = list_index_for_size (item->size);
1682 /* put it in the free list */
1683 item->next = domain->thunk_free_lists [i];
1684 domain->thunk_free_lists [i] = item;
1688 if (domain->thunk_free_lists [1]) {
1689 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1690 domain->thunk_free_lists [0]->length++;
1692 g_assert (!domain->thunk_free_lists [0]);
1694 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1695 domain->thunk_free_lists [0]->length = 1;
1699 typedef struct _GenericVirtualCase {
1703 struct _GenericVirtualCase *next;
1704 } GenericVirtualCase;
1707 * get_generic_virtual_entries:
1709 * Return IMT entries for the generic virtual method instances and
1710 * variant interface methods for vtable slot
1713 static MonoImtBuilderEntry*
1714 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1716 MONO_REQ_GC_NEUTRAL_MODE;
1718 GenericVirtualCase *list;
1719 MonoImtBuilderEntry *entries;
1721 mono_domain_lock (domain);
1722 if (!domain->generic_virtual_cases)
1723 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1725 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1728 for (; list; list = list->next) {
1729 MonoImtBuilderEntry *entry;
1731 if (list->count < THUNK_THRESHOLD)
1734 entry = g_new0 (MonoImtBuilderEntry, 1);
1735 entry->key = list->method;
1736 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1737 entry->has_target_code = 1;
1739 entry->children = entries->children + 1;
1740 entry->next = entries;
1744 mono_domain_unlock (domain);
1746 /* FIXME: Leaking memory ? */
1751 * mono_method_add_generic_virtual_invocation:
1753 * @vtable_slot: pointer to the vtable slot
1754 * @method: the inflated generic virtual method
1755 * @code: the method's code
1757 * Registers a call via unmanaged code to a generic virtual method
1758 * instantiation or variant interface method. If the number of calls reaches a threshold
1759 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1760 * virtual method thunk.
1763 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1764 gpointer *vtable_slot,
1765 MonoMethod *method, gpointer code)
1767 MONO_REQ_GC_NEUTRAL_MODE;
1769 static gboolean inited = FALSE;
1770 static int num_added = 0;
1772 GenericVirtualCase *gvc, *list;
1773 MonoImtBuilderEntry *entries;
1777 mono_domain_lock (domain);
1778 if (!domain->generic_virtual_cases)
1779 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1781 /* Check whether the case was already added */
1782 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1785 if (gvc->method == method)
1790 /* If not found, make a new one */
1792 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1793 gvc->method = method;
1796 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1798 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1801 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1807 if (++gvc->count == THUNK_THRESHOLD) {
1808 gpointer *old_thunk = (void **)*vtable_slot;
1809 gpointer vtable_trampoline = NULL;
1810 gpointer imt_trampoline = NULL;
1812 if ((gpointer)vtable_slot < (gpointer)vtable) {
1813 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1814 int imt_slot = MONO_IMT_SIZE + displacement;
1816 /* Force the rebuild of the thunk at the next call */
1817 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1818 *vtable_slot = imt_trampoline;
1820 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1822 entries = get_generic_virtual_entries (domain, vtable_slot);
1824 sorted = imt_sort_slot_entries (entries);
1826 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1830 MonoImtBuilderEntry *next = entries->next;
1835 for (i = 0; i < sorted->len; ++i)
1836 g_free (g_ptr_array_index (sorted, i));
1837 g_ptr_array_free (sorted, TRUE);
1840 #ifndef __native_client__
1841 /* We don't re-use any thunks as there is a lot of overhead */
1842 /* to deleting and re-using code in Native Client. */
1843 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1844 invalidate_generic_virtual_thunk (domain, old_thunk);
1848 mono_domain_unlock (domain);
1851 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1854 * mono_class_vtable:
1855 * @domain: the application domain
1856 * @class: the class to initialize
1858 * VTables are domain specific because we create domain specific code, and
1859 * they contain the domain specific static class data.
1860 * On failure, NULL is returned, and class->exception_type is set.
1863 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1866 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1867 mono_error_cleanup (&error);
1872 * mono_class_vtable_full:
1873 * @domain: the application domain
1874 * @class: the class to initialize
1875 * @error set on failure.
1877 * VTables are domain specific because we create domain specific code, and
1878 * they contain the domain specific static class data.
1881 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1883 MONO_REQ_GC_UNSAFE_MODE;
1885 MonoClassRuntimeInfo *runtime_info;
1887 mono_error_init (error);
1891 if (mono_class_has_failure (klass)) {
1892 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1896 /* this check can be inlined in jitted code, too */
1897 runtime_info = klass->runtime_info;
1898 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1899 return runtime_info->domain_vtables [domain->domain_id];
1900 return mono_class_create_runtime_vtable (domain, klass, error);
1904 * mono_class_try_get_vtable:
1905 * @domain: the application domain
1906 * @class: the class to initialize
1908 * This function tries to get the associated vtable from @class if
1909 * it was already created.
1912 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1914 MONO_REQ_GC_NEUTRAL_MODE;
1916 MonoClassRuntimeInfo *runtime_info;
1920 runtime_info = klass->runtime_info;
1921 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1922 return runtime_info->domain_vtables [domain->domain_id];
1927 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1929 MONO_REQ_GC_NEUTRAL_MODE;
1931 size_t alloc_offset;
1934 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1935 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1936 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1938 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1939 g_assert ((imt_table_bytes & 7) == 4);
1946 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1950 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1952 MONO_REQ_GC_UNSAFE_MODE;
1955 MonoClassRuntimeInfo *runtime_info, *old_info;
1956 MonoClassField *field;
1958 int i, vtable_slots;
1959 size_t imt_table_bytes;
1961 guint32 vtable_size, class_size;
1963 gpointer *interface_offsets;
1965 mono_error_init (error);
1967 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1968 mono_domain_lock (domain);
1969 runtime_info = klass->runtime_info;
1970 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1971 mono_domain_unlock (domain);
1972 mono_loader_unlock ();
1973 return runtime_info->domain_vtables [domain->domain_id];
1975 if (!klass->inited || mono_class_has_failure (klass)) {
1976 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1977 mono_domain_unlock (domain);
1978 mono_loader_unlock ();
1979 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1984 /* Array types require that their element type be valid*/
1985 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1986 MonoClass *element_class = klass->element_class;
1987 if (!element_class->inited)
1988 mono_class_init (element_class);
1990 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1991 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1992 mono_class_setup_vtable (element_class);
1994 if (mono_class_has_failure (element_class)) {
1995 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1996 if (!mono_class_has_failure (klass))
1997 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1998 mono_domain_unlock (domain);
1999 mono_loader_unlock ();
2000 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2006 * For some classes, mono_class_init () already computed klass->vtable_size, and
2007 * that is all that is needed because of the vtable trampolines.
2009 if (!klass->vtable_size)
2010 mono_class_setup_vtable (klass);
2012 if (klass->generic_class && !klass->vtable)
2013 mono_class_check_vtable_constraints (klass, NULL);
2015 /* Initialize klass->has_finalize */
2016 mono_class_has_finalizer (klass);
2018 if (mono_class_has_failure (klass)) {
2019 mono_domain_unlock (domain);
2020 mono_loader_unlock ();
2021 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2025 vtable_slots = klass->vtable_size;
2026 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2027 class_size = mono_class_data_size (klass);
2031 if (klass->interface_offsets_count) {
2032 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2033 mono_stats.imt_number_of_tables++;
2034 mono_stats.imt_tables_size += imt_table_bytes;
2036 imt_table_bytes = 0;
2039 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2041 mono_stats.used_class_count++;
2042 mono_stats.class_vtable_size += vtable_size;
2044 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2045 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2046 g_assert (!((gsize)vt & 7));
2049 vt->rank = klass->rank;
2050 vt->domain = domain;
2052 mono_class_compute_gc_descriptor (klass);
2054 * We can't use typed allocation in the non-root domains, since the
2055 * collector needs the GC descriptor stored in the vtable even after
2056 * the mempool containing the vtable is destroyed when the domain is
2057 * unloaded. An alternative might be to allocate vtables in the GC
2058 * heap, but this does not seem to work (it leads to crashes inside
2059 * libgc). If that approach is tried, two gc descriptors need to be
2060 * allocated for each class: one for the root domain, and one for all
2061 * other domains. The second descriptor should contain a bit for the
2062 * vtable field in MonoObject, since we can no longer assume the
2063 * vtable is reachable by other roots after the appdomain is unloaded.
2065 #ifdef HAVE_BOEHM_GC
2066 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2067 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2070 vt->gc_descr = klass->gc_descr;
2072 gc_bits = mono_gc_get_vtable_bits (klass);
2073 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2075 vt->gc_bits = gc_bits;
2078 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2079 if (klass->has_static_refs) {
2080 MonoGCDescriptor statics_gc_descr;
2082 gsize default_bitmap [4] = {0};
2085 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2086 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2087 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2088 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2089 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2090 if (bitmap != default_bitmap)
2093 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2095 vt->has_static_fields = TRUE;
2096 mono_stats.class_static_data_size += class_size;
2100 while ((field = mono_class_get_fields (klass, &iter))) {
2101 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2103 if (mono_field_is_deleted (field))
2105 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2106 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2107 if (special_static != SPECIAL_STATIC_NONE) {
2108 guint32 size, offset;
2110 gsize default_bitmap [4] = {0};
2115 if (mono_type_is_reference (field->type)) {
2116 default_bitmap [0] = 1;
2118 bitmap = default_bitmap;
2119 } else if (mono_type_is_struct (field->type)) {
2120 fclass = mono_class_from_mono_type (field->type);
2121 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2122 numbits = max_set + 1;
2124 default_bitmap [0] = 0;
2126 bitmap = default_bitmap;
2128 size = mono_type_size (field->type, &align);
2129 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2130 if (!domain->special_static_fields)
2131 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2132 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2133 if (bitmap != default_bitmap)
2136 * This marks the field as special static to speed up the
2137 * checks in mono_field_static_get/set_value ().
2143 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2144 MonoClass *fklass = mono_class_from_mono_type (field->type);
2145 const char *data = mono_field_get_data (field);
2147 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2148 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2149 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2152 if (fklass->valuetype) {
2153 memcpy (t, data, mono_class_value_size (fklass, NULL));
2155 /* it's a pointer type: add check */
2156 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2163 vt->max_interface_id = klass->max_interface_id;
2164 vt->interface_bitmap = klass->interface_bitmap;
2166 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2167 // class->name, klass->interface_offsets_count);
2169 /* Initialize vtable */
2170 if (callbacks.get_vtable_trampoline) {
2171 // This also covers the AOT case
2172 for (i = 0; i < klass->vtable_size; ++i) {
2173 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2176 mono_class_setup_vtable (klass);
2178 for (i = 0; i < klass->vtable_size; ++i) {
2181 cm = klass->vtable [i];
2183 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2184 if (!is_ok (error)) {
2185 mono_domain_unlock (domain);
2186 mono_loader_unlock ();
2193 if (imt_table_bytes) {
2194 /* Now that the vtable is full, we can actually fill up the IMT */
2195 for (i = 0; i < MONO_IMT_SIZE; ++i)
2196 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2200 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2201 * re-acquire them and check if another thread has created the vtable in the meantime.
2203 /* Special case System.MonoType to avoid infinite recursion */
2204 if (klass != mono_defaults.monotype_class) {
2205 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2206 if (!is_ok (error)) {
2207 mono_domain_unlock (domain);
2208 mono_loader_unlock ();
2212 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2213 /* This is unregistered in
2214 unregister_vtable_reflection_type() in
2216 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2219 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2221 /* class_vtable_array keeps an array of created vtables
2223 g_ptr_array_add (domain->class_vtable_array, vt);
2224 /* klass->runtime_info is protected by the loader lock, both when
2225 * it it enlarged and when it is stored info.
2229 * Store the vtable in klass->runtime_info.
2230 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2232 mono_memory_barrier ();
2234 old_info = klass->runtime_info;
2235 if (old_info && old_info->max_domain >= domain->domain_id) {
2236 /* someone already created a large enough runtime info */
2237 old_info->domain_vtables [domain->domain_id] = vt;
2239 int new_size = domain->domain_id;
2241 new_size = MAX (new_size, old_info->max_domain);
2243 /* make the new size a power of two */
2245 while (new_size > i)
2248 /* this is a bounded memory retention issue: may want to
2249 * handle it differently when we'll have a rcu-like system.
2251 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2252 runtime_info->max_domain = new_size - 1;
2253 /* copy the stuff from the older info */
2255 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2257 runtime_info->domain_vtables [domain->domain_id] = vt;
2259 mono_memory_barrier ();
2260 klass->runtime_info = runtime_info;
2263 if (klass == mono_defaults.monotype_class) {
2264 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2265 if (!is_ok (error)) {
2266 mono_domain_unlock (domain);
2267 mono_loader_unlock ();
2271 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2272 /* This is unregistered in
2273 unregister_vtable_reflection_type() in
2275 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2278 mono_domain_unlock (domain);
2279 mono_loader_unlock ();
2281 /* make sure the parent is initialized */
2282 /*FIXME shouldn't this fail the current type?*/
2284 mono_class_vtable_full (domain, klass->parent, error);
2289 #ifndef DISABLE_REMOTING
2291 * mono_class_proxy_vtable:
2292 * @domain: the application domain
2293 * @remove_class: the remote class
2295 * Creates a vtable for transparent proxies. It is basically
2296 * a copy of the real vtable of the class wrapped in @remote_class,
2297 * but all function pointers invoke the remoting functions, and
2298 * vtable->klass points to the transparent proxy class, and not to @class.
2301 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2303 MONO_REQ_GC_UNSAFE_MODE;
2306 MonoVTable *vt, *pvt;
2307 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2309 GSList *extra_interfaces = NULL;
2310 MonoClass *klass = remote_class->proxy_class;
2311 gpointer *interface_offsets;
2314 size_t imt_table_bytes;
2316 #ifdef COMPRESSED_INTERFACE_BITMAP
2320 vt = mono_class_vtable (domain, klass);
2321 g_assert (vt); /*FIXME property handle failure*/
2322 max_interface_id = vt->max_interface_id;
2324 /* Calculate vtable space for extra interfaces */
2325 for (j = 0; j < remote_class->interface_count; j++) {
2326 MonoClass* iclass = remote_class->interfaces[j];
2330 /*FIXME test for interfaces with variant generic arguments*/
2331 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2332 continue; /* interface implemented by the class */
2333 if (g_slist_find (extra_interfaces, iclass))
2336 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2338 method_count = mono_class_num_methods (iclass);
2340 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2341 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2343 for (i = 0; i < ifaces->len; ++i) {
2344 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2345 /*FIXME test for interfaces with variant generic arguments*/
2346 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2347 continue; /* interface implemented by the class */
2348 if (g_slist_find (extra_interfaces, ic))
2350 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2351 method_count += mono_class_num_methods (ic);
2353 g_ptr_array_free (ifaces, TRUE);
2356 extra_interface_vtsize += method_count * sizeof (gpointer);
2357 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2360 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2361 mono_stats.imt_number_of_tables++;
2362 mono_stats.imt_tables_size += imt_table_bytes;
2364 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2366 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2368 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2369 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2370 g_assert (!((gsize)pvt & 7));
2372 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2374 pvt->klass = mono_defaults.transparent_proxy_class;
2375 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2376 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2378 /* initialize vtable */
2379 mono_class_setup_vtable (klass);
2380 for (i = 0; i < klass->vtable_size; ++i) {
2383 if ((cm = klass->vtable [i]))
2384 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2386 pvt->vtable [i] = NULL;
2389 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2390 /* create trampolines for abstract methods */
2391 for (k = klass; k; k = k->parent) {
2393 gpointer iter = NULL;
2394 while ((m = mono_class_get_methods (k, &iter)))
2395 if (!pvt->vtable [m->slot])
2396 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2400 pvt->max_interface_id = max_interface_id;
2401 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2402 #ifdef COMPRESSED_INTERFACE_BITMAP
2403 bitmap = (uint8_t *)g_malloc0 (bsize);
2405 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2408 for (i = 0; i < klass->interface_offsets_count; ++i) {
2409 int interface_id = klass->interfaces_packed [i]->interface_id;
2410 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2413 if (extra_interfaces) {
2414 int slot = klass->vtable_size;
2420 /* Create trampolines for the methods of the interfaces */
2421 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2422 interf = (MonoClass *)list_item->data;
2424 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2428 while ((cm = mono_class_get_methods (interf, &iter)))
2429 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2431 slot += mono_class_num_methods (interf);
2435 /* Now that the vtable is full, we can actually fill up the IMT */
2436 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2437 if (extra_interfaces) {
2438 g_slist_free (extra_interfaces);
2441 #ifdef COMPRESSED_INTERFACE_BITMAP
2442 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2443 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2444 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2447 pvt->interface_bitmap = bitmap;
2452 #endif /* DISABLE_REMOTING */
2455 * mono_class_field_is_special_static:
2457 * Returns whether @field is a thread/context static field.
2460 mono_class_field_is_special_static (MonoClassField *field)
2462 MONO_REQ_GC_NEUTRAL_MODE
2464 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2466 if (mono_field_is_deleted (field))
2468 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2469 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2476 * mono_class_field_get_special_static_type:
2477 * @field: The MonoClassField describing the field.
2479 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2480 * SPECIAL_STATIC_NONE otherwise.
2483 mono_class_field_get_special_static_type (MonoClassField *field)
2485 MONO_REQ_GC_NEUTRAL_MODE
2487 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2488 return SPECIAL_STATIC_NONE;
2489 if (mono_field_is_deleted (field))
2490 return SPECIAL_STATIC_NONE;
2491 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2492 return field_is_special_static (field->parent, field);
2493 return SPECIAL_STATIC_NONE;
2497 * mono_class_has_special_static_fields:
2499 * Returns whenever @klass has any thread/context static fields.
2502 mono_class_has_special_static_fields (MonoClass *klass)
2504 MONO_REQ_GC_NEUTRAL_MODE
2506 MonoClassField *field;
2510 while ((field = mono_class_get_fields (klass, &iter))) {
2511 g_assert (field->parent == klass);
2512 if (mono_class_field_is_special_static (field))
2519 #ifndef DISABLE_REMOTING
2521 * create_remote_class_key:
2522 * Creates an array of pointers that can be used as a hash key for a remote class.
2523 * The first element of the array is the number of pointers.
2526 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2528 MONO_REQ_GC_NEUTRAL_MODE;
2533 if (remote_class == NULL) {
2534 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2535 key = (void **)g_malloc (sizeof(gpointer) * 3);
2536 key [0] = GINT_TO_POINTER (2);
2537 key [1] = mono_defaults.marshalbyrefobject_class;
2538 key [2] = extra_class;
2540 key = (void **)g_malloc (sizeof(gpointer) * 2);
2541 key [0] = GINT_TO_POINTER (1);
2542 key [1] = extra_class;
2545 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2546 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2547 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2548 key [1] = remote_class->proxy_class;
2550 // Keep the list of interfaces sorted
2551 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2552 if (extra_class && remote_class->interfaces [i] > extra_class) {
2553 key [j++] = extra_class;
2556 key [j] = remote_class->interfaces [i];
2559 key [j] = extra_class;
2561 // Replace the old class. The interface list is the same
2562 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2563 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2564 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2565 for (i = 0; i < remote_class->interface_count; i++)
2566 key [2 + i] = remote_class->interfaces [i];
2574 * copy_remote_class_key:
2576 * Make a copy of KEY in the domain and return the copy.
2579 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2581 MONO_REQ_GC_NEUTRAL_MODE
2583 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2584 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2586 memcpy (mp_key, key, key_size);
2592 * mono_remote_class:
2593 * @domain: the application domain
2594 * @class_name: name of the remote class
2595 * @error: set on error
2597 * Creates and initializes a MonoRemoteClass object for a remote type.
2599 * On failure returns NULL and sets @error
2602 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2604 MONO_REQ_GC_UNSAFE_MODE;
2606 MonoRemoteClass *rc;
2607 gpointer* key, *mp_key;
2610 mono_error_init (error);
2612 key = create_remote_class_key (NULL, proxy_class);
2614 mono_domain_lock (domain);
2615 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2619 mono_domain_unlock (domain);
2623 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2624 if (!is_ok (error)) {
2626 mono_domain_unlock (domain);
2630 mp_key = copy_remote_class_key (domain, key);
2634 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2635 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2636 rc->interface_count = 1;
2637 rc->interfaces [0] = proxy_class;
2638 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2640 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2641 rc->interface_count = 0;
2642 rc->proxy_class = proxy_class;
2645 rc->default_vtable = NULL;
2646 rc->xdomain_vtable = NULL;
2647 rc->proxy_class_name = name;
2648 #ifndef DISABLE_PERFCOUNTERS
2649 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2652 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2654 mono_domain_unlock (domain);
2659 * clone_remote_class:
2660 * Creates a copy of the remote_class, adding the provided class or interface
2662 static MonoRemoteClass*
2663 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2665 MONO_REQ_GC_NEUTRAL_MODE;
2667 MonoRemoteClass *rc;
2668 gpointer* key, *mp_key;
2670 key = create_remote_class_key (remote_class, extra_class);
2671 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2677 mp_key = copy_remote_class_key (domain, key);
2681 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2683 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2684 rc->proxy_class = remote_class->proxy_class;
2685 rc->interface_count = remote_class->interface_count + 1;
2687 // Keep the list of interfaces sorted, since the hash key of
2688 // the remote class depends on this
2689 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2690 if (remote_class->interfaces [i] > extra_class && i == j)
2691 rc->interfaces [j++] = extra_class;
2692 rc->interfaces [j] = remote_class->interfaces [i];
2695 rc->interfaces [j] = extra_class;
2697 // Replace the old class. The interface array is the same
2698 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2699 rc->proxy_class = extra_class;
2700 rc->interface_count = remote_class->interface_count;
2701 if (rc->interface_count > 0)
2702 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2705 rc->default_vtable = NULL;
2706 rc->xdomain_vtable = NULL;
2707 rc->proxy_class_name = remote_class->proxy_class_name;
2709 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2715 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2717 MONO_REQ_GC_UNSAFE_MODE;
2719 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2720 mono_domain_lock (domain);
2721 if (rp->target_domain_id != -1) {
2722 if (remote_class->xdomain_vtable == NULL)
2723 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2724 mono_domain_unlock (domain);
2725 mono_loader_unlock ();
2726 return remote_class->xdomain_vtable;
2728 if (remote_class->default_vtable == NULL) {
2731 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2732 klass = mono_class_from_mono_type (type);
2734 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)))
2735 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2738 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2741 mono_domain_unlock (domain);
2742 mono_loader_unlock ();
2743 return remote_class->default_vtable;
2747 * mono_upgrade_remote_class:
2748 * @domain: the application domain
2749 * @tproxy: the proxy whose remote class has to be upgraded.
2750 * @klass: class to which the remote class can be casted.
2752 * Updates the vtable of the remote class by adding the necessary method slots
2753 * and interface offsets so it can be safely casted to klass. klass can be a
2754 * class or an interface.
2757 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2759 MONO_REQ_GC_UNSAFE_MODE;
2761 MonoTransparentProxy *tproxy;
2762 MonoRemoteClass *remote_class;
2763 gboolean redo_vtable;
2765 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2766 mono_domain_lock (domain);
2768 tproxy = (MonoTransparentProxy*) proxy_object;
2769 remote_class = tproxy->remote_class;
2771 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2774 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2775 if (remote_class->interfaces [i] == klass)
2776 redo_vtable = FALSE;
2779 redo_vtable = (remote_class->proxy_class != klass);
2783 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2784 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2787 mono_domain_unlock (domain);
2788 mono_loader_unlock ();
2790 #endif /* DISABLE_REMOTING */
2794 * mono_object_get_virtual_method:
2795 * @obj: object to operate on.
2798 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2799 * the instance of a callvirt of method.
2802 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2804 MONO_REQ_GC_UNSAFE_MODE;
2807 MonoMethod **vtable;
2808 gboolean is_proxy = FALSE;
2809 MonoMethod *res = NULL;
2811 klass = mono_object_class (obj);
2812 #ifndef DISABLE_REMOTING
2813 if (klass == mono_defaults.transparent_proxy_class) {
2814 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2819 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2822 mono_class_setup_vtable (klass);
2823 vtable = klass->vtable;
2825 if (method->slot == -1) {
2826 /* method->slot might not be set for instances of generic methods */
2827 if (method->is_inflated) {
2828 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2829 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2832 g_assert_not_reached ();
2836 /* check method->slot is a valid index: perform isinstance? */
2837 if (method->slot != -1) {
2838 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2840 gboolean variance_used = FALSE;
2841 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2842 g_assert (iface_offset > 0);
2843 res = vtable [iface_offset + method->slot];
2846 res = vtable [method->slot];
2850 #ifndef DISABLE_REMOTING
2852 /* It may be an interface, abstract class method or generic method */
2853 if (!res || mono_method_signature (res)->generic_param_count)
2856 /* generic methods demand invoke_with_check */
2857 if (mono_method_signature (res)->generic_param_count)
2858 res = mono_marshal_get_remoting_invoke_with_check (res);
2861 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2862 res = mono_cominterop_get_invoke (res);
2865 res = mono_marshal_get_remoting_invoke (res);
2870 if (method->is_inflated) {
2872 /* Have to inflate the result */
2873 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2874 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2884 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2886 MONO_REQ_GC_UNSAFE_MODE;
2888 MonoObject *result = NULL;
2890 g_assert (callbacks.runtime_invoke);
2892 mono_error_init (error);
2894 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2895 mono_profiler_method_start_invoke (method);
2897 MONO_PREPARE_RESET_BLOCKING;
2899 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2901 MONO_FINISH_RESET_BLOCKING;
2903 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2904 mono_profiler_method_end_invoke (method);
2906 if (!mono_error_ok (error))
2913 * mono_runtime_invoke:
2914 * @method: method to invoke
2915 * @obJ: object instance
2916 * @params: arguments to the method
2917 * @exc: exception information.
2919 * Invokes the method represented by @method on the object @obj.
2921 * obj is the 'this' pointer, it should be NULL for static
2922 * methods, a MonoObject* for object instances and a pointer to
2923 * the value type for value types.
2925 * The params array contains the arguments to the method with the
2926 * same convention: MonoObject* pointers for object instances and
2927 * pointers to the value type otherwise.
2929 * From unmanaged code you'll usually use the
2930 * mono_runtime_invoke() variant.
2932 * Note that this function doesn't handle virtual methods for
2933 * you, it will exec the exact method you pass: we still need to
2934 * expose a function to lookup the derived class implementation
2935 * of a virtual method (there are examples of this in the code,
2938 * You can pass NULL as the exc argument if you don't want to
2939 * catch exceptions, otherwise, *exc will be set to the exception
2940 * thrown, if any. if an exception is thrown, you can't use the
2941 * MonoObject* result from the function.
2943 * If the method returns a value type, it is boxed in an object
2947 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2952 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2953 if (*exc == NULL && !mono_error_ok(&error)) {
2954 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2956 mono_error_cleanup (&error);
2958 res = mono_runtime_invoke_checked (method, obj, params, &error);
2959 mono_error_raise_exception (&error);
2965 * mono_runtime_try_invoke:
2966 * @method: method to invoke
2967 * @obJ: object instance
2968 * @params: arguments to the method
2969 * @exc: exception information.
2970 * @error: set on error
2972 * Invokes the method represented by @method on the object @obj.
2974 * obj is the 'this' pointer, it should be NULL for static
2975 * methods, a MonoObject* for object instances and a pointer to
2976 * the value type for value types.
2978 * The params array contains the arguments to the method with the
2979 * same convention: MonoObject* pointers for object instances and
2980 * pointers to the value type otherwise.
2982 * From unmanaged code you'll usually use the
2983 * mono_runtime_invoke() variant.
2985 * Note that this function doesn't handle virtual methods for
2986 * you, it will exec the exact method you pass: we still need to
2987 * expose a function to lookup the derived class implementation
2988 * of a virtual method (there are examples of this in the code,
2991 * For this function, you must not pass NULL as the exc argument if
2992 * you don't want to catch exceptions, use
2993 * mono_runtime_invoke_checked(). If an exception is thrown, you
2994 * can't use the MonoObject* result from the function.
2996 * If this method cannot be invoked, @error will be set and @exc and
2997 * the return value must not be used.
2999 * If the method returns a value type, it is boxed in an object
3003 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3005 MONO_REQ_GC_UNSAFE_MODE;
3007 g_assert (exc != NULL);
3009 if (mono_runtime_get_no_exec ())
3010 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3012 return do_runtime_invoke (method, obj, params, exc, error);
3016 * mono_runtime_invoke_checked:
3017 * @method: method to invoke
3018 * @obJ: object instance
3019 * @params: arguments to the method
3020 * @error: set on error
3022 * Invokes the method represented by @method on the object @obj.
3024 * obj is the 'this' pointer, it should be NULL for static
3025 * methods, a MonoObject* for object instances and a pointer to
3026 * the value type for value types.
3028 * The params array contains the arguments to the method with the
3029 * same convention: MonoObject* pointers for object instances and
3030 * pointers to the value type otherwise.
3032 * From unmanaged code you'll usually use the
3033 * mono_runtime_invoke() variant.
3035 * Note that this function doesn't handle virtual methods for
3036 * you, it will exec the exact method you pass: we still need to
3037 * expose a function to lookup the derived class implementation
3038 * of a virtual method (there are examples of this in the code,
3041 * If an exception is thrown, you can't use the MonoObject* result
3042 * from the function.
3044 * If this method cannot be invoked, @error will be set. If the
3045 * method throws an exception (and we're in coop mode) the exception
3046 * will be set in @error.
3048 * If the method returns a value type, it is boxed in an object
3052 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3054 MONO_REQ_GC_UNSAFE_MODE;
3056 if (mono_runtime_get_no_exec ())
3057 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3059 return do_runtime_invoke (method, obj, params, NULL, error);
3063 * mono_method_get_unmanaged_thunk:
3064 * @method: method to generate a thunk for.
3066 * Returns an unmanaged->managed thunk that can be used to call
3067 * a managed method directly from C.
3069 * The thunk's C signature closely matches the managed signature:
3071 * C#: public bool Equals (object obj);
3072 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3073 * MonoObject*, MonoException**);
3075 * The 1st ("this") parameter must not be used with static methods:
3077 * C#: public static bool ReferenceEquals (object a, object b);
3078 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3081 * The last argument must be a non-null pointer of a MonoException* pointer.
3082 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3083 * exception has been thrown in managed code. Otherwise it will point
3084 * to the MonoException* caught by the thunk. In this case, the result of
3085 * the thunk is undefined:
3087 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3088 * MonoException *ex = NULL;
3089 * Equals func = mono_method_get_unmanaged_thunk (method);
3090 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3092 * // handle exception
3095 * The calling convention of the thunk matches the platform's default
3096 * convention. This means that under Windows, C declarations must
3097 * contain the __stdcall attribute:
3099 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3100 * MonoObject*, MonoException**);
3104 * Value type arguments and return values are treated as they were objects:
3106 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3107 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3109 * Arguments must be properly boxed upon trunk's invocation, while return
3110 * values must be unboxed.
3113 mono_method_get_unmanaged_thunk (MonoMethod *method)
3115 MONO_REQ_GC_NEUTRAL_MODE;
3116 MONO_REQ_API_ENTRYPOINT;
3120 MONO_PREPARE_RESET_BLOCKING;
3121 method = mono_marshal_get_thunk_invoke_wrapper (method);
3122 res = mono_compile_method (method);
3123 MONO_FINISH_RESET_BLOCKING;
3129 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3131 MONO_REQ_GC_UNSAFE_MODE;
3135 /* object fields cannot be byref, so we don't need a
3137 gpointer *p = (gpointer*)dest;
3144 case MONO_TYPE_BOOLEAN:
3146 case MONO_TYPE_U1: {
3147 guint8 *p = (guint8*)dest;
3148 *p = value ? *(guint8*)value : 0;
3153 case MONO_TYPE_CHAR: {
3154 guint16 *p = (guint16*)dest;
3155 *p = value ? *(guint16*)value : 0;
3158 #if SIZEOF_VOID_P == 4
3163 case MONO_TYPE_U4: {
3164 gint32 *p = (gint32*)dest;
3165 *p = value ? *(gint32*)value : 0;
3168 #if SIZEOF_VOID_P == 8
3173 case MONO_TYPE_U8: {
3174 gint64 *p = (gint64*)dest;
3175 *p = value ? *(gint64*)value : 0;
3178 case MONO_TYPE_R4: {
3179 float *p = (float*)dest;
3180 *p = value ? *(float*)value : 0;
3183 case MONO_TYPE_R8: {
3184 double *p = (double*)dest;
3185 *p = value ? *(double*)value : 0;
3188 case MONO_TYPE_STRING:
3189 case MONO_TYPE_SZARRAY:
3190 case MONO_TYPE_CLASS:
3191 case MONO_TYPE_OBJECT:
3192 case MONO_TYPE_ARRAY:
3193 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3195 case MONO_TYPE_FNPTR:
3196 case MONO_TYPE_PTR: {
3197 gpointer *p = (gpointer*)dest;
3198 *p = deref_pointer? *(gpointer*)value: value;
3201 case MONO_TYPE_VALUETYPE:
3202 /* note that 't' and 'type->type' can be different */
3203 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3204 t = mono_class_enum_basetype (type->data.klass)->type;
3207 MonoClass *klass = mono_class_from_mono_type (type);
3208 int size = mono_class_value_size (klass, NULL);
3210 mono_gc_bzero_atomic (dest, size);
3212 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3215 case MONO_TYPE_GENERICINST:
3216 t = type->data.generic_class->container_class->byval_arg.type;
3219 g_error ("got type %x", type->type);
3224 * mono_field_set_value:
3225 * @obj: Instance object
3226 * @field: MonoClassField describing the field to set
3227 * @value: The value to be set
3229 * Sets the value of the field described by @field in the object instance @obj
3230 * to the value passed in @value. This method should only be used for instance
3231 * fields. For static fields, use mono_field_static_set_value.
3233 * The value must be on the native format of the field type.
3236 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3238 MONO_REQ_GC_UNSAFE_MODE;
3242 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3244 dest = (char*)obj + field->offset;
3245 mono_copy_value (field->type, dest, value, FALSE);
3249 * mono_field_static_set_value:
3250 * @field: MonoClassField describing the field to set
3251 * @value: The value to be set
3253 * Sets the value of the static field described by @field
3254 * to the value passed in @value.
3256 * The value must be on the native format of the field type.
3259 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3261 MONO_REQ_GC_UNSAFE_MODE;
3265 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3266 /* you cant set a constant! */
3267 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3269 if (field->offset == -1) {
3270 /* Special static */
3273 mono_domain_lock (vt->domain);
3274 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3275 mono_domain_unlock (vt->domain);
3276 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3278 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3280 mono_copy_value (field->type, dest, value, FALSE);
3284 * mono_vtable_get_static_field_data:
3286 * Internal use function: return a pointer to the memory holding the static fields
3287 * for a class or NULL if there are no static fields.
3288 * This is exported only for use by the debugger.
3291 mono_vtable_get_static_field_data (MonoVTable *vt)
3293 MONO_REQ_GC_NEUTRAL_MODE
3295 if (!vt->has_static_fields)
3297 return vt->vtable [vt->klass->vtable_size];
3301 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3303 MONO_REQ_GC_UNSAFE_MODE;
3307 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3308 if (field->offset == -1) {
3309 /* Special static */
3312 mono_domain_lock (vt->domain);
3313 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3314 mono_domain_unlock (vt->domain);
3315 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3317 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3320 src = (guint8*)obj + field->offset;
3327 * mono_field_get_value:
3328 * @obj: Object instance
3329 * @field: MonoClassField describing the field to fetch information from
3330 * @value: pointer to the location where the value will be stored
3332 * Use this routine to get the value of the field @field in the object
3335 * The pointer provided by value must be of the field type, for reference
3336 * types this is a MonoObject*, for value types its the actual pointer to
3341 * mono_field_get_value (obj, int_field, &i);
3344 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3346 MONO_REQ_GC_UNSAFE_MODE;
3352 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3354 src = (char*)obj + field->offset;
3355 mono_copy_value (field->type, value, src, TRUE);
3359 * mono_field_get_value_object:
3360 * @domain: domain where the object will be created (if boxing)
3361 * @field: MonoClassField describing the field to fetch information from
3362 * @obj: The object instance for the field.
3364 * Returns: a new MonoObject with the value from the given field. If the
3365 * field represents a value type, the value is boxed.
3369 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3372 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3373 mono_error_assert_ok (&error);
3378 * mono_field_get_value_object_checked:
3379 * @domain: domain where the object will be created (if boxing)
3380 * @field: MonoClassField describing the field to fetch information from
3381 * @obj: The object instance for the field.
3382 * @error: Set on error.
3384 * Returns: a new MonoObject with the value from the given field. If the
3385 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3389 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3391 MONO_REQ_GC_UNSAFE_MODE;
3393 mono_error_init (error);
3397 MonoVTable *vtable = NULL;
3399 gboolean is_static = FALSE;
3400 gboolean is_ref = FALSE;
3401 gboolean is_literal = FALSE;
3402 gboolean is_ptr = FALSE;
3403 MonoType *type = mono_field_get_type_checked (field, error);
3405 return_val_if_nok (error, NULL);
3407 switch (type->type) {
3408 case MONO_TYPE_STRING:
3409 case MONO_TYPE_OBJECT:
3410 case MONO_TYPE_CLASS:
3411 case MONO_TYPE_ARRAY:
3412 case MONO_TYPE_SZARRAY:
3417 case MONO_TYPE_BOOLEAN:
3420 case MONO_TYPE_CHAR:
3429 case MONO_TYPE_VALUETYPE:
3430 is_ref = type->byref;
3432 case MONO_TYPE_GENERICINST:
3433 is_ref = !mono_type_generic_inst_is_valuetype (type);
3439 g_error ("type 0x%x not handled in "
3440 "mono_field_get_value_object", type->type);
3444 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3447 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3451 vtable = mono_class_vtable_full (domain, field->parent, error);
3452 return_val_if_nok (error, NULL);
3454 if (!vtable->initialized) {
3455 mono_runtime_class_init_full (vtable, error);
3456 return_val_if_nok (error, NULL);
3465 get_default_field_value (domain, field, &o);
3466 } else if (is_static) {
3467 mono_field_static_get_value (vtable, field, &o);
3469 mono_field_get_value (obj, field, &o);
3475 static MonoMethod *m;
3481 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3482 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3488 get_default_field_value (domain, field, v);
3489 } else if (is_static) {
3490 mono_field_static_get_value (vtable, field, v);
3492 mono_field_get_value (obj, field, v);
3495 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3496 args [0] = ptr ? *ptr : NULL;
3497 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3498 return_val_if_nok (error, NULL);
3500 o = mono_runtime_invoke_checked (m, NULL, args, error);
3501 return_val_if_nok (error, NULL);
3506 /* boxed value type */
3507 klass = mono_class_from_mono_type (type);
3509 if (mono_class_is_nullable (klass))
3510 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3512 o = mono_object_new_checked (domain, klass, error);
3513 return_val_if_nok (error, NULL);
3514 v = ((gchar *) o) + sizeof (MonoObject);
3517 get_default_field_value (domain, field, v);
3518 } else if (is_static) {
3519 mono_field_static_get_value (vtable, field, v);
3521 mono_field_get_value (obj, field, v);
3528 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3530 MONO_REQ_GC_UNSAFE_MODE;
3533 const char *p = blob;
3534 mono_metadata_decode_blob_size (p, &p);
3537 case MONO_TYPE_BOOLEAN:
3540 *(guint8 *) value = *p;
3542 case MONO_TYPE_CHAR:
3545 *(guint16*) value = read16 (p);
3549 *(guint32*) value = read32 (p);
3553 *(guint64*) value = read64 (p);
3556 readr4 (p, (float*) value);
3559 readr8 (p, (double*) value);
3561 case MONO_TYPE_STRING:
3562 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3564 case MONO_TYPE_CLASS:
3565 *(gpointer*) value = NULL;
3569 g_warning ("type 0x%02x should not be in constant table", type);
3575 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3577 MONO_REQ_GC_NEUTRAL_MODE;
3579 MonoTypeEnum def_type;
3582 data = mono_class_get_field_default_value (field, &def_type);
3583 mono_get_constant_value_from_blob (domain, def_type, data, value);
3587 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3589 MONO_REQ_GC_UNSAFE_MODE;
3593 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3595 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3596 get_default_field_value (vt->domain, field, value);
3600 if (field->offset == -1) {
3601 /* Special static */
3602 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3603 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3605 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3607 mono_copy_value (field->type, value, src, TRUE);
3611 * mono_field_static_get_value:
3612 * @vt: vtable to the object
3613 * @field: MonoClassField describing the field to fetch information from
3614 * @value: where the value is returned
3616 * Use this routine to get the value of the static field @field value.
3618 * The pointer provided by value must be of the field type, for reference
3619 * types this is a MonoObject*, for value types its the actual pointer to
3624 * mono_field_static_get_value (vt, int_field, &i);
3627 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3629 MONO_REQ_GC_NEUTRAL_MODE;
3631 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3635 * mono_property_set_value:
3636 * @prop: MonoProperty to set
3637 * @obj: instance object on which to act
3638 * @params: parameters to pass to the propery
3639 * @exc: optional exception
3641 * Invokes the property's set method with the given arguments on the
3642 * object instance obj (or NULL for static properties).
3644 * You can pass NULL as the exc argument if you don't want to
3645 * catch exceptions, otherwise, *exc will be set to the exception
3646 * thrown, if any. if an exception is thrown, you can't use the
3647 * MonoObject* result from the function.
3650 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3652 MONO_REQ_GC_UNSAFE_MODE;
3655 do_runtime_invoke (prop->set, obj, params, exc, &error);
3656 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3657 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3659 mono_error_raise_exception (&error); /* FIXME don't raise here */
3664 * mono_property_get_value:
3665 * @prop: MonoProperty to fetch
3666 * @obj: instance object on which to act
3667 * @params: parameters to pass to the propery
3668 * @exc: optional exception
3670 * Invokes the property's get method with the given arguments on the
3671 * object instance obj (or NULL for static properties).
3673 * You can pass NULL as the exc argument if you don't want to
3674 * catch exceptions, otherwise, *exc will be set to the exception
3675 * thrown, if any. if an exception is thrown, you can't use the
3676 * MonoObject* result from the function.
3678 * Returns: the value from invoking the get method on the property.
3681 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3683 MONO_REQ_GC_UNSAFE_MODE;
3686 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3687 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3688 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3690 mono_error_raise_exception (&error); /* FIXME don't raise here */
3697 * mono_nullable_init:
3698 * @buf: The nullable structure to initialize.
3699 * @value: the value to initialize from
3700 * @klass: the type for the object
3702 * Initialize the nullable structure pointed to by @buf from @value which
3703 * should be a boxed value type. The size of @buf should be able to hold
3704 * as much data as the @klass->instance_size (which is the number of bytes
3705 * that will be copies).
3707 * Since Nullables have variable structure, we can not define a C
3708 * structure for them.
3711 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3713 MONO_REQ_GC_UNSAFE_MODE;
3715 MonoClass *param_class = klass->cast_class;
3717 mono_class_setup_fields_locking (klass);
3718 g_assert (klass->fields_inited);
3720 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3721 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3723 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3725 if (param_class->has_references)
3726 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3728 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3730 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3735 * mono_nullable_box:
3736 * @buf: The buffer representing the data to be boxed
3737 * @klass: the type to box it as.
3738 * @error: set on oerr
3740 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3741 * @buf. On failure returns NULL and sets @error
3744 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3746 MONO_REQ_GC_UNSAFE_MODE;
3748 mono_error_init (error);
3749 MonoClass *param_class = klass->cast_class;
3751 mono_class_setup_fields_locking (klass);
3752 g_assert (klass->fields_inited);
3754 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3755 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3757 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3758 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3759 return_val_if_nok (error, NULL);
3760 if (param_class->has_references)
3761 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3763 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3771 * mono_get_delegate_invoke:
3772 * @klass: The delegate class
3774 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3777 mono_get_delegate_invoke (MonoClass *klass)
3779 MONO_REQ_GC_NEUTRAL_MODE;
3783 /* This is called at runtime, so avoid the slower search in metadata */
3784 mono_class_setup_methods (klass);
3785 if (mono_class_has_failure (klass))
3787 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3792 * mono_get_delegate_begin_invoke:
3793 * @klass: The delegate class
3795 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3798 mono_get_delegate_begin_invoke (MonoClass *klass)
3800 MONO_REQ_GC_NEUTRAL_MODE;
3804 /* This is called at runtime, so avoid the slower search in metadata */
3805 mono_class_setup_methods (klass);
3806 if (mono_class_has_failure (klass))
3808 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3813 * mono_get_delegate_end_invoke:
3814 * @klass: The delegate class
3816 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3819 mono_get_delegate_end_invoke (MonoClass *klass)
3821 MONO_REQ_GC_NEUTRAL_MODE;
3825 /* This is called at runtime, so avoid the slower search in metadata */
3826 mono_class_setup_methods (klass);
3827 if (mono_class_has_failure (klass))
3829 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3834 * mono_runtime_delegate_invoke:
3835 * @delegate: pointer to a delegate object.
3836 * @params: parameters for the delegate.
3837 * @exc: Pointer to the exception result.
3839 * Invokes the delegate method @delegate with the parameters provided.
3841 * You can pass NULL as the exc argument if you don't want to
3842 * catch exceptions, otherwise, *exc will be set to the exception
3843 * thrown, if any. if an exception is thrown, you can't use the
3844 * MonoObject* result from the function.
3847 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3849 MONO_REQ_GC_UNSAFE_MODE;
3853 MonoClass *klass = delegate->vtable->klass;
3856 im = mono_get_delegate_invoke (klass);
3858 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3861 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3862 if (*exc == NULL && !mono_error_ok (&error))
3863 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3865 mono_error_cleanup (&error);
3867 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3868 mono_error_raise_exception (&error); /* FIXME don't raise here */
3874 static char **main_args = NULL;
3875 static int num_main_args = 0;
3878 * mono_runtime_get_main_args:
3880 * Returns: a MonoArray with the arguments passed to the main program
3883 mono_runtime_get_main_args (void)
3885 MONO_REQ_GC_UNSAFE_MODE;
3889 MonoDomain *domain = mono_domain_get ();
3891 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3893 for (i = 0; i < num_main_args; ++i)
3894 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3900 free_main_args (void)
3902 MONO_REQ_GC_NEUTRAL_MODE;
3906 for (i = 0; i < num_main_args; ++i)
3907 g_free (main_args [i]);
3914 * mono_runtime_set_main_args:
3915 * @argc: number of arguments from the command line
3916 * @argv: array of strings from the command line
3918 * Set the command line arguments from an embedding application that doesn't otherwise call
3919 * mono_runtime_run_main ().
3922 mono_runtime_set_main_args (int argc, char* argv[])
3924 MONO_REQ_GC_NEUTRAL_MODE;
3929 main_args = g_new0 (char*, argc);
3930 num_main_args = argc;
3932 for (i = 0; i < argc; ++i) {
3935 utf8_arg = mono_utf8_from_external (argv[i]);
3936 if (utf8_arg == NULL) {
3937 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3938 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3942 main_args [i] = utf8_arg;
3949 * mono_runtime_run_main:
3950 * @method: the method to start the application with (usually Main)
3951 * @argc: number of arguments from the command line
3952 * @argv: array of strings from the command line
3953 * @exc: excetption results
3955 * Execute a standard Main() method (argc/argv contains the
3956 * executable name). This method also sets the command line argument value
3957 * needed by System.Environment.
3962 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3965 MONO_REQ_GC_UNSAFE_MODE;
3968 MonoArray *args = NULL;
3969 MonoDomain *domain = mono_domain_get ();
3970 gchar *utf8_fullpath;
3971 MonoMethodSignature *sig;
3973 g_assert (method != NULL);
3975 mono_thread_set_main (mono_thread_current ());
3977 main_args = g_new0 (char*, argc);
3978 num_main_args = argc;
3980 if (!g_path_is_absolute (argv [0])) {
3981 gchar *basename = g_path_get_basename (argv [0]);
3982 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3986 utf8_fullpath = mono_utf8_from_external (fullpath);
3987 if(utf8_fullpath == NULL) {
3988 /* Printing the arg text will cause glib to
3989 * whinge about "Invalid UTF-8", but at least
3990 * its relevant, and shows the problem text
3993 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3994 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4001 utf8_fullpath = mono_utf8_from_external (argv[0]);
4002 if(utf8_fullpath == NULL) {
4003 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4004 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4009 main_args [0] = utf8_fullpath;
4011 for (i = 1; i < argc; ++i) {
4014 utf8_arg=mono_utf8_from_external (argv[i]);
4015 if(utf8_arg==NULL) {
4016 /* Ditto the comment about Invalid UTF-8 here */
4017 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4018 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4022 main_args [i] = utf8_arg;
4027 sig = mono_method_signature (method);
4029 g_print ("Unable to load Main method.\n");
4033 if (sig->param_count) {
4034 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
4035 for (i = 0; i < argc; ++i) {
4036 /* The encodings should all work, given that
4037 * we've checked all these args for the
4040 gchar *str = mono_utf8_from_external (argv [i]);
4041 MonoString *arg = mono_string_new (domain, str);
4042 mono_array_setref (args, i, arg);
4046 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4049 mono_assembly_set_main (method->klass->image->assembly);
4051 return mono_runtime_exec_main (method, args, exc);
4055 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4057 static MonoMethod *serialize_method;
4063 if (!serialize_method) {
4064 MonoClass *klass = mono_class_get_remoting_services_class ();
4065 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4068 if (!serialize_method) {
4073 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4078 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4079 if (*exc == NULL && !mono_error_ok (&error))
4080 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4082 mono_error_cleanup (&error);
4091 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4093 MONO_REQ_GC_UNSAFE_MODE;
4095 static MonoMethod *deserialize_method;
4101 if (!deserialize_method) {
4102 MonoClass *klass = mono_class_get_remoting_services_class ();
4103 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4105 if (!deserialize_method) {
4113 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4114 if (*exc == NULL && !mono_error_ok (&error))
4115 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4117 mono_error_cleanup (&error);
4125 #ifndef DISABLE_REMOTING
4127 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4129 MONO_REQ_GC_UNSAFE_MODE;
4131 static MonoMethod *get_proxy_method;
4134 MonoDomain *domain = mono_domain_get ();
4135 MonoRealProxy *real_proxy;
4136 MonoReflectionType *reflection_type;
4137 MonoTransparentProxy *transparent_proxy;
4139 if (!get_proxy_method)
4140 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4142 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4144 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4145 mono_error_raise_exception (&error); /* FIXME don't raise here */
4146 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4147 mono_error_raise_exception (&error); /* FIXME don't raise here */
4149 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4150 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4154 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4155 if (*exc == NULL && !mono_error_ok (&error))
4156 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4158 mono_error_cleanup (&error);
4162 return (MonoObject*) transparent_proxy;
4164 #endif /* DISABLE_REMOTING */
4167 * mono_object_xdomain_representation
4169 * @target_domain: a domain
4170 * @exc: pointer to a MonoObject*
4172 * Creates a representation of obj in the domain target_domain. This
4173 * is either a copy of obj arrived through via serialization and
4174 * deserialization or a proxy, depending on whether the object is
4175 * serializable or marshal by ref. obj must not be in target_domain.
4177 * If the object cannot be represented in target_domain, NULL is
4178 * returned and *exc is set to an appropriate exception.
4181 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4183 MONO_REQ_GC_UNSAFE_MODE;
4185 MonoObject *deserialized = NULL;
4186 gboolean failure = FALSE;
4188 g_assert (exc != NULL);
4191 #ifndef DISABLE_REMOTING
4192 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4193 deserialized = make_transparent_proxy (obj, &failure, exc);
4198 MonoDomain *domain = mono_domain_get ();
4199 MonoObject *serialized;
4201 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4202 serialized = serialize_object (obj, &failure, exc);
4203 mono_domain_set_internal_with_options (target_domain, FALSE);
4205 deserialized = deserialize_object (serialized, &failure, exc);
4206 if (domain != target_domain)
4207 mono_domain_set_internal_with_options (domain, FALSE);
4210 return deserialized;
4213 /* Used in call_unhandled_exception_delegate */
4215 create_unhandled_exception_eventargs (MonoObject *exc)
4217 MONO_REQ_GC_UNSAFE_MODE;
4222 MonoMethod *method = NULL;
4223 MonoBoolean is_terminating = TRUE;
4226 klass = mono_class_get_unhandled_exception_event_args_class ();
4227 mono_class_init (klass);
4229 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4230 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4234 args [1] = &is_terminating;
4236 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4237 mono_error_raise_exception (&error); /* FIXME don't raise here */
4239 mono_runtime_invoke_checked (method, obj, args, &error);
4240 mono_error_raise_exception (&error); /* FIXME don't raise here */
4245 /* Used in mono_unhandled_exception */
4247 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4248 MONO_REQ_GC_UNSAFE_MODE;
4250 MonoObject *e = NULL;
4252 MonoDomain *current_domain = mono_domain_get ();
4254 if (domain != current_domain)
4255 mono_domain_set_internal_with_options (domain, FALSE);
4257 g_assert (domain == mono_object_domain (domain->domain));
4259 if (mono_object_domain (exc) != domain) {
4260 MonoObject *serialization_exc;
4262 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4264 if (serialization_exc) {
4266 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4269 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4270 "System.Runtime.Serialization", "SerializationException",
4271 "Could not serialize unhandled exception.");
4275 g_assert (mono_object_domain (exc) == domain);
4277 pa [0] = domain->domain;
4278 pa [1] = create_unhandled_exception_eventargs (exc);
4279 mono_runtime_delegate_invoke (delegate, pa, &e);
4281 if (domain != current_domain)
4282 mono_domain_set_internal_with_options (current_domain, FALSE);
4286 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4287 if (!mono_error_ok (&error)) {
4288 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4289 mono_error_cleanup (&error);
4291 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4297 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4300 * mono_runtime_unhandled_exception_policy_set:
4301 * @policy: the new policy
4303 * This is a VM internal routine.
4305 * Sets the runtime policy for handling unhandled exceptions.
4308 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4309 runtime_unhandled_exception_policy = policy;
4313 * mono_runtime_unhandled_exception_policy_get:
4315 * This is a VM internal routine.
4317 * Gets the runtime policy for handling unhandled exceptions.
4319 MonoRuntimeUnhandledExceptionPolicy
4320 mono_runtime_unhandled_exception_policy_get (void) {
4321 return runtime_unhandled_exception_policy;
4325 * mono_unhandled_exception:
4326 * @exc: exception thrown
4328 * This is a VM internal routine.
4330 * We call this function when we detect an unhandled exception
4331 * in the default domain.
4333 * It invokes the * UnhandledException event in AppDomain or prints
4334 * a warning to the console
4337 mono_unhandled_exception (MonoObject *exc)
4339 MONO_REQ_GC_UNSAFE_MODE;
4342 MonoClassField *field;
4343 MonoDomain *current_domain, *root_domain;
4344 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4346 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4349 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4352 current_domain = mono_domain_get ();
4353 root_domain = mono_get_root_domain ();
4355 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4356 mono_error_raise_exception (&error); /* FIXME don't raise here */
4357 if (current_domain != root_domain) {
4358 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4359 mono_error_raise_exception (&error); /* FIXME don't raise here */
4362 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4363 mono_print_unhandled_exception (exc);
4365 if (root_appdomain_delegate)
4366 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4367 if (current_appdomain_delegate)
4368 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4371 /* set exitcode only if we will abort the process */
4372 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4373 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4375 mono_environment_exitcode_set (1);
4380 * mono_runtime_exec_managed_code:
4381 * @domain: Application domain
4382 * @main_func: function to invoke from the execution thread
4383 * @main_args: parameter to the main_func
4385 * Launch a new thread to execute a function
4387 * main_func is called back from the thread with main_args as the
4388 * parameter. The callback function is expected to start Main()
4389 * eventually. This function then waits for all managed threads to
4391 * It is not necesseray anymore to execute managed code in a subthread,
4392 * so this function should not be used anymore by default: just
4393 * execute the code and then call mono_thread_manage ().
4396 mono_runtime_exec_managed_code (MonoDomain *domain,
4397 MonoMainThreadFunc main_func,
4400 mono_thread_create (domain, main_func, main_args);
4402 mono_thread_manage ();
4406 * Execute a standard Main() method (args doesn't contain the
4410 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4412 MONO_REQ_GC_UNSAFE_MODE;
4418 MonoCustomAttrInfo* cinfo;
4419 gboolean has_stathread_attribute;
4420 MonoInternalThread* thread = mono_thread_internal_current ();
4426 domain = mono_object_domain (args);
4427 if (!domain->entry_assembly) {
4429 MonoAssembly *assembly;
4431 assembly = method->klass->image->assembly;
4432 domain->entry_assembly = assembly;
4433 /* Domains created from another domain already have application_base and configuration_file set */
4434 if (domain->setup->application_base == NULL) {
4435 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4438 if (domain->setup->configuration_file == NULL) {
4439 str = g_strconcat (assembly->image->name, ".config", NULL);
4440 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4442 mono_domain_set_options_from_config (domain);
4446 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4447 mono_error_cleanup (&error); /* FIXME warn here? */
4449 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4451 mono_custom_attrs_free (cinfo);
4453 has_stathread_attribute = FALSE;
4455 if (has_stathread_attribute) {
4456 thread->apartment_state = ThreadApartmentState_STA;
4458 thread->apartment_state = ThreadApartmentState_MTA;
4460 mono_thread_init_apartment_state ();
4462 /* FIXME: check signature of method */
4463 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4466 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4467 if (*exc == NULL && !mono_error_ok (&error))
4468 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4470 mono_error_cleanup (&error);
4472 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4473 mono_error_raise_exception (&error); /* FIXME don't raise here */
4477 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4481 mono_environment_exitcode_set (rval);
4484 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4485 if (*exc == NULL && !mono_error_ok (&error))
4486 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4488 mono_error_cleanup (&error);
4490 mono_runtime_invoke_checked (method, NULL, pa, &error);
4491 mono_error_raise_exception (&error); /* FIXME don't raise here */
4497 /* If the return type of Main is void, only
4498 * set the exitcode if an exception was thrown
4499 * (we don't want to blow away an
4500 * explicitly-set exit code)
4503 mono_environment_exitcode_set (rval);
4511 * mono_runtime_invoke_array:
4512 * @method: method to invoke
4513 * @obJ: object instance
4514 * @params: arguments to the method
4515 * @exc: exception information.
4517 * Invokes the method represented by @method on the object @obj.
4519 * obj is the 'this' pointer, it should be NULL for static
4520 * methods, a MonoObject* for object instances and a pointer to
4521 * the value type for value types.
4523 * The params array contains the arguments to the method with the
4524 * same convention: MonoObject* pointers for object instances and
4525 * pointers to the value type otherwise. The _invoke_array
4526 * variant takes a C# object[] as the params argument (MonoArray
4527 * *params): in this case the value types are boxed inside the
4528 * respective reference representation.
4530 * From unmanaged code you'll usually use the
4531 * mono_runtime_invoke_checked() variant.
4533 * Note that this function doesn't handle virtual methods for
4534 * you, it will exec the exact method you pass: we still need to
4535 * expose a function to lookup the derived class implementation
4536 * of a virtual method (there are examples of this in the code,
4539 * You can pass NULL as the exc argument if you don't want to
4540 * catch exceptions, otherwise, *exc will be set to the exception
4541 * thrown, if any. if an exception is thrown, you can't use the
4542 * MonoObject* result from the function.
4544 * If the method returns a value type, it is boxed in an object
4548 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4551 MONO_REQ_GC_UNSAFE_MODE;
4554 MonoMethodSignature *sig = mono_method_signature (method);
4555 gpointer *pa = NULL;
4558 gboolean has_byref_nullables = FALSE;
4560 if (NULL != params) {
4561 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4562 for (i = 0; i < mono_array_length (params); i++) {
4563 MonoType *t = sig->params [i];
4569 case MONO_TYPE_BOOLEAN:
4572 case MONO_TYPE_CHAR:
4581 case MONO_TYPE_VALUETYPE:
4582 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4583 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4584 pa [i] = mono_array_get (params, MonoObject*, i);
4586 has_byref_nullables = TRUE;
4588 /* MS seems to create the objects if a null is passed in */
4589 if (!mono_array_get (params, MonoObject*, i)) {
4590 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4591 mono_error_raise_exception (&error); /* FIXME don't raise here */
4592 mono_array_setref (params, i, o);
4597 * We can't pass the unboxed vtype byref to the callee, since
4598 * that would mean the callee would be able to modify boxed
4599 * primitive types. So we (and MS) make a copy of the boxed
4600 * object, pass that to the callee, and replace the original
4601 * boxed object in the arg array with the copy.
4603 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4604 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), &error);
4605 mono_error_raise_exception (&error); /* FIXME don't raise here */
4606 mono_array_setref (params, i, copy);
4609 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4612 case MONO_TYPE_STRING:
4613 case MONO_TYPE_OBJECT:
4614 case MONO_TYPE_CLASS:
4615 case MONO_TYPE_ARRAY:
4616 case MONO_TYPE_SZARRAY:
4618 pa [i] = mono_array_addr (params, MonoObject*, i);
4619 // FIXME: I need to check this code path
4621 pa [i] = mono_array_get (params, MonoObject*, i);
4623 case MONO_TYPE_GENERICINST:
4625 t = &t->data.generic_class->container_class->this_arg;
4627 t = &t->data.generic_class->container_class->byval_arg;
4629 case MONO_TYPE_PTR: {
4632 /* The argument should be an IntPtr */
4633 arg = mono_array_get (params, MonoObject*, i);
4637 g_assert (arg->vtable->klass == mono_defaults.int_class);
4638 pa [i] = ((MonoIntPtr*)arg)->m_value;
4643 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4648 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4651 if (mono_class_is_nullable (method->klass)) {
4652 /* Need to create a boxed vtype instead */
4658 MonoObject *result = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], &error);
4659 mono_error_raise_exception (&error); /* FIXME don't raise here */
4665 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4666 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4667 #ifndef DISABLE_REMOTING
4668 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4669 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4672 if (method->klass->valuetype)
4673 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4676 } else if (method->klass->valuetype) {
4677 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, &error);
4678 mono_error_raise_exception (&error); /* FIXME don't raise here */
4682 mono_runtime_try_invoke (method, o, pa, exc, &error);
4683 if (*exc == NULL && !mono_error_ok (&error))
4684 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4686 mono_error_cleanup (&error);
4688 mono_runtime_invoke_checked (method, o, pa, &error);
4689 mono_error_raise_exception (&error); /* FIXME don't raise here */
4692 return (MonoObject *)obj;
4694 if (mono_class_is_nullable (method->klass)) {
4695 MonoObject *nullable;
4697 /* Convert the unboxed vtype into a Nullable structure */
4698 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4699 mono_error_raise_exception (&error); /* FIXME don't raise here */
4701 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, &error);
4702 mono_error_raise_exception (&error); /* FIXME don't raise here */
4703 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
4704 obj = mono_object_unbox (nullable);
4707 /* obj must be already unboxed if needed */
4709 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4710 if (*exc == NULL && !mono_error_ok (&error))
4711 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4713 mono_error_cleanup (&error);
4715 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4716 mono_error_raise_exception (&error); /* FIXME don't raise here */
4719 if (sig->ret->type == MONO_TYPE_PTR) {
4720 MonoClass *pointer_class;
4721 static MonoMethod *box_method;
4723 MonoObject *box_exc;
4726 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4727 * convert it to a Pointer object.
4729 pointer_class = mono_class_get_pointer_class ();
4731 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4733 g_assert (res->vtable->klass == mono_defaults.int_class);
4734 box_args [0] = ((MonoIntPtr*)res)->m_value;
4735 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4736 mono_error_raise_exception (&error); /* FIXME don't raise here */
4738 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4739 g_assert (box_exc == NULL);
4740 mono_error_assert_ok (&error);
4743 if (has_byref_nullables) {
4745 * The runtime invoke wrapper already converted byref nullables back,
4746 * and stored them in pa, we just need to copy them back to the
4749 for (i = 0; i < mono_array_length (params); i++) {
4750 MonoType *t = sig->params [i];
4752 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4753 mono_array_setref (params, i, pa [i]);
4763 * @klass: the class of the object that we want to create
4765 * Returns: a newly created object whose definition is
4766 * looked up using @klass. This will not invoke any constructors,
4767 * so the consumer of this routine has to invoke any constructors on
4768 * its own to initialize the object.
4770 * It returns NULL on failure.
4773 mono_object_new (MonoDomain *domain, MonoClass *klass)
4775 MONO_REQ_GC_UNSAFE_MODE;
4779 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4781 mono_error_raise_exception (&error);
4786 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4788 MONO_REQ_GC_UNSAFE_MODE;
4792 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4794 mono_error_raise_exception (&error);
4799 * mono_object_new_checked:
4800 * @klass: the class of the object that we want to create
4801 * @error: set on error
4803 * Returns: a newly created object whose definition is
4804 * looked up using @klass. This will not invoke any constructors,
4805 * so the consumer of this routine has to invoke any constructors on
4806 * its own to initialize the object.
4808 * It returns NULL on failure and sets @error.
4811 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4813 MONO_REQ_GC_UNSAFE_MODE;
4817 vtable = mono_class_vtable (domain, klass);
4818 g_assert (vtable); /* FIXME don't swallow the error */
4820 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4825 * mono_object_new_pinned:
4827 * Same as mono_object_new, but the returned object will be pinned.
4828 * For SGEN, these objects will only be freed at appdomain unload.
4831 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4833 MONO_REQ_GC_UNSAFE_MODE;
4837 mono_error_init (error);
4839 vtable = mono_class_vtable (domain, klass);
4840 g_assert (vtable); /* FIXME don't swallow the error */
4842 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4844 if (G_UNLIKELY (!o))
4845 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4846 else if (G_UNLIKELY (vtable->klass->has_finalize))
4847 mono_object_register_finalizer (o, error);
4853 * mono_object_new_specific:
4854 * @vtable: the vtable of the object that we want to create
4856 * Returns: A newly created object with class and domain specified
4860 mono_object_new_specific (MonoVTable *vtable)
4863 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4864 mono_error_raise_exception (&error);
4870 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4872 MONO_REQ_GC_UNSAFE_MODE;
4876 mono_error_init (error);
4878 /* check for is_com_object for COM Interop */
4879 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4882 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4885 MonoClass *klass = mono_class_get_activation_services_class ();
4888 mono_class_init (klass);
4890 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4892 mono_error_set_not_supported (error, "Linked away.");
4895 vtable->domain->create_proxy_for_type_method = im;
4898 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4899 if (!mono_error_ok (error))
4902 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4903 if (!mono_error_ok (error))
4910 return mono_object_new_alloc_specific_checked (vtable, error);
4914 ves_icall_object_new_specific (MonoVTable *vtable)
4917 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4918 mono_error_raise_exception (&error);
4924 * mono_object_new_alloc_specific:
4925 * @vtable: virtual table for the object.
4927 * This function allocates a new `MonoObject` with the type derived
4928 * from the @vtable information. If the class of this object has a
4929 * finalizer, then the object will be tracked for finalization.
4931 * This method might raise an exception on errors. Use the
4932 * `mono_object_new_fast_checked` method if you want to manually raise
4935 * Returns: the allocated object.
4938 mono_object_new_alloc_specific (MonoVTable *vtable)
4941 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4942 mono_error_raise_exception (&error);
4948 * mono_object_new_alloc_specific_checked:
4949 * @vtable: virtual table for the object.
4950 * @error: holds the error return value.
4952 * This function allocates a new `MonoObject` with the type derived
4953 * from the @vtable information. If the class of this object has a
4954 * finalizer, then the object will be tracked for finalization.
4956 * If there is not enough memory, the @error parameter will be set
4957 * and will contain a user-visible message with the amount of bytes
4958 * that were requested.
4960 * Returns: the allocated object, or NULL if there is not enough memory
4964 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4966 MONO_REQ_GC_UNSAFE_MODE;
4970 mono_error_init (error);
4972 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4974 if (G_UNLIKELY (!o))
4975 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4976 else if (G_UNLIKELY (vtable->klass->has_finalize))
4977 mono_object_register_finalizer (o, error);
4983 * mono_object_new_fast:
4984 * @vtable: virtual table for the object.
4986 * This function allocates a new `MonoObject` with the type derived
4987 * from the @vtable information. The returned object is not tracked
4988 * for finalization. If your object implements a finalizer, you should
4989 * use `mono_object_new_alloc_specific` instead.
4991 * This method might raise an exception on errors. Use the
4992 * `mono_object_new_fast_checked` method if you want to manually raise
4995 * Returns: the allocated object.
4998 mono_object_new_fast (MonoVTable *vtable)
5001 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5002 mono_error_raise_exception (&error);
5008 * mono_object_new_fast_checked:
5009 * @vtable: virtual table for the object.
5010 * @error: holds the error return value.
5012 * This function allocates a new `MonoObject` with the type derived
5013 * from the @vtable information. The returned object is not tracked
5014 * for finalization. If your object implements a finalizer, you should
5015 * use `mono_object_new_alloc_specific_checked` instead.
5017 * If there is not enough memory, the @error parameter will be set
5018 * and will contain a user-visible message with the amount of bytes
5019 * that were requested.
5021 * Returns: the allocated object, or NULL if there is not enough memory
5025 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5027 MONO_REQ_GC_UNSAFE_MODE;
5031 mono_error_init (error);
5033 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5035 if (G_UNLIKELY (!o))
5036 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5042 ves_icall_object_new_fast (MonoVTable *vtable)
5045 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5046 mono_error_raise_exception (&error);
5052 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5054 MONO_REQ_GC_UNSAFE_MODE;
5058 mono_error_init (error);
5060 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5062 if (G_UNLIKELY (!o))
5063 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5064 else if (G_UNLIKELY (vtable->klass->has_finalize))
5065 mono_object_register_finalizer (o, error);
5071 * mono_class_get_allocation_ftn:
5073 * @for_box: the object will be used for boxing
5074 * @pass_size_in_words:
5076 * Return the allocation function appropriate for the given class.
5080 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5082 MONO_REQ_GC_NEUTRAL_MODE;
5084 *pass_size_in_words = FALSE;
5086 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5087 return ves_icall_object_new_specific;
5089 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5091 return ves_icall_object_new_fast;
5094 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5095 * of the overhead of parameter passing.
5098 *pass_size_in_words = TRUE;
5099 #ifdef GC_REDIRECT_TO_LOCAL
5100 return GC_local_gcj_fast_malloc;
5102 return GC_gcj_fast_malloc;
5107 return ves_icall_object_new_specific;
5111 * mono_object_new_from_token:
5112 * @image: Context where the type_token is hosted
5113 * @token: a token of the type that we want to create
5115 * Returns: A newly created object whose definition is
5116 * looked up using @token in the @image image
5119 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5121 MONO_REQ_GC_UNSAFE_MODE;
5127 klass = mono_class_get_checked (image, token, &error);
5128 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5130 result = mono_object_new_checked (domain, klass, &error);
5132 mono_error_raise_exception (&error); /* FIXME don't raise here */
5139 * mono_object_clone:
5140 * @obj: the object to clone
5142 * Returns: A newly created object who is a shallow copy of @obj
5145 mono_object_clone (MonoObject *obj)
5148 MonoObject *o = mono_object_clone_checked (obj, &error);
5149 mono_error_raise_exception (&error);
5155 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5157 MONO_REQ_GC_UNSAFE_MODE;
5162 mono_error_init (error);
5164 size = obj->vtable->klass->instance_size;
5166 if (obj->vtable->klass->rank)
5167 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5169 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5171 if (G_UNLIKELY (!o)) {
5172 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5176 /* If the object doesn't contain references this will do a simple memmove. */
5177 mono_gc_wbarrier_object_copy (o, obj);
5179 if (obj->vtable->klass->has_finalize)
5180 mono_object_register_finalizer (o, error);
5185 * mono_array_full_copy:
5186 * @src: source array to copy
5187 * @dest: destination array
5189 * Copies the content of one array to another with exactly the same type and size.
5192 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5194 MONO_REQ_GC_UNSAFE_MODE;
5197 MonoClass *klass = src->obj.vtable->klass;
5199 g_assert (klass == dest->obj.vtable->klass);
5201 size = mono_array_length (src);
5202 g_assert (size == mono_array_length (dest));
5203 size *= mono_array_element_size (klass);
5205 if (klass->element_class->valuetype) {
5206 if (klass->element_class->has_references)
5207 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5209 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5211 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5214 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5219 * mono_array_clone_in_domain:
5220 * @domain: the domain in which the array will be cloned into
5221 * @array: the array to clone
5223 * This routine returns a copy of the array that is hosted on the
5224 * specified MonoDomain.
5227 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5229 MONO_REQ_GC_UNSAFE_MODE;
5235 MonoClass *klass = array->obj.vtable->klass;
5237 if (array->bounds == NULL) {
5238 size = mono_array_length (array);
5239 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5240 mono_error_raise_exception (&error); /* FIXME don't raise here */
5242 size *= mono_array_element_size (klass);
5244 if (klass->element_class->valuetype) {
5245 if (klass->element_class->has_references)
5246 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5248 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5250 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5253 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5258 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5259 size = mono_array_element_size (klass);
5260 for (i = 0; i < klass->rank; ++i) {
5261 sizes [i] = array->bounds [i].length;
5262 size *= array->bounds [i].length;
5263 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5265 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5266 mono_error_raise_exception (&error); /* FIXME don't raise here */
5268 if (klass->element_class->valuetype) {
5269 if (klass->element_class->has_references)
5270 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5272 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5274 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5277 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5285 * @array: the array to clone
5287 * Returns: A newly created array who is a shallow copy of @array
5290 mono_array_clone (MonoArray *array)
5292 MONO_REQ_GC_UNSAFE_MODE;
5294 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5297 /* helper macros to check for overflow when calculating the size of arrays */
5298 #ifdef MONO_BIG_ARRAYS
5299 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5300 #define MYGUINT_MAX MYGUINT64_MAX
5301 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5302 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5303 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5304 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5305 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5307 #define MYGUINT32_MAX 4294967295U
5308 #define MYGUINT_MAX MYGUINT32_MAX
5309 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5310 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5311 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5312 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5313 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5317 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5319 MONO_REQ_GC_NEUTRAL_MODE;
5323 byte_len = mono_array_element_size (klass);
5324 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5327 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5329 byte_len += MONO_SIZEOF_MONO_ARRAY;
5337 * mono_array_new_full:
5338 * @domain: domain where the object is created
5339 * @array_class: array class
5340 * @lengths: lengths for each dimension in the array
5341 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5343 * This routine creates a new array objects with the given dimensions,
5344 * lower bounds and type.
5347 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5350 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5351 mono_error_raise_exception (&error);
5357 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5359 MONO_REQ_GC_UNSAFE_MODE;
5361 uintptr_t byte_len = 0, len, bounds_size;
5364 MonoArrayBounds *bounds;
5368 mono_error_init (error);
5370 if (!array_class->inited)
5371 mono_class_init (array_class);
5375 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5376 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5378 if (len > MONO_ARRAY_MAX_INDEX) {
5379 mono_error_set_generic_error (error, "System", "OverflowException", "");
5384 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5386 for (i = 0; i < array_class->rank; ++i) {
5387 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5388 mono_error_set_generic_error (error, "System", "OverflowException", "");
5391 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5392 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5399 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5400 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5406 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5407 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5410 byte_len = (byte_len + 3) & ~3;
5411 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5412 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5415 byte_len += bounds_size;
5418 * Following three lines almost taken from mono_object_new ():
5419 * they need to be kept in sync.
5421 vtable = mono_class_vtable_full (domain, array_class, error);
5422 return_val_if_nok (error, NULL);
5425 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5427 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5429 if (G_UNLIKELY (!o)) {
5430 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5434 array = (MonoArray*)o;
5436 bounds = array->bounds;
5439 for (i = 0; i < array_class->rank; ++i) {
5440 bounds [i].length = lengths [i];
5442 bounds [i].lower_bound = lower_bounds [i];
5451 * @domain: domain where the object is created
5452 * @eclass: element class
5453 * @n: number of array elements
5455 * This routine creates a new szarray with @n elements of type @eclass.
5458 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5460 MONO_REQ_GC_UNSAFE_MODE;
5466 ac = mono_array_class_get (eclass, 1);
5469 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5470 mono_error_raise_exception (&error); /* FIXME don't raise here */
5472 arr = mono_array_new_specific_checked (vtable, n, &error);
5473 mono_error_raise_exception (&error); /* FIXME don't raise here */
5479 * mono_array_new_specific:
5480 * @vtable: a vtable in the appropriate domain for an initialized class
5481 * @n: number of array elements
5483 * This routine is a fast alternative to mono_array_new() for code which
5484 * can be sure about the domain it operates in.
5487 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5490 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5491 mono_error_raise_exception (&error); /* FIXME don't raise here */
5497 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5499 MONO_REQ_GC_UNSAFE_MODE;
5504 mono_error_init (error);
5506 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5507 mono_error_set_generic_error (error, "System", "OverflowException", "");
5511 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5512 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5515 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5517 if (G_UNLIKELY (!o)) {
5518 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5522 return (MonoArray*)o;
5526 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5529 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5530 mono_error_raise_exception (&error);
5536 * mono_string_new_utf16:
5537 * @text: a pointer to an utf16 string
5538 * @len: the length of the string
5540 * Returns: A newly created string object which contains @text.
5543 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5545 MONO_REQ_GC_UNSAFE_MODE;
5548 MonoString *res = NULL;
5549 res = mono_string_new_utf16_checked (domain, text, len, &error);
5550 mono_error_raise_exception (&error);
5556 * mono_string_new_utf16_checked:
5557 * @text: a pointer to an utf16 string
5558 * @len: the length of the string
5559 * @error: written on error.
5561 * Returns: A newly created string object which contains @text.
5562 * On error, returns NULL and sets @error.
5565 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5567 MONO_REQ_GC_UNSAFE_MODE;
5571 mono_error_init (error);
5573 s = mono_string_new_size_checked (domain, len, error);
5575 memcpy (mono_string_chars (s), text, len * 2);
5581 * mono_string_new_utf32:
5582 * @text: a pointer to an utf32 string
5583 * @len: the length of the string
5585 * Returns: A newly created string object which contains @text.
5588 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5590 MONO_REQ_GC_UNSAFE_MODE;
5594 mono_unichar2 *utf16_output = NULL;
5595 gint32 utf16_len = 0;
5596 GError *gerror = NULL;
5597 glong items_written;
5599 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5602 g_error_free (gerror);
5604 while (utf16_output [utf16_len]) utf16_len++;
5606 s = mono_string_new_size_checked (domain, utf16_len, &error);
5607 mono_error_raise_exception (&error); /* FIXME don't raise here */
5609 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5611 g_free (utf16_output);
5617 * mono_string_new_size:
5618 * @text: a pointer to an utf16 string
5619 * @len: the length of the string
5621 * Returns: A newly created string object of @len
5624 mono_string_new_size (MonoDomain *domain, gint32 len)
5627 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5628 mono_error_raise_exception (&error);
5634 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5636 MONO_REQ_GC_UNSAFE_MODE;
5642 mono_error_init (error);
5644 /* check for overflow */
5645 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5646 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5650 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5651 g_assert (size > 0);
5653 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5656 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5658 if (G_UNLIKELY (!s)) {
5659 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5667 * mono_string_new_len:
5668 * @text: a pointer to an utf8 string
5669 * @length: number of bytes in @text to consider
5671 * Returns: A newly created string object which contains @text.
5674 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5676 MONO_REQ_GC_UNSAFE_MODE;
5679 GError *eg_error = NULL;
5680 MonoString *o = NULL;
5682 glong items_written;
5684 mono_error_init (&error);
5686 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5689 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5691 g_error_free (eg_error);
5695 mono_error_raise_exception (&error); /* FIXME don't raise here */
5701 * @text: a pointer to an utf8 string
5703 * Returns: A newly created string object which contains @text.
5705 * This function asserts if it cannot allocate a new string.
5707 * @deprecated Use mono_string_new_checked in new code.
5710 mono_string_new (MonoDomain *domain, const char *text)
5713 MonoString *res = NULL;
5714 res = mono_string_new_checked (domain, text, &error);
5715 mono_error_assert_ok (&error);
5720 * mono_string_new_checked:
5721 * @text: a pointer to an utf8 string
5722 * @merror: set on error
5724 * Returns: A newly created string object which contains @text.
5725 * On error returns NULL and sets @merror.
5728 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5730 MONO_REQ_GC_UNSAFE_MODE;
5732 GError *eg_error = NULL;
5733 MonoString *o = NULL;
5735 glong items_written;
5738 mono_error_init (error);
5742 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5745 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5747 g_error_free (eg_error);
5750 mono_error_raise_exception (error);
5752 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5757 MonoString *o = NULL;
5759 if (!g_utf8_validate (text, -1, &end)) {
5760 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5764 len = g_utf8_strlen (text, -1);
5765 o = mono_string_new_size_checked (domain, len, error);
5768 str = mono_string_chars (o);
5770 while (text < end) {
5771 *str++ = g_utf8_get_char (text);
5772 text = g_utf8_next_char (text);
5781 * mono_string_new_wrapper:
5782 * @text: pointer to utf8 characters.
5784 * Helper function to create a string object from @text in the current domain.
5787 mono_string_new_wrapper (const char *text)
5789 MONO_REQ_GC_UNSAFE_MODE;
5791 MonoDomain *domain = mono_domain_get ();
5794 return mono_string_new (domain, text);
5801 * @class: the class of the value
5802 * @value: a pointer to the unboxed data
5804 * Returns: A newly created object which contains @value.
5807 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5810 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
5811 mono_error_cleanup (&error);
5816 * mono_value_box_checked:
5817 * @domain: the domain of the new object
5818 * @class: the class of the value
5819 * @value: a pointer to the unboxed data
5820 * @error: set on error
5822 * Returns: A newly created object which contains @value. On failure
5823 * returns NULL and sets @error.
5826 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
5828 MONO_REQ_GC_UNSAFE_MODE;
5833 mono_error_init (error);
5835 g_assert (klass->valuetype);
5836 if (mono_class_is_nullable (klass))
5837 return mono_nullable_box ((guint8 *)value, klass, error);
5839 vtable = mono_class_vtable (domain, klass);
5842 size = mono_class_instance_size (klass);
5843 res = mono_object_new_alloc_specific_checked (vtable, error);
5844 return_val_if_nok (error, NULL);
5846 size = size - sizeof (MonoObject);
5849 g_assert (size == mono_class_value_size (klass, NULL));
5850 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5852 #if NO_UNALIGNED_ACCESS
5853 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5857 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5860 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5863 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5866 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5869 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5873 if (klass->has_finalize) {
5874 mono_object_register_finalizer (res, error);
5875 return_val_if_nok (error, NULL);
5882 * @dest: destination pointer
5883 * @src: source pointer
5884 * @klass: a valuetype class
5886 * Copy a valuetype from @src to @dest. This function must be used
5887 * when @klass contains references fields.
5890 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5892 MONO_REQ_GC_UNSAFE_MODE;
5894 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5898 * mono_value_copy_array:
5899 * @dest: destination array
5900 * @dest_idx: index in the @dest array
5901 * @src: source pointer
5902 * @count: number of items
5904 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5905 * This function must be used when @klass contains references fields.
5906 * Overlap is handled.
5909 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5911 MONO_REQ_GC_UNSAFE_MODE;
5913 int size = mono_array_element_size (dest->obj.vtable->klass);
5914 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5915 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5916 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5920 * mono_object_get_domain:
5921 * @obj: object to query
5923 * Returns: the MonoDomain where the object is hosted
5926 mono_object_get_domain (MonoObject *obj)
5928 MONO_REQ_GC_UNSAFE_MODE;
5930 return mono_object_domain (obj);
5934 * mono_object_get_class:
5935 * @obj: object to query
5937 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5939 * Returns: the MonoClass of the object.
5942 mono_object_get_class (MonoObject *obj)
5944 MONO_REQ_GC_UNSAFE_MODE;
5946 return mono_object_class (obj);
5949 * mono_object_get_size:
5950 * @o: object to query
5952 * Returns: the size, in bytes, of @o
5955 mono_object_get_size (MonoObject* o)
5957 MONO_REQ_GC_UNSAFE_MODE;
5959 MonoClass* klass = mono_object_class (o);
5960 if (klass == mono_defaults.string_class) {
5961 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5962 } else if (o->vtable->rank) {
5963 MonoArray *array = (MonoArray*)o;
5964 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5965 if (array->bounds) {
5968 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5972 return mono_class_instance_size (klass);
5977 * mono_object_unbox:
5978 * @obj: object to unbox
5980 * Returns: a pointer to the start of the valuetype boxed in this
5983 * This method will assert if the object passed is not a valuetype.
5986 mono_object_unbox (MonoObject *obj)
5988 MONO_REQ_GC_UNSAFE_MODE;
5990 /* add assert for valuetypes? */
5991 g_assert (obj->vtable->klass->valuetype);
5992 return ((char*)obj) + sizeof (MonoObject);
5996 * mono_object_isinst:
5998 * @klass: a pointer to a class
6000 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6003 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6005 MONO_REQ_GC_UNSAFE_MODE;
6008 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6009 mono_error_cleanup (&error);
6015 * mono_object_isinst_checked:
6017 * @klass: a pointer to a class
6018 * @error: set on error
6020 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6021 * On failure returns NULL and sets @error.
6024 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6026 MONO_REQ_GC_UNSAFE_MODE;
6028 mono_error_init (error);
6030 MonoObject *result = NULL;
6033 mono_class_init (klass);
6035 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6036 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6043 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6047 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6049 MONO_REQ_GC_UNSAFE_MODE;
6052 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6053 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6058 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6060 MONO_REQ_GC_UNSAFE_MODE;
6064 mono_error_init (error);
6071 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6072 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6076 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6077 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6080 MonoClass *oklass = vt->klass;
6081 if (mono_class_is_transparent_proxy (oklass))
6082 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6084 mono_class_setup_supertypes (klass);
6085 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6088 #ifndef DISABLE_REMOTING
6089 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6091 MonoDomain *domain = mono_domain_get ();
6093 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6094 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6095 MonoMethod *im = NULL;
6098 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6100 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6101 im = mono_object_get_virtual_method (rp, im);
6104 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6105 return_val_if_nok (error, NULL);
6108 res = mono_runtime_invoke_checked (im, rp, pa, error);
6109 return_val_if_nok (error, NULL);
6111 if (*(MonoBoolean *) mono_object_unbox(res)) {
6112 /* Update the vtable of the remote type, so it can safely cast to this new type */
6113 mono_upgrade_remote_class (domain, obj, klass);
6117 #endif /* DISABLE_REMOTING */
6122 * mono_object_castclass_mbyref:
6124 * @klass: a pointer to a class
6126 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6129 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6131 MONO_REQ_GC_UNSAFE_MODE;
6134 if (!obj) return NULL;
6135 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6136 mono_error_cleanup (&error);
6141 MonoDomain *orig_domain;
6147 str_lookup (MonoDomain *domain, gpointer user_data)
6149 MONO_REQ_GC_UNSAFE_MODE;
6151 LDStrInfo *info = (LDStrInfo *)user_data;
6152 if (info->res || domain == info->orig_domain)
6154 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6158 mono_string_get_pinned (MonoString *str, MonoError *error)
6160 MONO_REQ_GC_UNSAFE_MODE;
6162 mono_error_init (error);
6164 /* We only need to make a pinned version of a string if this is a moving GC */
6165 if (!mono_gc_is_moving ())
6169 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6170 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6172 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6173 news->length = mono_string_length (str);
6175 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6181 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6183 MONO_REQ_GC_UNSAFE_MODE;
6185 MonoGHashTable *ldstr_table;
6186 MonoString *s, *res;
6189 mono_error_init (error);
6191 domain = ((MonoObject *)str)->vtable->domain;
6192 ldstr_table = domain->ldstr_table;
6194 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6200 /* Allocate outside the lock */
6202 s = mono_string_get_pinned (str, error);
6203 return_val_if_nok (error, NULL);
6206 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6211 mono_g_hash_table_insert (ldstr_table, s, s);
6216 LDStrInfo ldstr_info;
6217 ldstr_info.orig_domain = domain;
6218 ldstr_info.ins = str;
6219 ldstr_info.res = NULL;
6221 mono_domain_foreach (str_lookup, &ldstr_info);
6222 if (ldstr_info.res) {
6224 * the string was already interned in some other domain:
6225 * intern it in the current one as well.
6227 mono_g_hash_table_insert (ldstr_table, str, str);
6237 * mono_string_is_interned:
6238 * @o: String to probe
6240 * Returns whether the string has been interned.
6243 mono_string_is_interned (MonoString *o)
6246 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6247 /* This function does not fail. */
6248 mono_error_assert_ok (&error);
6253 * mono_string_intern:
6254 * @o: String to intern
6256 * Interns the string passed.
6257 * Returns: The interned string.
6260 mono_string_intern (MonoString *str)
6263 MonoString *result = mono_string_intern_checked (str, &error);
6264 mono_error_assert_ok (&error);
6269 * mono_string_intern_checked:
6270 * @o: String to intern
6271 * @error: set on error.
6273 * Interns the string passed.
6274 * Returns: The interned string. On failure returns NULL and sets @error
6277 mono_string_intern_checked (MonoString *str, MonoError *error)
6279 MONO_REQ_GC_UNSAFE_MODE;
6281 mono_error_init (error);
6283 return mono_string_is_interned_lookup (str, TRUE, error);
6288 * @domain: the domain where the string will be used.
6289 * @image: a metadata context
6290 * @idx: index into the user string table.
6292 * Implementation for the ldstr opcode.
6293 * Returns: a loaded string from the @image/@idx combination.
6296 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6298 MONO_REQ_GC_UNSAFE_MODE;
6301 if (image->dynamic) {
6302 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, &error);
6303 mono_error_raise_exception (&error); /* FIXME don't raise here */
6306 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6307 return NULL; /*FIXME we should probably be raising an exception here*/
6308 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6313 * mono_ldstr_metadata_sig
6314 * @domain: the domain for the string
6315 * @sig: the signature of a metadata string
6317 * Returns: a MonoString for a string stored in the metadata
6320 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6322 MONO_REQ_GC_UNSAFE_MODE;
6325 const char *str = sig;
6326 MonoString *o, *interned;
6329 len2 = mono_metadata_decode_blob_size (str, &str);
6332 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6333 mono_error_raise_exception (&error); /* FIXME don't raise here */
6334 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6337 guint16 *p2 = (guint16*)mono_string_chars (o);
6338 for (i = 0; i < len2; ++i) {
6339 *p2 = GUINT16_FROM_LE (*p2);
6345 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6348 return interned; /* o will get garbage collected */
6350 o = mono_string_get_pinned (o, &error);
6351 mono_error_raise_exception (&error); /* FIXME don't raise here */
6354 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6356 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6366 * mono_string_to_utf8:
6367 * @s: a System.String
6369 * Returns the UTF8 representation for @s.
6370 * The resulting buffer needs to be freed with mono_free().
6372 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6375 mono_string_to_utf8 (MonoString *s)
6377 MONO_REQ_GC_UNSAFE_MODE;
6380 char *result = mono_string_to_utf8_checked (s, &error);
6382 if (!mono_error_ok (&error))
6383 mono_error_raise_exception (&error);
6388 * mono_string_to_utf8_checked:
6389 * @s: a System.String
6390 * @error: a MonoError.
6392 * Converts a MonoString to its UTF8 representation. May fail; check
6393 * @error to determine whether the conversion was successful.
6394 * The resulting buffer should be freed with mono_free().
6397 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6399 MONO_REQ_GC_UNSAFE_MODE;
6403 GError *gerror = NULL;
6405 mono_error_init (error);
6411 return g_strdup ("");
6413 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6415 mono_error_set_argument (error, "string", "%s", gerror->message);
6416 g_error_free (gerror);
6419 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6420 if (s->length > written) {
6421 /* allocate the total length and copy the part of the string that has been converted */
6422 char *as2 = (char *)g_malloc0 (s->length);
6423 memcpy (as2, as, written);
6432 * mono_string_to_utf8_ignore:
6435 * Converts a MonoString to its UTF8 representation. Will ignore
6436 * invalid surrogate pairs.
6437 * The resulting buffer should be freed with mono_free().
6441 mono_string_to_utf8_ignore (MonoString *s)
6443 MONO_REQ_GC_UNSAFE_MODE;
6452 return g_strdup ("");
6454 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6456 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6457 if (s->length > written) {
6458 /* allocate the total length and copy the part of the string that has been converted */
6459 char *as2 = (char *)g_malloc0 (s->length);
6460 memcpy (as2, as, written);
6469 * mono_string_to_utf8_image_ignore:
6470 * @s: a System.String
6472 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6475 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6477 MONO_REQ_GC_UNSAFE_MODE;
6479 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6483 * mono_string_to_utf8_mp_ignore:
6484 * @s: a System.String
6486 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6489 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6491 MONO_REQ_GC_UNSAFE_MODE;
6493 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6498 * mono_string_to_utf16:
6501 * Return an null-terminated array of the utf-16 chars
6502 * contained in @s. The result must be freed with g_free().
6503 * This is a temporary helper until our string implementation
6504 * is reworked to always include the null terminating char.
6507 mono_string_to_utf16 (MonoString *s)
6509 MONO_REQ_GC_UNSAFE_MODE;
6516 as = (char *)g_malloc ((s->length * 2) + 2);
6517 as [(s->length * 2)] = '\0';
6518 as [(s->length * 2) + 1] = '\0';
6521 return (gunichar2 *)(as);
6524 memcpy (as, mono_string_chars(s), s->length * 2);
6525 return (gunichar2 *)(as);
6529 * mono_string_to_utf32:
6532 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6533 * contained in @s. The result must be freed with g_free().
6536 mono_string_to_utf32 (MonoString *s)
6538 MONO_REQ_GC_UNSAFE_MODE;
6540 mono_unichar4 *utf32_output = NULL;
6541 GError *error = NULL;
6542 glong items_written;
6547 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6550 g_error_free (error);
6552 return utf32_output;
6556 * mono_string_from_utf16:
6557 * @data: the UTF16 string (LPWSTR) to convert
6559 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6561 * Returns: a MonoString.
6564 mono_string_from_utf16 (gunichar2 *data)
6566 MONO_REQ_GC_UNSAFE_MODE;
6569 MonoString *res = NULL;
6570 MonoDomain *domain = mono_domain_get ();
6576 while (data [len]) len++;
6578 res = mono_string_new_utf16_checked (domain, data, len, &error);
6579 mono_error_raise_exception (&error); /* FIXME don't raise here */
6584 * mono_string_from_utf32:
6585 * @data: the UTF32 string (LPWSTR) to convert
6587 * Converts a UTF32 (UCS-4)to a MonoString.
6589 * Returns: a MonoString.
6592 mono_string_from_utf32 (mono_unichar4 *data)
6594 MONO_REQ_GC_UNSAFE_MODE;
6596 MonoString* result = NULL;
6597 mono_unichar2 *utf16_output = NULL;
6598 GError *error = NULL;
6599 glong items_written;
6605 while (data [len]) len++;
6607 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6610 g_error_free (error);
6612 result = mono_string_from_utf16 (utf16_output);
6613 g_free (utf16_output);
6618 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6620 MONO_REQ_GC_UNSAFE_MODE;
6627 r = mono_string_to_utf8_ignore (s);
6629 r = mono_string_to_utf8_checked (s, error);
6630 if (!mono_error_ok (error))
6637 len = strlen (r) + 1;
6639 mp_s = (char *)mono_mempool_alloc (mp, len);
6641 mp_s = (char *)mono_image_alloc (image, len);
6643 memcpy (mp_s, r, len);
6651 * mono_string_to_utf8_image:
6652 * @s: a System.String
6654 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6657 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6659 MONO_REQ_GC_UNSAFE_MODE;
6661 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6665 * mono_string_to_utf8_mp:
6666 * @s: a System.String
6668 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6671 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6673 MONO_REQ_GC_UNSAFE_MODE;
6675 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6679 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6682 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6684 eh_callbacks = *cbs;
6687 MonoRuntimeExceptionHandlingCallbacks *
6688 mono_get_eh_callbacks (void)
6690 return &eh_callbacks;
6694 * mono_raise_exception:
6695 * @ex: exception object
6697 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6700 mono_raise_exception (MonoException *ex)
6702 MONO_REQ_GC_UNSAFE_MODE;
6705 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6706 * that will cause gcc to omit the function epilog, causing problems when
6707 * the JIT tries to walk the stack, since the return address on the stack
6708 * will point into the next function in the executable, not this one.
6710 eh_callbacks.mono_raise_exception (ex);
6714 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6716 MONO_REQ_GC_UNSAFE_MODE;
6718 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6722 * mono_wait_handle_new:
6723 * @domain: Domain where the object will be created
6724 * @handle: Handle for the wait handle
6726 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6729 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6731 MONO_REQ_GC_UNSAFE_MODE;
6734 MonoWaitHandle *res;
6735 gpointer params [1];
6736 static MonoMethod *handle_set;
6738 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6739 mono_error_raise_exception (&error); /* FIXME don't raise here */
6741 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6743 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6745 params [0] = &handle;
6747 mono_runtime_invoke_checked (handle_set, res, params, &error);
6748 mono_error_raise_exception (&error); /* FIXME don't raise here */
6754 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6756 MONO_REQ_GC_UNSAFE_MODE;
6758 static MonoClassField *f_safe_handle = NULL;
6761 if (!f_safe_handle) {
6762 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6763 g_assert (f_safe_handle);
6766 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6772 mono_runtime_capture_context (MonoDomain *domain)
6774 MONO_REQ_GC_UNSAFE_MODE;
6776 RuntimeInvokeFunction runtime_invoke;
6778 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6779 MonoMethod *method = mono_get_context_capture_method ();
6780 MonoMethod *wrapper;
6783 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6784 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6785 domain->capture_context_method = mono_compile_method (method);
6788 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6790 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6793 * mono_async_result_new:
6794 * @domain:domain where the object will be created.
6795 * @handle: wait handle.
6796 * @state: state to pass to AsyncResult
6797 * @data: C closure data.
6799 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6800 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6804 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6806 MONO_REQ_GC_UNSAFE_MODE;
6809 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6810 mono_error_raise_exception (&error); /* FIXME don't raise here */
6811 MonoObject *context = mono_runtime_capture_context (domain);
6812 /* we must capture the execution context from the original thread */
6814 MONO_OBJECT_SETREF (res, execution_context, context);
6815 /* note: result may be null if the flow is suppressed */
6818 res->data = (void **)data;
6819 MONO_OBJECT_SETREF (res, object_data, object_data);
6820 MONO_OBJECT_SETREF (res, async_state, state);
6822 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6824 res->sync_completed = FALSE;
6825 res->completed = FALSE;
6831 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6833 MONO_REQ_GC_UNSAFE_MODE;
6840 g_assert (ares->async_delegate);
6842 ac = (MonoAsyncCall*) ares->object_data;
6844 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6846 gpointer wait_event = NULL;
6848 ac->msg->exc = NULL;
6849 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6850 MONO_OBJECT_SETREF (ac, res, res);
6852 mono_monitor_enter ((MonoObject*) ares);
6853 ares->completed = 1;
6855 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6856 mono_monitor_exit ((MonoObject*) ares);
6858 if (wait_event != NULL)
6859 SetEvent (wait_event);
6861 if (ac->cb_method) {
6862 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6863 mono_error_raise_exception (&error);
6871 mono_message_init (MonoDomain *domain,
6872 MonoMethodMessage *this_obj,
6873 MonoReflectionMethod *method,
6874 MonoArray *out_args)
6876 MONO_REQ_GC_UNSAFE_MODE;
6878 static MonoClass *object_array_klass;
6879 static MonoClass *byte_array_klass;
6880 static MonoClass *string_array_klass;
6882 MonoMethodSignature *sig = mono_method_signature (method->method);
6889 if (!object_array_klass) {
6892 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6894 byte_array_klass = klass;
6896 klass = mono_array_class_get (mono_defaults.string_class, 1);
6898 string_array_klass = klass;
6900 klass = mono_array_class_get (mono_defaults.object_class, 1);
6903 mono_atomic_store_release (&object_array_klass, klass);
6906 MONO_OBJECT_SETREF (this_obj, method, method);
6908 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6909 mono_error_raise_exception (&error); /* FIXME don't raise here */
6911 MONO_OBJECT_SETREF (this_obj, args, arr);
6913 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6914 mono_error_raise_exception (&error); /* FIXME don't raise here */
6916 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6918 this_obj->async_result = NULL;
6919 this_obj->call_type = CallType_Sync;
6921 names = g_new (char *, sig->param_count);
6922 mono_method_get_param_names (method->method, (const char **) names);
6924 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6925 mono_error_raise_exception (&error); /* FIXME don't raise here */
6927 MONO_OBJECT_SETREF (this_obj, names, arr);
6929 for (i = 0; i < sig->param_count; i++) {
6930 name = mono_string_new (domain, names [i]);
6931 mono_array_setref (this_obj->names, i, name);
6935 for (i = 0, j = 0; i < sig->param_count; i++) {
6936 if (sig->params [i]->byref) {
6938 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6939 mono_array_setref (this_obj->args, i, arg);
6943 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6947 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6950 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6954 #ifndef DISABLE_REMOTING
6956 * mono_remoting_invoke:
6957 * @real_proxy: pointer to a RealProxy object
6958 * @msg: The MonoMethodMessage to execute
6959 * @exc: used to store exceptions
6960 * @out_args: used to store output arguments
6962 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6963 * IMessage interface and it is not trivial to extract results from there. So
6964 * we call an helper method PrivateInvoke instead of calling
6965 * RealProxy::Invoke() directly.
6967 * Returns: the result object.
6970 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
6972 MONO_REQ_GC_UNSAFE_MODE;
6975 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6980 mono_error_init (error);
6982 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6985 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6987 mono_error_set_not_supported (error, "Linked away.");
6990 real_proxy->vtable->domain->private_invoke_method = im;
6993 pa [0] = real_proxy;
6998 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
6999 return_val_if_nok (error, NULL);
7006 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7007 MonoObject **exc, MonoArray **out_args)
7009 MONO_REQ_GC_UNSAFE_MODE;
7011 static MonoClass *object_array_klass;
7015 MonoMethodSignature *sig;
7018 int i, j, outarg_count = 0;
7020 #ifndef DISABLE_REMOTING
7021 if (target && mono_object_is_transparent_proxy (target)) {
7022 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7023 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7024 target = tp->rp->unwrapped_server;
7026 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
7027 mono_error_raise_exception (&error); /* FIXME don't raise here */
7034 domain = mono_domain_get ();
7035 method = msg->method->method;
7036 sig = mono_method_signature (method);
7038 for (i = 0; i < sig->param_count; i++) {
7039 if (sig->params [i]->byref)
7043 if (!object_array_klass) {
7046 klass = mono_array_class_get (mono_defaults.object_class, 1);
7049 mono_memory_barrier ();
7050 object_array_klass = klass;
7053 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
7054 mono_error_raise_exception (&error); /* FIXME don't raise here */
7056 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7059 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
7061 for (i = 0, j = 0; i < sig->param_count; i++) {
7062 if (sig->params [i]->byref) {
7064 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7065 mono_array_setref (*out_args, j, arg);
7074 * mono_object_to_string:
7076 * @exc: Any exception thrown by ToString (). May be NULL.
7078 * Returns: the result of calling ToString () on an object.
7081 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7083 MONO_REQ_GC_UNSAFE_MODE;
7085 static MonoMethod *to_string = NULL;
7094 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7096 method = mono_object_get_virtual_method (obj, to_string);
7098 // Unbox value type if needed
7099 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7100 target = mono_object_unbox (obj);
7104 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7105 if (*exc == NULL && !mono_error_ok (&error))
7106 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7108 mono_error_cleanup (&error);
7110 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7111 mono_error_raise_exception (&error); /* FIXME don't raise here */
7118 * mono_print_unhandled_exception:
7119 * @exc: The exception
7121 * Prints the unhandled exception.
7124 mono_print_unhandled_exception (MonoObject *exc)
7126 MONO_REQ_GC_UNSAFE_MODE;
7129 char *message = (char*)"";
7130 gboolean free_message = FALSE;
7133 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7134 message = g_strdup ("OutOfMemoryException");
7135 free_message = TRUE;
7136 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7137 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7138 free_message = TRUE;
7141 if (((MonoException*)exc)->native_trace_ips) {
7142 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7143 free_message = TRUE;
7145 MonoObject *other_exc = NULL;
7146 str = mono_object_to_string (exc, &other_exc);
7148 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7149 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7151 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7152 original_backtrace, nested_backtrace);
7154 g_free (original_backtrace);
7155 g_free (nested_backtrace);
7156 free_message = TRUE;
7158 message = mono_string_to_utf8_checked (str, &error);
7159 if (!mono_error_ok (&error)) {
7160 mono_error_cleanup (&error);
7161 message = (char *) "";
7163 free_message = TRUE;
7170 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7171 * exc->vtable->klass->name, message);
7173 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7180 * mono_delegate_ctor:
7181 * @this: pointer to an uninitialized delegate object
7182 * @target: target object
7183 * @addr: pointer to native code
7186 * Initialize a delegate and sets a specific method, not the one
7187 * associated with addr. This is useful when sharing generic code.
7188 * In that case addr will most probably not be associated with the
7189 * correct instantiation of the method.
7192 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7194 MONO_REQ_GC_UNSAFE_MODE;
7196 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7198 g_assert (this_obj);
7201 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7204 delegate->method = method;
7206 mono_stats.delegate_creations++;
7208 #ifndef DISABLE_REMOTING
7209 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7211 method = mono_marshal_get_remoting_invoke (method);
7212 delegate->method_ptr = mono_compile_method (method);
7213 MONO_OBJECT_SETREF (delegate, target, target);
7217 delegate->method_ptr = addr;
7218 MONO_OBJECT_SETREF (delegate, target, target);
7221 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7222 if (callbacks.init_delegate)
7223 callbacks.init_delegate (delegate);
7227 * mono_delegate_ctor:
7228 * @this: pointer to an uninitialized delegate object
7229 * @target: target object
7230 * @addr: pointer to native code
7232 * This is used to initialize a delegate.
7235 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7237 MONO_REQ_GC_UNSAFE_MODE;
7239 MonoDomain *domain = mono_domain_get ();
7241 MonoMethod *method = NULL;
7245 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7247 if (!ji && domain != mono_get_root_domain ())
7248 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7250 method = mono_jit_info_get_method (ji);
7251 g_assert (!method->klass->generic_container);
7254 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7258 * mono_method_call_message_new:
7259 * @method: method to encapsulate
7260 * @params: parameters to the method
7261 * @invoke: optional, delegate invoke.
7262 * @cb: async callback delegate.
7263 * @state: state passed to the async callback.
7265 * Translates arguments pointers into a MonoMethodMessage.
7268 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7269 MonoDelegate **cb, MonoObject **state)
7271 MONO_REQ_GC_UNSAFE_MODE;
7275 MonoDomain *domain = mono_domain_get ();
7276 MonoMethodSignature *sig = mono_method_signature (method);
7277 MonoMethodMessage *msg;
7280 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7281 mono_error_raise_exception (&error); /* FIXME don't raise here */
7284 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7285 mono_error_raise_exception (&error); /* FIXME don't raise here */
7286 mono_message_init (domain, msg, rm, NULL);
7287 count = sig->param_count - 2;
7289 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7290 mono_error_raise_exception (&error); /* FIXME don't raise here */
7291 mono_message_init (domain, msg, rm, NULL);
7292 count = sig->param_count;
7295 for (i = 0; i < count; i++) {
7300 if (sig->params [i]->byref)
7301 vpos = *((gpointer *)params [i]);
7305 klass = mono_class_from_mono_type (sig->params [i]);
7307 if (klass->valuetype) {
7308 arg = mono_value_box_checked (domain, klass, vpos, &error);
7309 mono_error_raise_exception (&error); /* FIXME don't raise here */
7311 arg = *((MonoObject **)vpos);
7313 mono_array_setref (msg->args, i, arg);
7316 if (cb != NULL && state != NULL) {
7317 *cb = *((MonoDelegate **)params [i]);
7319 *state = *((MonoObject **)params [i]);
7326 * mono_method_return_message_restore:
7328 * Restore results from message based processing back to arguments pointers
7331 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7333 MONO_REQ_GC_UNSAFE_MODE;
7335 MonoMethodSignature *sig = mono_method_signature (method);
7336 int i, j, type, size, out_len;
7338 if (out_args == NULL)
7340 out_len = mono_array_length (out_args);
7344 for (i = 0, j = 0; i < sig->param_count; i++) {
7345 MonoType *pt = sig->params [i];
7350 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7352 arg = (char *)mono_array_get (out_args, gpointer, j);
7355 g_assert (type != MONO_TYPE_VOID);
7357 if (MONO_TYPE_IS_REFERENCE (pt)) {
7358 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7361 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7362 size = mono_class_value_size (klass, NULL);
7363 if (klass->has_references)
7364 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7366 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7368 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7369 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7378 #ifndef DISABLE_REMOTING
7381 * mono_load_remote_field:
7382 * @this: pointer to an object
7383 * @klass: klass of the object containing @field
7384 * @field: the field to load
7385 * @res: a storage to store the result
7387 * This method is called by the runtime on attempts to load fields of
7388 * transparent proxy objects. @this points to such TP, @klass is the class of
7389 * the object containing @field. @res is a storage location which can be
7390 * used to store the result.
7392 * Returns: an address pointing to the value of field.
7395 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7397 MONO_REQ_GC_UNSAFE_MODE;
7401 static MonoMethod *getter = NULL;
7402 MonoDomain *domain = mono_domain_get ();
7403 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7404 MonoClass *field_class;
7405 MonoMethodMessage *msg;
7406 MonoArray *out_args;
7410 g_assert (mono_object_is_transparent_proxy (this_obj));
7411 g_assert (res != NULL);
7413 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7414 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7419 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7421 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7424 field_class = mono_class_from_mono_type (field->type);
7426 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7427 mono_error_raise_exception (&error); /* FIXME don't raise here */
7428 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7429 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7430 mono_error_raise_exception (&error); /* FIXME don't raise here */
7431 mono_message_init (domain, msg, rm, out_args);
7433 full_name = mono_type_get_full_name (klass);
7434 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7435 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7438 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7439 mono_error_raise_exception (&error); /* FIXME don't raise here */
7441 if (exc) mono_raise_exception ((MonoException *)exc);
7443 if (mono_array_length (out_args) == 0)
7446 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7448 if (field_class->valuetype) {
7449 return ((char *)*res) + sizeof (MonoObject);
7455 * mono_load_remote_field_new:
7460 * Missing documentation.
7463 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7465 MONO_REQ_GC_UNSAFE_MODE;
7469 static MonoMethod *getter = NULL;
7470 MonoDomain *domain = mono_domain_get ();
7471 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7472 MonoClass *field_class;
7473 MonoMethodMessage *msg;
7474 MonoArray *out_args;
7475 MonoObject *exc, *res;
7478 g_assert (mono_object_is_transparent_proxy (this_obj));
7480 field_class = mono_class_from_mono_type (field->type);
7482 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7484 if (field_class->valuetype) {
7485 res = mono_object_new_checked (domain, field_class, &error);
7486 mono_error_raise_exception (&error); /* FIXME don't raise here */
7487 val = ((gchar *) res) + sizeof (MonoObject);
7491 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7496 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7498 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7501 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7502 mono_error_raise_exception (&error); /* FIXME don't raise here */
7503 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7505 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7506 mono_error_raise_exception (&error); /* FIXME don't raise here */
7507 mono_message_init (domain, msg, rm, out_args);
7509 full_name = mono_type_get_full_name (klass);
7510 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7511 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7514 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7515 mono_error_raise_exception (&error); /* FIXME don't raise here */
7517 if (exc) mono_raise_exception ((MonoException *)exc);
7519 if (mono_array_length (out_args) == 0)
7522 res = mono_array_get (out_args, MonoObject *, 0);
7528 * mono_store_remote_field:
7529 * @this_obj: pointer to an object
7530 * @klass: klass of the object containing @field
7531 * @field: the field to load
7532 * @val: the value/object to store
7534 * This method is called by the runtime on attempts to store fields of
7535 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7536 * the object containing @field. @val is the new value to store in @field.
7539 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7541 MONO_REQ_GC_UNSAFE_MODE;
7545 static MonoMethod *setter = NULL;
7546 MonoDomain *domain = mono_domain_get ();
7547 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7548 MonoClass *field_class;
7549 MonoMethodMessage *msg;
7550 MonoArray *out_args;
7555 g_assert (mono_object_is_transparent_proxy (this_obj));
7557 field_class = mono_class_from_mono_type (field->type);
7559 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7560 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7561 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7566 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7568 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7571 if (field_class->valuetype) {
7572 arg = mono_value_box_checked (domain, field_class, val, &error);
7573 mono_error_raise_exception (&error); /* FIXME don't raise here */
7575 arg = *((MonoObject **)val);
7578 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7579 mono_error_raise_exception (&error); /* FIXME don't raise here */
7580 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7581 mono_error_raise_exception (&error); /* FIXME don't raise here */
7582 mono_message_init (domain, msg, rm, NULL);
7584 full_name = mono_type_get_full_name (klass);
7585 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7586 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7587 mono_array_setref (msg->args, 2, arg);
7590 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7591 mono_error_raise_exception (&error); /* FIXME don't raise here */
7593 if (exc) mono_raise_exception ((MonoException *)exc);
7597 * mono_store_remote_field_new:
7603 * Missing documentation
7606 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7608 MONO_REQ_GC_UNSAFE_MODE;
7612 static MonoMethod *setter = NULL;
7613 MonoDomain *domain = mono_domain_get ();
7614 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7615 MonoClass *field_class;
7616 MonoMethodMessage *msg;
7617 MonoArray *out_args;
7621 g_assert (mono_object_is_transparent_proxy (this_obj));
7623 field_class = mono_class_from_mono_type (field->type);
7625 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7626 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7627 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7632 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7634 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7637 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7638 mono_error_raise_exception (&error); /* FIXME don't raise here */
7639 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7640 mono_error_raise_exception (&error); /* FIXME don't raise here */
7641 mono_message_init (domain, msg, rm, NULL);
7643 full_name = mono_type_get_full_name (klass);
7644 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7645 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7646 mono_array_setref (msg->args, 2, arg);
7649 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, &error);
7650 mono_error_raise_exception (&error); /* FIXME don't raise here */
7652 if (exc) mono_raise_exception ((MonoException *)exc);
7657 * mono_create_ftnptr:
7659 * Given a function address, create a function descriptor for it.
7660 * This is only needed on some platforms.
7663 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7665 return callbacks.create_ftnptr (domain, addr);
7669 * mono_get_addr_from_ftnptr:
7671 * Given a pointer to a function descriptor, return the function address.
7672 * This is only needed on some platforms.
7675 mono_get_addr_from_ftnptr (gpointer descr)
7677 return callbacks.get_addr_from_ftnptr (descr);
7681 * mono_string_chars:
7684 * Returns a pointer to the UCS16 characters stored in the MonoString
7687 mono_string_chars (MonoString *s)
7689 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7695 * mono_string_length:
7698 * Returns the lenght in characters of the string
7701 mono_string_length (MonoString *s)
7703 MONO_REQ_GC_UNSAFE_MODE;
7709 * mono_array_length:
7710 * @array: a MonoArray*
7712 * Returns the total number of elements in the array. This works for
7713 * both vectors and multidimensional arrays.
7716 mono_array_length (MonoArray *array)
7718 MONO_REQ_GC_UNSAFE_MODE;
7720 return array->max_length;
7724 * mono_array_addr_with_size:
7725 * @array: a MonoArray*
7726 * @size: size of the array elements
7727 * @idx: index into the array
7729 * Use this function to obtain the address for the @idx item on the
7730 * @array containing elements of size @size.
7732 * This method performs no bounds checking or type checking.
7734 * Returns the address of the @idx element in the array.
7737 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7739 MONO_REQ_GC_UNSAFE_MODE;
7741 return ((char*)(array)->vector) + size * idx;
7746 mono_glist_to_array (GList *list, MonoClass *eclass)
7748 MonoDomain *domain = mono_domain_get ();
7755 len = g_list_length (list);
7756 res = mono_array_new (domain, eclass, len);
7758 for (i = 0; list; list = list->next, i++)
7759 mono_array_set (res, gpointer, i, list->data);
7766 * The following section is purely to declare prototypes and
7767 * document the API, as these C files are processed by our
7773 * @array: array to alter
7774 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7775 * @index: index into the array
7776 * @value: value to set
7778 * Value Type version: This sets the @index's element of the @array
7779 * with elements of size sizeof(type) to the provided @value.
7781 * This macro does not attempt to perform type checking or bounds checking.
7783 * Use this to set value types in a `MonoArray`.
7785 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7790 * mono_array_setref:
7791 * @array: array to alter
7792 * @index: index into the array
7793 * @value: value to set
7795 * Reference Type version: This sets the @index's element of the
7796 * @array with elements of size sizeof(type) to the provided @value.
7798 * This macro does not attempt to perform type checking or bounds checking.
7800 * Use this to reference types in a `MonoArray`.
7802 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7808 * @array: array on which to operate on
7809 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7810 * @index: index into the array
7812 * Use this macro to retrieve the @index element of an @array and
7813 * extract the value assuming that the elements of the array match
7814 * the provided type value.
7816 * This method can be used with both arrays holding value types and
7817 * reference types. For reference types, the @type parameter should
7818 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7820 * This macro does not attempt to perform type checking or bounds checking.
7822 * Returns: The element at the @index position in the @array.
7824 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)