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, MonoError *error);
56 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
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, MonoError *error)
635 MONO_REQ_GC_NEUTRAL_MODE;
637 mono_error_init (error);
638 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
643 mono_runtime_create_delegate_trampoline (MonoClass *klass)
645 MONO_REQ_GC_NEUTRAL_MODE
647 return arch_create_delegate_trampoline (mono_domain_get (), klass);
650 static MonoFreeMethodFunc default_mono_free_method = NULL;
653 * mono_install_free_method:
654 * @func: pointer to the MonoFreeMethodFunc used to release a method
656 * This is an internal VM routine, it is used for the engines to
657 * register a handler to release the resources associated with a method.
659 * Methods are freed when no more references to the delegate that holds
663 mono_install_free_method (MonoFreeMethodFunc func)
665 default_mono_free_method = func;
669 * mono_runtime_free_method:
670 * @domain; domain where the method is hosted
671 * @method: method to release
673 * This routine is invoked to free the resources associated with
674 * a method that has been JIT compiled. This is used to discard
675 * methods that were used only temporarily (for example, used in marshalling)
679 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
681 MONO_REQ_GC_NEUTRAL_MODE
683 if (default_mono_free_method != NULL)
684 default_mono_free_method (domain, method);
686 mono_method_clear_object (domain, method);
688 mono_free_method (method);
692 * The vtables in the root appdomain are assumed to be reachable by other
693 * roots, and we don't use typed allocation in the other domains.
696 /* The sync block is no longer a GC pointer */
697 #define GC_HEADER_BITMAP (0)
699 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
702 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
704 MONO_REQ_GC_NEUTRAL_MODE;
706 MonoClassField *field;
712 max_size = mono_class_data_size (klass) / sizeof (gpointer);
714 max_size = klass->instance_size / sizeof (gpointer);
715 if (max_size > size) {
716 g_assert (offset <= 0);
717 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
722 /*An Ephemeron cannot be marked by sgen*/
723 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
725 memset (bitmap, 0, size / 8);
730 for (p = klass; p != NULL; p = p->parent) {
731 gpointer iter = NULL;
732 while ((field = mono_class_get_fields (p, &iter))) {
736 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
738 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
741 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
744 /* FIXME: should not happen, flag as type load error */
745 if (field->type->byref)
748 if (static_fields && field->offset == -1)
752 pos = field->offset / sizeof (gpointer);
755 type = mono_type_get_underlying_type (field->type);
756 switch (type->type) {
759 case MONO_TYPE_FNPTR:
761 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
766 if (klass->image != mono_defaults.corlib)
769 case MONO_TYPE_STRING:
770 case MONO_TYPE_SZARRAY:
771 case MONO_TYPE_CLASS:
772 case MONO_TYPE_OBJECT:
773 case MONO_TYPE_ARRAY:
774 g_assert ((field->offset % sizeof(gpointer)) == 0);
776 g_assert (pos < size || pos <= max_size);
777 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
778 *max_set = MAX (*max_set, pos);
780 case MONO_TYPE_GENERICINST:
781 if (!mono_type_generic_inst_is_valuetype (type)) {
782 g_assert ((field->offset % sizeof(gpointer)) == 0);
784 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
785 *max_set = MAX (*max_set, pos);
790 case MONO_TYPE_VALUETYPE: {
791 MonoClass *fclass = mono_class_from_mono_type (field->type);
792 if (fclass->has_references) {
793 /* remove the object header */
794 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
808 case MONO_TYPE_BOOLEAN:
812 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
823 * mono_class_compute_bitmap:
825 * Mono internal function to compute a bitmap of reference fields in a class.
828 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
830 MONO_REQ_GC_NEUTRAL_MODE;
832 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
837 * similar to the above, but sets the bits in the bitmap for any non-ref field
838 * and ignores static fields
841 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
843 MonoClassField *field;
848 max_size = class->instance_size / sizeof (gpointer);
849 if (max_size >= size) {
850 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
853 for (p = class; p != NULL; p = p->parent) {
854 gpointer iter = NULL;
855 while ((field = mono_class_get_fields (p, &iter))) {
858 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
860 /* FIXME: should not happen, flag as type load error */
861 if (field->type->byref)
864 pos = field->offset / sizeof (gpointer);
867 type = mono_type_get_underlying_type (field->type);
868 switch (type->type) {
869 #if SIZEOF_VOID_P == 8
873 case MONO_TYPE_FNPTR:
878 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
879 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
880 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
883 #if SIZEOF_VOID_P == 4
887 case MONO_TYPE_FNPTR:
892 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
893 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
894 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
901 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
902 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
905 case MONO_TYPE_BOOLEAN:
908 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
910 case MONO_TYPE_STRING:
911 case MONO_TYPE_SZARRAY:
912 case MONO_TYPE_CLASS:
913 case MONO_TYPE_OBJECT:
914 case MONO_TYPE_ARRAY:
916 case MONO_TYPE_GENERICINST:
917 if (!mono_type_generic_inst_is_valuetype (type)) {
922 case MONO_TYPE_VALUETYPE: {
923 MonoClass *fclass = mono_class_from_mono_type (field->type);
924 /* remove the object header */
925 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
929 g_assert_not_reached ();
938 * mono_class_insecure_overlapping:
939 * check if a class with explicit layout has references and non-references
940 * fields overlapping.
942 * Returns: TRUE if it is insecure to load the type.
945 mono_class_insecure_overlapping (MonoClass *klass)
949 gsize default_bitmap [4] = {0};
951 gsize default_nrbitmap [4] = {0};
952 int i, insecure = FALSE;
955 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
956 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
958 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
959 int idx = i % (sizeof (bitmap [0]) * 8);
960 if (bitmap [idx] & nrbitmap [idx]) {
965 if (bitmap != default_bitmap)
967 if (nrbitmap != default_nrbitmap)
970 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
978 ves_icall_string_alloc (int length)
981 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
982 mono_error_set_pending_exception (&error);
988 mono_class_compute_gc_descriptor (MonoClass *klass)
990 MONO_REQ_GC_NEUTRAL_MODE;
994 gsize default_bitmap [4] = {0};
995 static gboolean gcj_inited = FALSE;
1000 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1001 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1004 mono_loader_unlock ();
1008 mono_class_init (klass);
1010 if (klass->gc_descr_inited)
1013 klass->gc_descr_inited = TRUE;
1014 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1016 bitmap = default_bitmap;
1017 if (klass == mono_defaults.string_class) {
1018 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1019 } else if (klass->rank) {
1020 mono_class_compute_gc_descriptor (klass->element_class);
1021 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1023 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1024 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1025 class->name_space, class->name);*/
1027 /* remove the object header */
1028 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1029 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));
1030 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1031 class->name_space, class->name);*/
1032 if (bitmap != default_bitmap)
1036 /*static int count = 0;
1039 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1040 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1042 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1043 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1045 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1046 if (bitmap != default_bitmap)
1052 * field_is_special_static:
1053 * @fklass: The MonoClass to look up.
1054 * @field: The MonoClassField describing the field.
1056 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1057 * SPECIAL_STATIC_NONE otherwise.
1060 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1062 MONO_REQ_GC_NEUTRAL_MODE;
1065 MonoCustomAttrInfo *ainfo;
1067 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1068 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1071 for (i = 0; i < ainfo->num_attrs; ++i) {
1072 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1073 if (klass->image == mono_defaults.corlib) {
1074 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1075 mono_custom_attrs_free (ainfo);
1076 return SPECIAL_STATIC_THREAD;
1078 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1079 mono_custom_attrs_free (ainfo);
1080 return SPECIAL_STATIC_CONTEXT;
1084 mono_custom_attrs_free (ainfo);
1085 return SPECIAL_STATIC_NONE;
1088 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1089 #define mix(a,b,c) { \
1090 a -= c; a ^= rot(c, 4); c += b; \
1091 b -= a; b ^= rot(a, 6); a += c; \
1092 c -= b; c ^= rot(b, 8); b += a; \
1093 a -= c; a ^= rot(c,16); c += b; \
1094 b -= a; b ^= rot(a,19); a += c; \
1095 c -= b; c ^= rot(b, 4); b += a; \
1097 #define final(a,b,c) { \
1098 c ^= b; c -= rot(b,14); \
1099 a ^= c; a -= rot(c,11); \
1100 b ^= a; b -= rot(a,25); \
1101 c ^= b; c -= rot(b,16); \
1102 a ^= c; a -= rot(c,4); \
1103 b ^= a; b -= rot(a,14); \
1104 c ^= b; c -= rot(b,24); \
1108 * mono_method_get_imt_slot:
1110 * The IMT slot is embedded into AOTed code, so this must return the same value
1111 * for the same method across all executions. This means:
1112 * - pointers shouldn't be used as hash values.
1113 * - mono_metadata_str_hash () should be used for hashing strings.
1116 mono_method_get_imt_slot (MonoMethod *method)
1118 MONO_REQ_GC_NEUTRAL_MODE;
1120 MonoMethodSignature *sig;
1122 guint32 *hashes_start, *hashes;
1126 /* This can be used to stress tests the collision code */
1130 * We do this to simplify generic sharing. It will hurt
1131 * performance in cases where a class implements two different
1132 * instantiations of the same generic interface.
1133 * The code in build_imt_slots () depends on this.
1135 if (method->is_inflated)
1136 method = ((MonoMethodInflated*)method)->declaring;
1138 sig = mono_method_signature (method);
1139 hashes_count = sig->param_count + 4;
1140 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1141 hashes = hashes_start;
1143 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1144 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1145 method->klass->name_space, method->klass->name, method->name);
1148 /* Initialize hashes */
1149 hashes [0] = mono_metadata_str_hash (method->klass->name);
1150 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1151 hashes [2] = mono_metadata_str_hash (method->name);
1152 hashes [3] = mono_metadata_type_hash (sig->ret);
1153 for (i = 0; i < sig->param_count; i++) {
1154 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1157 /* Setup internal state */
1158 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1160 /* Handle most of the hashes */
1161 while (hashes_count > 3) {
1170 /* Handle the last 3 hashes (all the case statements fall through) */
1171 switch (hashes_count) {
1172 case 3 : c += hashes [2];
1173 case 2 : b += hashes [1];
1174 case 1 : a += hashes [0];
1176 case 0: /* nothing left to add */
1180 free (hashes_start);
1181 /* Report the result */
1182 return c % MONO_IMT_SIZE;
1191 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1192 MONO_REQ_GC_NEUTRAL_MODE;
1194 guint32 imt_slot = mono_method_get_imt_slot (method);
1195 MonoImtBuilderEntry *entry;
1197 if (slot_num >= 0 && imt_slot != slot_num) {
1198 /* we build just a single imt slot and this is not it */
1202 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1203 entry->key = method;
1204 entry->value.vtable_slot = vtable_slot;
1205 entry->next = imt_builder [imt_slot];
1206 if (imt_builder [imt_slot] != NULL) {
1207 entry->children = imt_builder [imt_slot]->children + 1;
1208 if (entry->children == 1) {
1209 mono_stats.imt_slots_with_collisions++;
1210 *imt_collisions_bitmap |= (1 << imt_slot);
1213 entry->children = 0;
1214 mono_stats.imt_used_slots++;
1216 imt_builder [imt_slot] = entry;
1219 char *method_name = mono_method_full_name (method, TRUE);
1220 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1221 method, method_name, imt_slot, vtable_slot, entry->children);
1222 g_free (method_name);
1229 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1231 MonoMethod *method = e->key;
1232 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1236 method->klass->name_space,
1237 method->klass->name,
1240 printf (" * %s: NULL\n", message);
1246 compare_imt_builder_entries (const void *p1, const void *p2) {
1247 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1248 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1250 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1254 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1256 MONO_REQ_GC_NEUTRAL_MODE;
1258 int count = end - start;
1259 int chunk_start = out_array->len;
1262 for (i = start; i < end; ++i) {
1263 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1264 item->key = sorted_array [i]->key;
1265 item->value = sorted_array [i]->value;
1266 item->has_target_code = sorted_array [i]->has_target_code;
1267 item->is_equals = TRUE;
1269 item->check_target_idx = out_array->len + 1;
1271 item->check_target_idx = 0;
1272 g_ptr_array_add (out_array, item);
1275 int middle = start + count / 2;
1276 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1278 item->key = sorted_array [middle]->key;
1279 item->is_equals = FALSE;
1280 g_ptr_array_add (out_array, item);
1281 imt_emit_ir (sorted_array, start, middle, out_array);
1282 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1288 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1289 MONO_REQ_GC_NEUTRAL_MODE;
1291 int number_of_entries = entries->children + 1;
1292 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1293 GPtrArray *result = g_ptr_array_new ();
1294 MonoImtBuilderEntry *current_entry;
1297 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1298 sorted_array [i] = current_entry;
1300 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1302 /*for (i = 0; i < number_of_entries; i++) {
1303 print_imt_entry (" sorted array:", sorted_array [i], i);
1306 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1308 free (sorted_array);
1313 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1315 MONO_REQ_GC_NEUTRAL_MODE;
1317 if (imt_builder_entry != NULL) {
1318 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1319 /* No collision, return the vtable slot contents */
1320 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1322 /* Collision, build the thunk */
1323 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1326 result = imt_thunk_builder (vtable, domain,
1327 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1328 for (i = 0; i < imt_ir->len; ++i)
1329 g_free (g_ptr_array_index (imt_ir, i));
1330 g_ptr_array_free (imt_ir, TRUE);
1342 static MonoImtBuilderEntry*
1343 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1346 * LOCKING: requires the loader and domain locks.
1350 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1352 MONO_REQ_GC_NEUTRAL_MODE;
1356 guint32 imt_collisions_bitmap = 0;
1357 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1358 int method_count = 0;
1359 gboolean record_method_count_for_max_collisions = FALSE;
1360 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1363 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1365 for (i = 0; i < klass->interface_offsets_count; ++i) {
1366 MonoClass *iface = klass->interfaces_packed [i];
1367 int interface_offset = klass->interface_offsets_packed [i];
1368 int method_slot_in_interface, vt_slot;
1370 if (mono_class_has_variant_generic_params (iface))
1371 has_variant_iface = TRUE;
1373 mono_class_setup_methods (iface);
1374 vt_slot = interface_offset;
1375 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1378 if (slot_num >= 0 && iface->is_inflated) {
1380 * The imt slot of the method is the same as for its declaring method,
1381 * see the comment in mono_method_get_imt_slot (), so we can
1382 * avoid inflating methods which will be discarded by
1383 * add_imt_builder_entry anyway.
1385 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1386 if (mono_method_get_imt_slot (method) != slot_num) {
1391 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1392 if (method->is_generic) {
1393 has_generic_virtual = TRUE;
1398 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1399 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1404 if (extra_interfaces) {
1405 int interface_offset = klass->vtable_size;
1407 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1408 MonoClass* iface = (MonoClass *)list_item->data;
1409 int method_slot_in_interface;
1410 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1411 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1413 if (method->is_generic)
1414 has_generic_virtual = TRUE;
1415 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1417 interface_offset += iface->method.count;
1420 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1421 /* overwrite the imt slot only if we're building all the entries or if
1422 * we're building this specific one
1424 if (slot_num < 0 || i == slot_num) {
1425 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1428 if (imt_builder [i]) {
1429 MonoImtBuilderEntry *entry;
1431 /* Link entries with imt_builder [i] */
1432 for (entry = entries; entry->next; entry = entry->next) {
1434 MonoMethod *method = (MonoMethod*)entry->key;
1435 char *method_name = mono_method_full_name (method, TRUE);
1436 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1437 g_free (method_name);
1440 entry->next = imt_builder [i];
1441 entries->children += imt_builder [i]->children + 1;
1443 imt_builder [i] = entries;
1446 if (has_generic_virtual || has_variant_iface) {
1448 * There might be collisions later when the the thunk is expanded.
1450 imt_collisions_bitmap |= (1 << i);
1453 * The IMT thunk might be called with an instance of one of the
1454 * generic virtual methods, so has to fallback to the IMT trampoline.
1456 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1458 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1461 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1465 if (imt_builder [i] != NULL) {
1466 int methods_in_slot = imt_builder [i]->children + 1;
1467 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1468 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1469 record_method_count_for_max_collisions = TRUE;
1471 method_count += methods_in_slot;
1475 mono_stats.imt_number_of_methods += method_count;
1476 if (record_method_count_for_max_collisions) {
1477 mono_stats.imt_method_count_when_max_collisions = method_count;
1480 for (i = 0; i < MONO_IMT_SIZE; i++) {
1481 MonoImtBuilderEntry* entry = imt_builder [i];
1482 while (entry != NULL) {
1483 MonoImtBuilderEntry* next = entry->next;
1489 /* we OR the bitmap since we may build just a single imt slot at a time */
1490 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1494 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1495 MONO_REQ_GC_NEUTRAL_MODE;
1497 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1501 * mono_vtable_build_imt_slot:
1502 * @vtable: virtual object table struct
1503 * @imt_slot: slot in the IMT table
1505 * Fill the given @imt_slot in the IMT table of @vtable with
1506 * a trampoline or a thunk for the case of collisions.
1507 * This is part of the internal mono API.
1509 * LOCKING: Take the domain lock.
1512 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1514 MONO_REQ_GC_NEUTRAL_MODE;
1516 gpointer *imt = (gpointer*)vtable;
1517 imt -= MONO_IMT_SIZE;
1518 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1520 /* no support for extra interfaces: the proxy objects will need
1521 * to build the complete IMT
1522 * Update and heck needs to ahppen inside the proper domain lock, as all
1523 * the changes made to a MonoVTable.
1525 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1526 mono_domain_lock (vtable->domain);
1527 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1528 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1529 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1530 mono_domain_unlock (vtable->domain);
1531 mono_loader_unlock ();
1536 * The first two free list entries both belong to the wait list: The
1537 * first entry is the pointer to the head of the list and the second
1538 * entry points to the last element. That way appending and removing
1539 * the first element are both O(1) operations.
1541 #ifdef MONO_SMALL_CONFIG
1542 #define NUM_FREE_LISTS 6
1544 #define NUM_FREE_LISTS 12
1546 #define FIRST_FREE_LIST_SIZE 64
1547 #define MAX_WAIT_LENGTH 50
1548 #define THUNK_THRESHOLD 10
1551 * LOCKING: The domain lock must be held.
1554 init_thunk_free_lists (MonoDomain *domain)
1556 MONO_REQ_GC_NEUTRAL_MODE;
1558 if (domain->thunk_free_lists)
1560 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1564 list_index_for_size (int item_size)
1567 int size = FIRST_FREE_LIST_SIZE;
1569 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1578 * mono_method_alloc_generic_virtual_thunk:
1580 * @size: size in bytes
1582 * Allocs size bytes to be used for the code of a generic virtual
1583 * thunk. It's either allocated from the domain's code manager or
1584 * reused from a previously invalidated piece.
1586 * LOCKING: The domain lock must be held.
1589 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1591 MONO_REQ_GC_NEUTRAL_MODE;
1593 static gboolean inited = FALSE;
1594 static int generic_virtual_thunks_size = 0;
1598 MonoThunkFreeList **l;
1600 init_thunk_free_lists (domain);
1602 size += sizeof (guint32);
1603 if (size < sizeof (MonoThunkFreeList))
1604 size = sizeof (MonoThunkFreeList);
1606 i = list_index_for_size (size);
1607 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1608 if ((*l)->size >= size) {
1609 MonoThunkFreeList *item = *l;
1611 return ((guint32*)item) + 1;
1615 /* no suitable item found - search lists of larger sizes */
1616 while (++i < NUM_FREE_LISTS) {
1617 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1620 g_assert (item->size > size);
1621 domain->thunk_free_lists [i] = item->next;
1622 return ((guint32*)item) + 1;
1625 /* still nothing found - allocate it */
1627 mono_counters_register ("Generic virtual thunk bytes",
1628 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1631 generic_virtual_thunks_size += size;
1633 p = (guint32 *)mono_domain_code_reserve (domain, size);
1636 mono_domain_lock (domain);
1637 if (!domain->generic_virtual_thunks)
1638 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1639 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1640 mono_domain_unlock (domain);
1646 * LOCKING: The domain lock must be held.
1649 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1651 MONO_REQ_GC_NEUTRAL_MODE;
1653 guint32 *p = (guint32 *)code;
1654 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1655 gboolean found = FALSE;
1657 mono_domain_lock (domain);
1658 if (!domain->generic_virtual_thunks)
1659 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1660 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1662 mono_domain_unlock (domain);
1665 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1667 init_thunk_free_lists (domain);
1669 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1670 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1671 int length = item->length;
1674 /* unlink the first item from the wait list */
1675 domain->thunk_free_lists [0] = item->next;
1676 domain->thunk_free_lists [0]->length = length - 1;
1678 i = list_index_for_size (item->size);
1680 /* put it in the free list */
1681 item->next = domain->thunk_free_lists [i];
1682 domain->thunk_free_lists [i] = item;
1686 if (domain->thunk_free_lists [1]) {
1687 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1688 domain->thunk_free_lists [0]->length++;
1690 g_assert (!domain->thunk_free_lists [0]);
1692 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1693 domain->thunk_free_lists [0]->length = 1;
1697 typedef struct _GenericVirtualCase {
1701 struct _GenericVirtualCase *next;
1702 } GenericVirtualCase;
1705 * get_generic_virtual_entries:
1707 * Return IMT entries for the generic virtual method instances and
1708 * variant interface methods for vtable slot
1711 static MonoImtBuilderEntry*
1712 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1714 MONO_REQ_GC_NEUTRAL_MODE;
1716 GenericVirtualCase *list;
1717 MonoImtBuilderEntry *entries;
1719 mono_domain_lock (domain);
1720 if (!domain->generic_virtual_cases)
1721 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1723 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1726 for (; list; list = list->next) {
1727 MonoImtBuilderEntry *entry;
1729 if (list->count < THUNK_THRESHOLD)
1732 entry = g_new0 (MonoImtBuilderEntry, 1);
1733 entry->key = list->method;
1734 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1735 entry->has_target_code = 1;
1737 entry->children = entries->children + 1;
1738 entry->next = entries;
1742 mono_domain_unlock (domain);
1744 /* FIXME: Leaking memory ? */
1749 * mono_method_add_generic_virtual_invocation:
1751 * @vtable_slot: pointer to the vtable slot
1752 * @method: the inflated generic virtual method
1753 * @code: the method's code
1755 * Registers a call via unmanaged code to a generic virtual method
1756 * instantiation or variant interface method. If the number of calls reaches a threshold
1757 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1758 * virtual method thunk.
1761 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1762 gpointer *vtable_slot,
1763 MonoMethod *method, gpointer code)
1765 MONO_REQ_GC_NEUTRAL_MODE;
1767 static gboolean inited = FALSE;
1768 static int num_added = 0;
1770 GenericVirtualCase *gvc, *list;
1771 MonoImtBuilderEntry *entries;
1775 mono_domain_lock (domain);
1776 if (!domain->generic_virtual_cases)
1777 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1779 /* Check whether the case was already added */
1780 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1783 if (gvc->method == method)
1788 /* If not found, make a new one */
1790 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1791 gvc->method = method;
1794 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1796 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1799 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1805 if (++gvc->count == THUNK_THRESHOLD) {
1806 gpointer *old_thunk = (void **)*vtable_slot;
1807 gpointer vtable_trampoline = NULL;
1808 gpointer imt_trampoline = NULL;
1810 if ((gpointer)vtable_slot < (gpointer)vtable) {
1811 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1812 int imt_slot = MONO_IMT_SIZE + displacement;
1814 /* Force the rebuild of the thunk at the next call */
1815 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1816 *vtable_slot = imt_trampoline;
1818 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1820 entries = get_generic_virtual_entries (domain, vtable_slot);
1822 sorted = imt_sort_slot_entries (entries);
1824 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1828 MonoImtBuilderEntry *next = entries->next;
1833 for (i = 0; i < sorted->len; ++i)
1834 g_free (g_ptr_array_index (sorted, i));
1835 g_ptr_array_free (sorted, TRUE);
1838 #ifndef __native_client__
1839 /* We don't re-use any thunks as there is a lot of overhead */
1840 /* to deleting and re-using code in Native Client. */
1841 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1842 invalidate_generic_virtual_thunk (domain, old_thunk);
1846 mono_domain_unlock (domain);
1849 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1852 * mono_class_vtable:
1853 * @domain: the application domain
1854 * @class: the class to initialize
1856 * VTables are domain specific because we create domain specific code, and
1857 * they contain the domain specific static class data.
1858 * On failure, NULL is returned, and class->exception_type is set.
1861 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1864 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1865 mono_error_cleanup (&error);
1870 * mono_class_vtable_full:
1871 * @domain: the application domain
1872 * @class: the class to initialize
1873 * @error set on failure.
1875 * VTables are domain specific because we create domain specific code, and
1876 * they contain the domain specific static class data.
1879 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1881 MONO_REQ_GC_UNSAFE_MODE;
1883 MonoClassRuntimeInfo *runtime_info;
1885 mono_error_init (error);
1889 if (mono_class_has_failure (klass)) {
1890 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1894 /* this check can be inlined in jitted code, too */
1895 runtime_info = klass->runtime_info;
1896 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1897 return runtime_info->domain_vtables [domain->domain_id];
1898 return mono_class_create_runtime_vtable (domain, klass, error);
1902 * mono_class_try_get_vtable:
1903 * @domain: the application domain
1904 * @class: the class to initialize
1906 * This function tries to get the associated vtable from @class if
1907 * it was already created.
1910 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1912 MONO_REQ_GC_NEUTRAL_MODE;
1914 MonoClassRuntimeInfo *runtime_info;
1918 runtime_info = klass->runtime_info;
1919 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1920 return runtime_info->domain_vtables [domain->domain_id];
1925 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1927 MONO_REQ_GC_NEUTRAL_MODE;
1929 size_t alloc_offset;
1932 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1933 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1934 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1936 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1937 g_assert ((imt_table_bytes & 7) == 4);
1944 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1948 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1950 MONO_REQ_GC_UNSAFE_MODE;
1953 MonoClassRuntimeInfo *runtime_info, *old_info;
1954 MonoClassField *field;
1956 int i, vtable_slots;
1957 size_t imt_table_bytes;
1959 guint32 vtable_size, class_size;
1961 gpointer *interface_offsets;
1963 mono_error_init (error);
1965 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1966 mono_domain_lock (domain);
1967 runtime_info = klass->runtime_info;
1968 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1969 mono_domain_unlock (domain);
1970 mono_loader_unlock ();
1971 return runtime_info->domain_vtables [domain->domain_id];
1973 if (!klass->inited || mono_class_has_failure (klass)) {
1974 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1975 mono_domain_unlock (domain);
1976 mono_loader_unlock ();
1977 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1982 /* Array types require that their element type be valid*/
1983 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1984 MonoClass *element_class = klass->element_class;
1985 if (!element_class->inited)
1986 mono_class_init (element_class);
1988 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1989 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1990 mono_class_setup_vtable (element_class);
1992 if (mono_class_has_failure (element_class)) {
1993 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1994 if (!mono_class_has_failure (klass))
1995 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1996 mono_domain_unlock (domain);
1997 mono_loader_unlock ();
1998 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2004 * For some classes, mono_class_init () already computed klass->vtable_size, and
2005 * that is all that is needed because of the vtable trampolines.
2007 if (!klass->vtable_size)
2008 mono_class_setup_vtable (klass);
2010 if (klass->generic_class && !klass->vtable)
2011 mono_class_check_vtable_constraints (klass, NULL);
2013 /* Initialize klass->has_finalize */
2014 mono_class_has_finalizer (klass);
2016 if (mono_class_has_failure (klass)) {
2017 mono_domain_unlock (domain);
2018 mono_loader_unlock ();
2019 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2023 vtable_slots = klass->vtable_size;
2024 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2025 class_size = mono_class_data_size (klass);
2029 if (klass->interface_offsets_count) {
2030 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2031 mono_stats.imt_number_of_tables++;
2032 mono_stats.imt_tables_size += imt_table_bytes;
2034 imt_table_bytes = 0;
2037 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2039 mono_stats.used_class_count++;
2040 mono_stats.class_vtable_size += vtable_size;
2042 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2043 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2044 g_assert (!((gsize)vt & 7));
2047 vt->rank = klass->rank;
2048 vt->domain = domain;
2050 mono_class_compute_gc_descriptor (klass);
2052 * We can't use typed allocation in the non-root domains, since the
2053 * collector needs the GC descriptor stored in the vtable even after
2054 * the mempool containing the vtable is destroyed when the domain is
2055 * unloaded. An alternative might be to allocate vtables in the GC
2056 * heap, but this does not seem to work (it leads to crashes inside
2057 * libgc). If that approach is tried, two gc descriptors need to be
2058 * allocated for each class: one for the root domain, and one for all
2059 * other domains. The second descriptor should contain a bit for the
2060 * vtable field in MonoObject, since we can no longer assume the
2061 * vtable is reachable by other roots after the appdomain is unloaded.
2063 #ifdef HAVE_BOEHM_GC
2064 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2065 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2068 vt->gc_descr = klass->gc_descr;
2070 gc_bits = mono_gc_get_vtable_bits (klass);
2071 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2073 vt->gc_bits = gc_bits;
2076 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2077 if (klass->has_static_refs) {
2078 MonoGCDescriptor statics_gc_descr;
2080 gsize default_bitmap [4] = {0};
2083 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2084 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2085 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2086 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2087 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2088 if (bitmap != default_bitmap)
2091 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2093 vt->has_static_fields = TRUE;
2094 mono_stats.class_static_data_size += class_size;
2098 while ((field = mono_class_get_fields (klass, &iter))) {
2099 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2101 if (mono_field_is_deleted (field))
2103 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2104 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2105 if (special_static != SPECIAL_STATIC_NONE) {
2106 guint32 size, offset;
2108 gsize default_bitmap [4] = {0};
2113 if (mono_type_is_reference (field->type)) {
2114 default_bitmap [0] = 1;
2116 bitmap = default_bitmap;
2117 } else if (mono_type_is_struct (field->type)) {
2118 fclass = mono_class_from_mono_type (field->type);
2119 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2120 numbits = max_set + 1;
2122 default_bitmap [0] = 0;
2124 bitmap = default_bitmap;
2126 size = mono_type_size (field->type, &align);
2127 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2128 if (!domain->special_static_fields)
2129 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2130 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2131 if (bitmap != default_bitmap)
2134 * This marks the field as special static to speed up the
2135 * checks in mono_field_static_get/set_value ().
2141 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2142 MonoClass *fklass = mono_class_from_mono_type (field->type);
2143 const char *data = mono_field_get_data (field);
2145 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2146 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2147 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2150 if (fklass->valuetype) {
2151 memcpy (t, data, mono_class_value_size (fklass, NULL));
2153 /* it's a pointer type: add check */
2154 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2161 vt->max_interface_id = klass->max_interface_id;
2162 vt->interface_bitmap = klass->interface_bitmap;
2164 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2165 // class->name, klass->interface_offsets_count);
2167 /* Initialize vtable */
2168 if (callbacks.get_vtable_trampoline) {
2169 // This also covers the AOT case
2170 for (i = 0; i < klass->vtable_size; ++i) {
2171 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2174 mono_class_setup_vtable (klass);
2176 for (i = 0; i < klass->vtable_size; ++i) {
2179 cm = klass->vtable [i];
2181 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2182 if (!is_ok (error)) {
2183 mono_domain_unlock (domain);
2184 mono_loader_unlock ();
2191 if (imt_table_bytes) {
2192 /* Now that the vtable is full, we can actually fill up the IMT */
2193 for (i = 0; i < MONO_IMT_SIZE; ++i)
2194 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2198 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2199 * re-acquire them and check if another thread has created the vtable in the meantime.
2201 /* Special case System.MonoType to avoid infinite recursion */
2202 if (klass != mono_defaults.monotype_class) {
2203 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2204 if (!is_ok (error)) {
2205 mono_domain_unlock (domain);
2206 mono_loader_unlock ();
2210 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2211 /* This is unregistered in
2212 unregister_vtable_reflection_type() in
2214 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2217 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2219 /* class_vtable_array keeps an array of created vtables
2221 g_ptr_array_add (domain->class_vtable_array, vt);
2222 /* klass->runtime_info is protected by the loader lock, both when
2223 * it it enlarged and when it is stored info.
2227 * Store the vtable in klass->runtime_info.
2228 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2230 mono_memory_barrier ();
2232 old_info = klass->runtime_info;
2233 if (old_info && old_info->max_domain >= domain->domain_id) {
2234 /* someone already created a large enough runtime info */
2235 old_info->domain_vtables [domain->domain_id] = vt;
2237 int new_size = domain->domain_id;
2239 new_size = MAX (new_size, old_info->max_domain);
2241 /* make the new size a power of two */
2243 while (new_size > i)
2246 /* this is a bounded memory retention issue: may want to
2247 * handle it differently when we'll have a rcu-like system.
2249 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2250 runtime_info->max_domain = new_size - 1;
2251 /* copy the stuff from the older info */
2253 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2255 runtime_info->domain_vtables [domain->domain_id] = vt;
2257 mono_memory_barrier ();
2258 klass->runtime_info = runtime_info;
2261 if (klass == mono_defaults.monotype_class) {
2262 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2263 if (!is_ok (error)) {
2264 mono_domain_unlock (domain);
2265 mono_loader_unlock ();
2269 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2270 /* This is unregistered in
2271 unregister_vtable_reflection_type() in
2273 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2276 mono_domain_unlock (domain);
2277 mono_loader_unlock ();
2279 /* make sure the parent is initialized */
2280 /*FIXME shouldn't this fail the current type?*/
2282 mono_class_vtable_full (domain, klass->parent, error);
2287 #ifndef DISABLE_REMOTING
2289 * mono_class_proxy_vtable:
2290 * @domain: the application domain
2291 * @remove_class: the remote class
2293 * Creates a vtable for transparent proxies. It is basically
2294 * a copy of the real vtable of the class wrapped in @remote_class,
2295 * but all function pointers invoke the remoting functions, and
2296 * vtable->klass points to the transparent proxy class, and not to @class.
2299 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2301 MONO_REQ_GC_UNSAFE_MODE;
2304 MonoVTable *vt, *pvt;
2305 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2307 GSList *extra_interfaces = NULL;
2308 MonoClass *klass = remote_class->proxy_class;
2309 gpointer *interface_offsets;
2312 size_t imt_table_bytes;
2314 #ifdef COMPRESSED_INTERFACE_BITMAP
2318 vt = mono_class_vtable (domain, klass);
2319 g_assert (vt); /*FIXME property handle failure*/
2320 max_interface_id = vt->max_interface_id;
2322 /* Calculate vtable space for extra interfaces */
2323 for (j = 0; j < remote_class->interface_count; j++) {
2324 MonoClass* iclass = remote_class->interfaces[j];
2328 /*FIXME test for interfaces with variant generic arguments*/
2329 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2330 continue; /* interface implemented by the class */
2331 if (g_slist_find (extra_interfaces, iclass))
2334 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2336 method_count = mono_class_num_methods (iclass);
2338 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2339 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2341 for (i = 0; i < ifaces->len; ++i) {
2342 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2343 /*FIXME test for interfaces with variant generic arguments*/
2344 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2345 continue; /* interface implemented by the class */
2346 if (g_slist_find (extra_interfaces, ic))
2348 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2349 method_count += mono_class_num_methods (ic);
2351 g_ptr_array_free (ifaces, TRUE);
2354 extra_interface_vtsize += method_count * sizeof (gpointer);
2355 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2358 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2359 mono_stats.imt_number_of_tables++;
2360 mono_stats.imt_tables_size += imt_table_bytes;
2362 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2364 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2366 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2367 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2368 g_assert (!((gsize)pvt & 7));
2370 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2372 pvt->klass = mono_defaults.transparent_proxy_class;
2373 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2374 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2376 /* initialize vtable */
2377 mono_class_setup_vtable (klass);
2378 for (i = 0; i < klass->vtable_size; ++i) {
2381 if ((cm = klass->vtable [i]))
2382 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2384 pvt->vtable [i] = NULL;
2387 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2388 /* create trampolines for abstract methods */
2389 for (k = klass; k; k = k->parent) {
2391 gpointer iter = NULL;
2392 while ((m = mono_class_get_methods (k, &iter)))
2393 if (!pvt->vtable [m->slot])
2394 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2398 pvt->max_interface_id = max_interface_id;
2399 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2400 #ifdef COMPRESSED_INTERFACE_BITMAP
2401 bitmap = (uint8_t *)g_malloc0 (bsize);
2403 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2406 for (i = 0; i < klass->interface_offsets_count; ++i) {
2407 int interface_id = klass->interfaces_packed [i]->interface_id;
2408 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2411 if (extra_interfaces) {
2412 int slot = klass->vtable_size;
2418 /* Create trampolines for the methods of the interfaces */
2419 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2420 interf = (MonoClass *)list_item->data;
2422 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2426 while ((cm = mono_class_get_methods (interf, &iter)))
2427 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2429 slot += mono_class_num_methods (interf);
2433 /* Now that the vtable is full, we can actually fill up the IMT */
2434 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2435 if (extra_interfaces) {
2436 g_slist_free (extra_interfaces);
2439 #ifdef COMPRESSED_INTERFACE_BITMAP
2440 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2441 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2442 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2445 pvt->interface_bitmap = bitmap;
2450 #endif /* DISABLE_REMOTING */
2453 * mono_class_field_is_special_static:
2455 * Returns whether @field is a thread/context static field.
2458 mono_class_field_is_special_static (MonoClassField *field)
2460 MONO_REQ_GC_NEUTRAL_MODE
2462 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2464 if (mono_field_is_deleted (field))
2466 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2467 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2474 * mono_class_field_get_special_static_type:
2475 * @field: The MonoClassField describing the field.
2477 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2478 * SPECIAL_STATIC_NONE otherwise.
2481 mono_class_field_get_special_static_type (MonoClassField *field)
2483 MONO_REQ_GC_NEUTRAL_MODE
2485 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2486 return SPECIAL_STATIC_NONE;
2487 if (mono_field_is_deleted (field))
2488 return SPECIAL_STATIC_NONE;
2489 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2490 return field_is_special_static (field->parent, field);
2491 return SPECIAL_STATIC_NONE;
2495 * mono_class_has_special_static_fields:
2497 * Returns whenever @klass has any thread/context static fields.
2500 mono_class_has_special_static_fields (MonoClass *klass)
2502 MONO_REQ_GC_NEUTRAL_MODE
2504 MonoClassField *field;
2508 while ((field = mono_class_get_fields (klass, &iter))) {
2509 g_assert (field->parent == klass);
2510 if (mono_class_field_is_special_static (field))
2517 #ifndef DISABLE_REMOTING
2519 * create_remote_class_key:
2520 * Creates an array of pointers that can be used as a hash key for a remote class.
2521 * The first element of the array is the number of pointers.
2524 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2526 MONO_REQ_GC_NEUTRAL_MODE;
2531 if (remote_class == NULL) {
2532 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2533 key = (void **)g_malloc (sizeof(gpointer) * 3);
2534 key [0] = GINT_TO_POINTER (2);
2535 key [1] = mono_defaults.marshalbyrefobject_class;
2536 key [2] = extra_class;
2538 key = (void **)g_malloc (sizeof(gpointer) * 2);
2539 key [0] = GINT_TO_POINTER (1);
2540 key [1] = extra_class;
2543 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2544 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2545 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2546 key [1] = remote_class->proxy_class;
2548 // Keep the list of interfaces sorted
2549 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2550 if (extra_class && remote_class->interfaces [i] > extra_class) {
2551 key [j++] = extra_class;
2554 key [j] = remote_class->interfaces [i];
2557 key [j] = extra_class;
2559 // Replace the old class. The interface list is the same
2560 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2561 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2562 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2563 for (i = 0; i < remote_class->interface_count; i++)
2564 key [2 + i] = remote_class->interfaces [i];
2572 * copy_remote_class_key:
2574 * Make a copy of KEY in the domain and return the copy.
2577 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2579 MONO_REQ_GC_NEUTRAL_MODE
2581 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2582 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2584 memcpy (mp_key, key, key_size);
2590 * mono_remote_class:
2591 * @domain: the application domain
2592 * @class_name: name of the remote class
2593 * @error: set on error
2595 * Creates and initializes a MonoRemoteClass object for a remote type.
2597 * On failure returns NULL and sets @error
2600 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2602 MONO_REQ_GC_UNSAFE_MODE;
2604 MonoRemoteClass *rc;
2605 gpointer* key, *mp_key;
2608 mono_error_init (error);
2610 key = create_remote_class_key (NULL, proxy_class);
2612 mono_domain_lock (domain);
2613 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2617 mono_domain_unlock (domain);
2621 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2622 if (!is_ok (error)) {
2624 mono_domain_unlock (domain);
2628 mp_key = copy_remote_class_key (domain, key);
2632 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2633 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2634 rc->interface_count = 1;
2635 rc->interfaces [0] = proxy_class;
2636 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2638 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2639 rc->interface_count = 0;
2640 rc->proxy_class = proxy_class;
2643 rc->default_vtable = NULL;
2644 rc->xdomain_vtable = NULL;
2645 rc->proxy_class_name = name;
2646 #ifndef DISABLE_PERFCOUNTERS
2647 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2650 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2652 mono_domain_unlock (domain);
2657 * clone_remote_class:
2658 * Creates a copy of the remote_class, adding the provided class or interface
2660 static MonoRemoteClass*
2661 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2663 MONO_REQ_GC_NEUTRAL_MODE;
2665 MonoRemoteClass *rc;
2666 gpointer* key, *mp_key;
2668 key = create_remote_class_key (remote_class, extra_class);
2669 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2675 mp_key = copy_remote_class_key (domain, key);
2679 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2681 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2682 rc->proxy_class = remote_class->proxy_class;
2683 rc->interface_count = remote_class->interface_count + 1;
2685 // Keep the list of interfaces sorted, since the hash key of
2686 // the remote class depends on this
2687 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2688 if (remote_class->interfaces [i] > extra_class && i == j)
2689 rc->interfaces [j++] = extra_class;
2690 rc->interfaces [j] = remote_class->interfaces [i];
2693 rc->interfaces [j] = extra_class;
2695 // Replace the old class. The interface array is the same
2696 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2697 rc->proxy_class = extra_class;
2698 rc->interface_count = remote_class->interface_count;
2699 if (rc->interface_count > 0)
2700 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2703 rc->default_vtable = NULL;
2704 rc->xdomain_vtable = NULL;
2705 rc->proxy_class_name = remote_class->proxy_class_name;
2707 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2713 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2715 MONO_REQ_GC_UNSAFE_MODE;
2717 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2718 mono_domain_lock (domain);
2719 if (rp->target_domain_id != -1) {
2720 if (remote_class->xdomain_vtable == NULL)
2721 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2722 mono_domain_unlock (domain);
2723 mono_loader_unlock ();
2724 return remote_class->xdomain_vtable;
2726 if (remote_class->default_vtable == NULL) {
2729 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2730 klass = mono_class_from_mono_type (type);
2732 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)))
2733 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2736 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2739 mono_domain_unlock (domain);
2740 mono_loader_unlock ();
2741 return remote_class->default_vtable;
2745 * mono_upgrade_remote_class:
2746 * @domain: the application domain
2747 * @tproxy: the proxy whose remote class has to be upgraded.
2748 * @klass: class to which the remote class can be casted.
2750 * Updates the vtable of the remote class by adding the necessary method slots
2751 * and interface offsets so it can be safely casted to klass. klass can be a
2752 * class or an interface.
2755 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2757 MONO_REQ_GC_UNSAFE_MODE;
2759 MonoTransparentProxy *tproxy;
2760 MonoRemoteClass *remote_class;
2761 gboolean redo_vtable;
2763 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2764 mono_domain_lock (domain);
2766 tproxy = (MonoTransparentProxy*) proxy_object;
2767 remote_class = tproxy->remote_class;
2769 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2772 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2773 if (remote_class->interfaces [i] == klass)
2774 redo_vtable = FALSE;
2777 redo_vtable = (remote_class->proxy_class != klass);
2781 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2782 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2785 mono_domain_unlock (domain);
2786 mono_loader_unlock ();
2788 #endif /* DISABLE_REMOTING */
2792 * mono_object_get_virtual_method:
2793 * @obj: object to operate on.
2796 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2797 * the instance of a callvirt of method.
2800 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2802 MONO_REQ_GC_UNSAFE_MODE;
2805 MonoMethod **vtable;
2806 gboolean is_proxy = FALSE;
2807 MonoMethod *res = NULL;
2809 klass = mono_object_class (obj);
2810 #ifndef DISABLE_REMOTING
2811 if (klass == mono_defaults.transparent_proxy_class) {
2812 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2817 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2820 mono_class_setup_vtable (klass);
2821 vtable = klass->vtable;
2823 if (method->slot == -1) {
2824 /* method->slot might not be set for instances of generic methods */
2825 if (method->is_inflated) {
2826 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2827 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2830 g_assert_not_reached ();
2834 /* check method->slot is a valid index: perform isinstance? */
2835 if (method->slot != -1) {
2836 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2838 gboolean variance_used = FALSE;
2839 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2840 g_assert (iface_offset > 0);
2841 res = vtable [iface_offset + method->slot];
2844 res = vtable [method->slot];
2848 #ifndef DISABLE_REMOTING
2850 /* It may be an interface, abstract class method or generic method */
2851 if (!res || mono_method_signature (res)->generic_param_count)
2854 /* generic methods demand invoke_with_check */
2855 if (mono_method_signature (res)->generic_param_count)
2856 res = mono_marshal_get_remoting_invoke_with_check (res);
2859 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2860 res = mono_cominterop_get_invoke (res);
2863 res = mono_marshal_get_remoting_invoke (res);
2868 if (method->is_inflated) {
2870 /* Have to inflate the result */
2871 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2872 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2882 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2884 MONO_REQ_GC_UNSAFE_MODE;
2886 MonoObject *result = NULL;
2888 g_assert (callbacks.runtime_invoke);
2890 mono_error_init (error);
2892 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2893 mono_profiler_method_start_invoke (method);
2895 MONO_ENTER_GC_UNSAFE;
2897 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2899 MONO_EXIT_GC_UNSAFE;
2901 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2902 mono_profiler_method_end_invoke (method);
2904 if (!mono_error_ok (error))
2911 * mono_runtime_invoke:
2912 * @method: method to invoke
2913 * @obJ: object instance
2914 * @params: arguments to the method
2915 * @exc: exception information.
2917 * Invokes the method represented by @method on the object @obj.
2919 * obj is the 'this' pointer, it should be NULL for static
2920 * methods, a MonoObject* for object instances and a pointer to
2921 * the value type for value types.
2923 * The params array contains the arguments to the method with the
2924 * same convention: MonoObject* pointers for object instances and
2925 * pointers to the value type otherwise.
2927 * From unmanaged code you'll usually use the
2928 * mono_runtime_invoke() variant.
2930 * Note that this function doesn't handle virtual methods for
2931 * you, it will exec the exact method you pass: we still need to
2932 * expose a function to lookup the derived class implementation
2933 * of a virtual method (there are examples of this in the code,
2936 * You can pass NULL as the exc argument if you don't want to
2937 * catch exceptions, otherwise, *exc will be set to the exception
2938 * thrown, if any. if an exception is thrown, you can't use the
2939 * MonoObject* result from the function.
2941 * If the method returns a value type, it is boxed in an object
2945 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2950 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2951 if (*exc == NULL && !mono_error_ok(&error)) {
2952 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2954 mono_error_cleanup (&error);
2956 res = mono_runtime_invoke_checked (method, obj, params, &error);
2957 mono_error_raise_exception (&error);
2963 * mono_runtime_try_invoke:
2964 * @method: method to invoke
2965 * @obJ: object instance
2966 * @params: arguments to the method
2967 * @exc: exception information.
2968 * @error: set on error
2970 * Invokes the method represented by @method on the object @obj.
2972 * obj is the 'this' pointer, it should be NULL for static
2973 * methods, a MonoObject* for object instances and a pointer to
2974 * the value type for value types.
2976 * The params array contains the arguments to the method with the
2977 * same convention: MonoObject* pointers for object instances and
2978 * pointers to the value type otherwise.
2980 * From unmanaged code you'll usually use the
2981 * mono_runtime_invoke() variant.
2983 * Note that this function doesn't handle virtual methods for
2984 * you, it will exec the exact method you pass: we still need to
2985 * expose a function to lookup the derived class implementation
2986 * of a virtual method (there are examples of this in the code,
2989 * For this function, you must not pass NULL as the exc argument if
2990 * you don't want to catch exceptions, use
2991 * mono_runtime_invoke_checked(). If an exception is thrown, you
2992 * can't use the MonoObject* result from the function.
2994 * If this method cannot be invoked, @error will be set and @exc and
2995 * the return value must not be used.
2997 * If the method returns a value type, it is boxed in an object
3001 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3003 MONO_REQ_GC_UNSAFE_MODE;
3005 g_assert (exc != NULL);
3007 if (mono_runtime_get_no_exec ())
3008 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3010 return do_runtime_invoke (method, obj, params, exc, error);
3014 * mono_runtime_invoke_checked:
3015 * @method: method to invoke
3016 * @obJ: object instance
3017 * @params: arguments to the method
3018 * @error: set on error
3020 * Invokes the method represented by @method on the object @obj.
3022 * obj is the 'this' pointer, it should be NULL for static
3023 * methods, a MonoObject* for object instances and a pointer to
3024 * the value type for value types.
3026 * The params array contains the arguments to the method with the
3027 * same convention: MonoObject* pointers for object instances and
3028 * pointers to the value type otherwise.
3030 * From unmanaged code you'll usually use the
3031 * mono_runtime_invoke() variant.
3033 * Note that this function doesn't handle virtual methods for
3034 * you, it will exec the exact method you pass: we still need to
3035 * expose a function to lookup the derived class implementation
3036 * of a virtual method (there are examples of this in the code,
3039 * If an exception is thrown, you can't use the MonoObject* result
3040 * from the function.
3042 * If this method cannot be invoked, @error will be set. If the
3043 * method throws an exception (and we're in coop mode) the exception
3044 * will be set in @error.
3046 * If the method returns a value type, it is boxed in an object
3050 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3052 MONO_REQ_GC_UNSAFE_MODE;
3054 if (mono_runtime_get_no_exec ())
3055 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3057 return do_runtime_invoke (method, obj, params, NULL, error);
3061 * mono_method_get_unmanaged_thunk:
3062 * @method: method to generate a thunk for.
3064 * Returns an unmanaged->managed thunk that can be used to call
3065 * a managed method directly from C.
3067 * The thunk's C signature closely matches the managed signature:
3069 * C#: public bool Equals (object obj);
3070 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3071 * MonoObject*, MonoException**);
3073 * The 1st ("this") parameter must not be used with static methods:
3075 * C#: public static bool ReferenceEquals (object a, object b);
3076 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3079 * The last argument must be a non-null pointer of a MonoException* pointer.
3080 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3081 * exception has been thrown in managed code. Otherwise it will point
3082 * to the MonoException* caught by the thunk. In this case, the result of
3083 * the thunk is undefined:
3085 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3086 * MonoException *ex = NULL;
3087 * Equals func = mono_method_get_unmanaged_thunk (method);
3088 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3090 * // handle exception
3093 * The calling convention of the thunk matches the platform's default
3094 * convention. This means that under Windows, C declarations must
3095 * contain the __stdcall attribute:
3097 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3098 * MonoObject*, MonoException**);
3102 * Value type arguments and return values are treated as they were objects:
3104 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3105 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3107 * Arguments must be properly boxed upon trunk's invocation, while return
3108 * values must be unboxed.
3111 mono_method_get_unmanaged_thunk (MonoMethod *method)
3113 MONO_REQ_GC_NEUTRAL_MODE;
3114 MONO_REQ_API_ENTRYPOINT;
3118 g_assert (!mono_threads_is_coop_enabled ());
3120 MONO_ENTER_GC_UNSAFE;
3121 method = mono_marshal_get_thunk_invoke_wrapper (method);
3122 res = mono_compile_method (method);
3123 MONO_EXIT_GC_UNSAFE;
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, error);
3466 return_val_if_nok (error, NULL);
3467 } else if (is_static) {
3468 mono_field_static_get_value_checked (vtable, field, &o, error);
3469 return_val_if_nok (error, NULL);
3471 mono_field_get_value (obj, field, &o);
3477 static MonoMethod *m;
3483 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3484 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3490 get_default_field_value (domain, field, v, error);
3491 return_val_if_nok (error, NULL);
3492 } else if (is_static) {
3493 mono_field_static_get_value_checked (vtable, field, v, error);
3494 return_val_if_nok (error, NULL);
3496 mono_field_get_value (obj, field, v);
3499 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3500 args [0] = ptr ? *ptr : NULL;
3501 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3502 return_val_if_nok (error, NULL);
3504 o = mono_runtime_invoke_checked (m, NULL, args, error);
3505 return_val_if_nok (error, NULL);
3510 /* boxed value type */
3511 klass = mono_class_from_mono_type (type);
3513 if (mono_class_is_nullable (klass))
3514 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3516 o = mono_object_new_checked (domain, klass, error);
3517 return_val_if_nok (error, NULL);
3518 v = ((gchar *) o) + sizeof (MonoObject);
3521 get_default_field_value (domain, field, v, error);
3522 return_val_if_nok (error, NULL);
3523 } else if (is_static) {
3524 mono_field_static_get_value_checked (vtable, field, v, error);
3525 return_val_if_nok (error, NULL);
3527 mono_field_get_value (obj, field, v);
3534 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3536 MONO_REQ_GC_UNSAFE_MODE;
3538 mono_error_init (error);
3540 const char *p = blob;
3541 mono_metadata_decode_blob_size (p, &p);
3544 case MONO_TYPE_BOOLEAN:
3547 *(guint8 *) value = *p;
3549 case MONO_TYPE_CHAR:
3552 *(guint16*) value = read16 (p);
3556 *(guint32*) value = read32 (p);
3560 *(guint64*) value = read64 (p);
3563 readr4 (p, (float*) value);
3566 readr8 (p, (double*) value);
3568 case MONO_TYPE_STRING:
3569 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3571 case MONO_TYPE_CLASS:
3572 *(gpointer*) value = NULL;
3576 g_warning ("type 0x%02x should not be in constant table", type);
3582 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3584 MONO_REQ_GC_NEUTRAL_MODE;
3586 MonoTypeEnum def_type;
3589 mono_error_init (error);
3591 data = mono_class_get_field_default_value (field, &def_type);
3592 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3596 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3598 MONO_REQ_GC_UNSAFE_MODE;
3602 mono_error_init (error);
3604 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3606 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3607 get_default_field_value (vt->domain, field, value, error);
3611 if (field->offset == -1) {
3612 /* Special static */
3613 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3614 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3616 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3618 mono_copy_value (field->type, value, src, TRUE);
3622 * mono_field_static_get_value:
3623 * @vt: vtable to the object
3624 * @field: MonoClassField describing the field to fetch information from
3625 * @value: where the value is returned
3627 * Use this routine to get the value of the static field @field value.
3629 * The pointer provided by value must be of the field type, for reference
3630 * types this is a MonoObject*, for value types its the actual pointer to
3635 * mono_field_static_get_value (vt, int_field, &i);
3638 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3640 MONO_REQ_GC_NEUTRAL_MODE;
3643 mono_field_static_get_value_checked (vt, field, value, &error);
3644 mono_error_cleanup (&error);
3648 * mono_field_static_get_value_checked:
3649 * @vt: vtable to the object
3650 * @field: MonoClassField describing the field to fetch information from
3651 * @value: where the value is returned
3652 * @error: set on error
3654 * Use this routine to get the value of the static field @field value.
3656 * The pointer provided by value must be of the field type, for reference
3657 * types this is a MonoObject*, for value types its the actual pointer to
3662 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3663 * if (!is_ok (error)) { ... }
3665 * On failure sets @error.
3668 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3670 MONO_REQ_GC_NEUTRAL_MODE;
3672 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3676 * mono_property_set_value:
3677 * @prop: MonoProperty to set
3678 * @obj: instance object on which to act
3679 * @params: parameters to pass to the propery
3680 * @exc: optional exception
3682 * Invokes the property's set method with the given arguments on the
3683 * object instance obj (or NULL for static properties).
3685 * You can pass NULL as the exc argument if you don't want to
3686 * catch exceptions, otherwise, *exc will be set to the exception
3687 * thrown, if any. if an exception is thrown, you can't use the
3688 * MonoObject* result from the function.
3691 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3693 MONO_REQ_GC_UNSAFE_MODE;
3696 do_runtime_invoke (prop->set, obj, params, exc, &error);
3697 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3698 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3700 mono_error_cleanup (&error);
3705 * mono_property_set_value_checked:
3706 * @prop: MonoProperty to set
3707 * @obj: instance object on which to act
3708 * @params: parameters to pass to the propery
3709 * @error: set on error
3711 * Invokes the property's set method with the given arguments on the
3712 * object instance obj (or NULL for static properties).
3714 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3715 * If an exception is thrown, it will be caught and returned via @error.
3718 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3720 MONO_REQ_GC_UNSAFE_MODE;
3724 mono_error_init (error);
3725 do_runtime_invoke (prop->set, obj, params, &exc, error);
3726 if (exc != NULL && is_ok (error))
3727 mono_error_set_exception_instance (error, (MonoException*)exc);
3728 return is_ok (error);
3732 * mono_property_get_value:
3733 * @prop: MonoProperty to fetch
3734 * @obj: instance object on which to act
3735 * @params: parameters to pass to the propery
3736 * @exc: optional exception
3738 * Invokes the property's get method with the given arguments on the
3739 * object instance obj (or NULL for static properties).
3741 * You can pass NULL as the exc argument if you don't want to
3742 * catch exceptions, otherwise, *exc will be set to the exception
3743 * thrown, if any. if an exception is thrown, you can't use the
3744 * MonoObject* result from the function.
3746 * Returns: the value from invoking the get method on the property.
3749 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3751 MONO_REQ_GC_UNSAFE_MODE;
3754 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3755 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3756 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3758 mono_error_cleanup (&error); /* FIXME don't raise here */
3765 * mono_property_get_value_checked:
3766 * @prop: MonoProperty to fetch
3767 * @obj: instance object on which to act
3768 * @params: parameters to pass to the propery
3769 * @error: set on error
3771 * Invokes the property's get method with the given arguments on the
3772 * object instance obj (or NULL for static properties).
3774 * If an exception is thrown, you can't use the
3775 * MonoObject* result from the function. The exception will be propagated via @error.
3777 * Returns: the value from invoking the get method on the property. On
3778 * failure returns NULL and sets @error.
3781 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3783 MONO_REQ_GC_UNSAFE_MODE;
3786 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3787 if (exc != NULL && !is_ok (error))
3788 mono_error_set_exception_instance (error, (MonoException*) exc);
3796 * mono_nullable_init:
3797 * @buf: The nullable structure to initialize.
3798 * @value: the value to initialize from
3799 * @klass: the type for the object
3801 * Initialize the nullable structure pointed to by @buf from @value which
3802 * should be a boxed value type. The size of @buf should be able to hold
3803 * as much data as the @klass->instance_size (which is the number of bytes
3804 * that will be copies).
3806 * Since Nullables have variable structure, we can not define a C
3807 * structure for them.
3810 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3812 MONO_REQ_GC_UNSAFE_MODE;
3814 MonoClass *param_class = klass->cast_class;
3816 mono_class_setup_fields_locking (klass);
3817 g_assert (klass->fields_inited);
3819 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3820 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3822 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3824 if (param_class->has_references)
3825 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3827 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3829 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3834 * mono_nullable_box:
3835 * @buf: The buffer representing the data to be boxed
3836 * @klass: the type to box it as.
3837 * @error: set on oerr
3839 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3840 * @buf. On failure returns NULL and sets @error
3843 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3845 MONO_REQ_GC_UNSAFE_MODE;
3847 mono_error_init (error);
3848 MonoClass *param_class = klass->cast_class;
3850 mono_class_setup_fields_locking (klass);
3851 g_assert (klass->fields_inited);
3853 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3854 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3856 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3857 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3858 return_val_if_nok (error, NULL);
3859 if (param_class->has_references)
3860 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3862 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3870 * mono_get_delegate_invoke:
3871 * @klass: The delegate class
3873 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3876 mono_get_delegate_invoke (MonoClass *klass)
3878 MONO_REQ_GC_NEUTRAL_MODE;
3882 /* This is called at runtime, so avoid the slower search in metadata */
3883 mono_class_setup_methods (klass);
3884 if (mono_class_has_failure (klass))
3886 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3891 * mono_get_delegate_begin_invoke:
3892 * @klass: The delegate class
3894 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3897 mono_get_delegate_begin_invoke (MonoClass *klass)
3899 MONO_REQ_GC_NEUTRAL_MODE;
3903 /* This is called at runtime, so avoid the slower search in metadata */
3904 mono_class_setup_methods (klass);
3905 if (mono_class_has_failure (klass))
3907 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3912 * mono_get_delegate_end_invoke:
3913 * @klass: The delegate class
3915 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3918 mono_get_delegate_end_invoke (MonoClass *klass)
3920 MONO_REQ_GC_NEUTRAL_MODE;
3924 /* This is called at runtime, so avoid the slower search in metadata */
3925 mono_class_setup_methods (klass);
3926 if (mono_class_has_failure (klass))
3928 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3933 * mono_runtime_delegate_invoke:
3934 * @delegate: pointer to a delegate object.
3935 * @params: parameters for the delegate.
3936 * @exc: Pointer to the exception result.
3938 * Invokes the delegate method @delegate with the parameters provided.
3940 * You can pass NULL as the exc argument if you don't want to
3941 * catch exceptions, otherwise, *exc will be set to the exception
3942 * thrown, if any. if an exception is thrown, you can't use the
3943 * MonoObject* result from the function.
3946 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3948 MONO_REQ_GC_UNSAFE_MODE;
3952 MonoClass *klass = delegate->vtable->klass;
3955 im = mono_get_delegate_invoke (klass);
3957 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3960 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3961 if (*exc == NULL && !mono_error_ok (&error))
3962 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3964 mono_error_cleanup (&error);
3966 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3967 mono_error_raise_exception (&error); /* FIXME don't raise here */
3973 static char **main_args = NULL;
3974 static int num_main_args = 0;
3977 * mono_runtime_get_main_args:
3979 * Returns: a MonoArray with the arguments passed to the main program
3982 mono_runtime_get_main_args (void)
3984 MONO_REQ_GC_UNSAFE_MODE;
3986 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3987 mono_error_assert_ok (&error);
3992 * mono_runtime_get_main_args:
3993 * @error: set on error
3995 * Returns: a MonoArray with the arguments passed to the main
3996 * program. On failure returns NULL and sets @error.
3999 mono_runtime_get_main_args_checked (MonoError *error)
4003 MonoDomain *domain = mono_domain_get ();
4005 mono_error_init (error);
4007 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4008 return_val_if_nok (error, NULL);
4010 for (i = 0; i < num_main_args; ++i)
4011 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4017 free_main_args (void)
4019 MONO_REQ_GC_NEUTRAL_MODE;
4023 for (i = 0; i < num_main_args; ++i)
4024 g_free (main_args [i]);
4031 * mono_runtime_set_main_args:
4032 * @argc: number of arguments from the command line
4033 * @argv: array of strings from the command line
4035 * Set the command line arguments from an embedding application that doesn't otherwise call
4036 * mono_runtime_run_main ().
4039 mono_runtime_set_main_args (int argc, char* argv[])
4041 MONO_REQ_GC_NEUTRAL_MODE;
4046 main_args = g_new0 (char*, argc);
4047 num_main_args = argc;
4049 for (i = 0; i < argc; ++i) {
4052 utf8_arg = mono_utf8_from_external (argv[i]);
4053 if (utf8_arg == NULL) {
4054 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4055 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4059 main_args [i] = utf8_arg;
4066 * mono_runtime_run_main:
4067 * @method: the method to start the application with (usually Main)
4068 * @argc: number of arguments from the command line
4069 * @argv: array of strings from the command line
4070 * @exc: excetption results
4072 * Execute a standard Main() method (argc/argv contains the
4073 * executable name). This method also sets the command line argument value
4074 * needed by System.Environment.
4079 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4082 MONO_REQ_GC_UNSAFE_MODE;
4086 MonoArray *args = NULL;
4087 MonoDomain *domain = mono_domain_get ();
4088 gchar *utf8_fullpath;
4089 MonoMethodSignature *sig;
4091 g_assert (method != NULL);
4093 mono_thread_set_main (mono_thread_current ());
4095 main_args = g_new0 (char*, argc);
4096 num_main_args = argc;
4098 if (!g_path_is_absolute (argv [0])) {
4099 gchar *basename = g_path_get_basename (argv [0]);
4100 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4104 utf8_fullpath = mono_utf8_from_external (fullpath);
4105 if(utf8_fullpath == NULL) {
4106 /* Printing the arg text will cause glib to
4107 * whinge about "Invalid UTF-8", but at least
4108 * its relevant, and shows the problem text
4111 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4112 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4119 utf8_fullpath = mono_utf8_from_external (argv[0]);
4120 if(utf8_fullpath == NULL) {
4121 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4122 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4127 main_args [0] = utf8_fullpath;
4129 for (i = 1; i < argc; ++i) {
4132 utf8_arg=mono_utf8_from_external (argv[i]);
4133 if(utf8_arg==NULL) {
4134 /* Ditto the comment about Invalid UTF-8 here */
4135 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4136 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4140 main_args [i] = utf8_arg;
4145 sig = mono_method_signature (method);
4147 g_print ("Unable to load Main method.\n");
4151 if (sig->param_count) {
4152 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4153 mono_error_assert_ok (&error);
4154 for (i = 0; i < argc; ++i) {
4155 /* The encodings should all work, given that
4156 * we've checked all these args for the
4159 gchar *str = mono_utf8_from_external (argv [i]);
4160 MonoString *arg = mono_string_new (domain, str);
4161 mono_array_setref (args, i, arg);
4165 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4166 mono_error_assert_ok (&error);
4169 mono_assembly_set_main (method->klass->image->assembly);
4171 return mono_runtime_exec_main (method, args, exc);
4175 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4177 static MonoMethod *serialize_method;
4183 if (!serialize_method) {
4184 MonoClass *klass = mono_class_get_remoting_services_class ();
4185 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4188 if (!serialize_method) {
4193 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4198 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4199 if (*exc == NULL && !mono_error_ok (&error))
4200 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4202 mono_error_cleanup (&error);
4211 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4213 MONO_REQ_GC_UNSAFE_MODE;
4215 static MonoMethod *deserialize_method;
4221 if (!deserialize_method) {
4222 MonoClass *klass = mono_class_get_remoting_services_class ();
4223 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4225 if (!deserialize_method) {
4233 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4234 if (*exc == NULL && !mono_error_ok (&error))
4235 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4237 mono_error_cleanup (&error);
4245 #ifndef DISABLE_REMOTING
4247 make_transparent_proxy (MonoObject *obj, MonoError *error)
4249 MONO_REQ_GC_UNSAFE_MODE;
4251 static MonoMethod *get_proxy_method;
4253 MonoDomain *domain = mono_domain_get ();
4254 MonoRealProxy *real_proxy;
4255 MonoReflectionType *reflection_type;
4256 MonoTransparentProxy *transparent_proxy;
4258 mono_error_init (error);
4260 if (!get_proxy_method)
4261 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4263 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4265 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4266 return_val_if_nok (error, NULL);
4267 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4268 return_val_if_nok (error, NULL);
4270 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4271 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4273 MonoObject *exc = NULL;
4275 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4276 if (exc != NULL && is_ok (error))
4277 mono_error_set_exception_instance (error, (MonoException*)exc);
4279 return (MonoObject*) transparent_proxy;
4281 #endif /* DISABLE_REMOTING */
4284 * mono_object_xdomain_representation
4286 * @target_domain: a domain
4287 * @error: set on error.
4289 * Creates a representation of obj in the domain target_domain. This
4290 * is either a copy of obj arrived through via serialization and
4291 * deserialization or a proxy, depending on whether the object is
4292 * serializable or marshal by ref. obj must not be in target_domain.
4294 * If the object cannot be represented in target_domain, NULL is
4295 * returned and @error is set appropriately.
4298 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4300 MONO_REQ_GC_UNSAFE_MODE;
4302 mono_error_init (error);
4303 MonoObject *deserialized = NULL;
4305 #ifndef DISABLE_REMOTING
4306 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4307 deserialized = make_transparent_proxy (obj, error);
4312 gboolean failure = FALSE;
4313 MonoDomain *domain = mono_domain_get ();
4314 MonoObject *serialized;
4315 MonoObject *exc = NULL;
4317 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4318 serialized = serialize_object (obj, &failure, &exc);
4319 mono_domain_set_internal_with_options (target_domain, FALSE);
4321 deserialized = deserialize_object (serialized, &failure, &exc);
4322 if (domain != target_domain)
4323 mono_domain_set_internal_with_options (domain, FALSE);
4325 mono_error_set_exception_instance (error, (MonoException*)exc);
4328 return deserialized;
4331 /* Used in call_unhandled_exception_delegate */
4333 create_unhandled_exception_eventargs (MonoObject *exc)
4335 MONO_REQ_GC_UNSAFE_MODE;
4340 MonoMethod *method = NULL;
4341 MonoBoolean is_terminating = TRUE;
4344 klass = mono_class_get_unhandled_exception_event_args_class ();
4345 mono_class_init (klass);
4347 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4348 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4352 args [1] = &is_terminating;
4354 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4355 mono_error_raise_exception (&error); /* FIXME don't raise here */
4357 mono_runtime_invoke_checked (method, obj, args, &error);
4358 mono_error_raise_exception (&error); /* FIXME don't raise here */
4363 /* Used in mono_unhandled_exception */
4365 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4366 MONO_REQ_GC_UNSAFE_MODE;
4368 MonoObject *e = NULL;
4370 MonoDomain *current_domain = mono_domain_get ();
4372 if (domain != current_domain)
4373 mono_domain_set_internal_with_options (domain, FALSE);
4375 g_assert (domain == mono_object_domain (domain->domain));
4377 if (mono_object_domain (exc) != domain) {
4380 exc = mono_object_xdomain_representation (exc, domain, &error);
4382 if (!is_ok (&error)) {
4383 MonoError inner_error;
4384 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4385 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4386 mono_error_assert_ok (&inner_error);
4388 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4389 "System.Runtime.Serialization", "SerializationException",
4390 "Could not serialize unhandled exception.");
4394 g_assert (mono_object_domain (exc) == domain);
4396 pa [0] = domain->domain;
4397 pa [1] = create_unhandled_exception_eventargs (exc);
4398 mono_runtime_delegate_invoke (delegate, pa, &e);
4400 if (domain != current_domain)
4401 mono_domain_set_internal_with_options (current_domain, FALSE);
4405 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4406 if (!mono_error_ok (&error)) {
4407 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4408 mono_error_cleanup (&error);
4410 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4416 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4419 * mono_runtime_unhandled_exception_policy_set:
4420 * @policy: the new policy
4422 * This is a VM internal routine.
4424 * Sets the runtime policy for handling unhandled exceptions.
4427 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4428 runtime_unhandled_exception_policy = policy;
4432 * mono_runtime_unhandled_exception_policy_get:
4434 * This is a VM internal routine.
4436 * Gets the runtime policy for handling unhandled exceptions.
4438 MonoRuntimeUnhandledExceptionPolicy
4439 mono_runtime_unhandled_exception_policy_get (void) {
4440 return runtime_unhandled_exception_policy;
4444 * mono_unhandled_exception:
4445 * @exc: exception thrown
4447 * This is a VM internal routine.
4449 * We call this function when we detect an unhandled exception
4450 * in the default domain.
4452 * It invokes the * UnhandledException event in AppDomain or prints
4453 * a warning to the console
4456 mono_unhandled_exception (MonoObject *exc)
4458 MONO_REQ_GC_UNSAFE_MODE;
4461 MonoClassField *field;
4462 MonoDomain *current_domain, *root_domain;
4463 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4465 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4468 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4471 current_domain = mono_domain_get ();
4472 root_domain = mono_get_root_domain ();
4474 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4475 mono_error_raise_exception (&error); /* FIXME don't raise here */
4476 if (current_domain != root_domain) {
4477 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4478 mono_error_raise_exception (&error); /* FIXME don't raise here */
4481 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4482 mono_print_unhandled_exception (exc);
4484 if (root_appdomain_delegate)
4485 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4486 if (current_appdomain_delegate)
4487 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4490 /* set exitcode only if we will abort the process */
4491 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4492 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4494 mono_environment_exitcode_set (1);
4499 * mono_runtime_exec_managed_code:
4500 * @domain: Application domain
4501 * @main_func: function to invoke from the execution thread
4502 * @main_args: parameter to the main_func
4504 * Launch a new thread to execute a function
4506 * main_func is called back from the thread with main_args as the
4507 * parameter. The callback function is expected to start Main()
4508 * eventually. This function then waits for all managed threads to
4510 * It is not necesseray anymore to execute managed code in a subthread,
4511 * so this function should not be used anymore by default: just
4512 * execute the code and then call mono_thread_manage ().
4515 mono_runtime_exec_managed_code (MonoDomain *domain,
4516 MonoMainThreadFunc main_func,
4520 mono_thread_create_checked (domain, main_func, main_args, &error);
4521 mono_error_assert_ok (&error);
4523 mono_thread_manage ();
4527 * Execute a standard Main() method (args doesn't contain the
4531 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4533 MONO_REQ_GC_UNSAFE_MODE;
4539 MonoCustomAttrInfo* cinfo;
4540 gboolean has_stathread_attribute;
4541 MonoInternalThread* thread = mono_thread_internal_current ();
4547 domain = mono_object_domain (args);
4548 if (!domain->entry_assembly) {
4550 MonoAssembly *assembly;
4552 assembly = method->klass->image->assembly;
4553 domain->entry_assembly = assembly;
4554 /* Domains created from another domain already have application_base and configuration_file set */
4555 if (domain->setup->application_base == NULL) {
4556 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4559 if (domain->setup->configuration_file == NULL) {
4560 str = g_strconcat (assembly->image->name, ".config", NULL);
4561 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4563 mono_domain_set_options_from_config (domain);
4567 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4568 mono_error_cleanup (&error); /* FIXME warn here? */
4570 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4572 mono_custom_attrs_free (cinfo);
4574 has_stathread_attribute = FALSE;
4576 if (has_stathread_attribute) {
4577 thread->apartment_state = ThreadApartmentState_STA;
4579 thread->apartment_state = ThreadApartmentState_MTA;
4581 mono_thread_init_apartment_state ();
4583 /* FIXME: check signature of method */
4584 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4587 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4588 if (*exc == NULL && !mono_error_ok (&error))
4589 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4591 mono_error_cleanup (&error);
4593 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4594 mono_error_raise_exception (&error); /* FIXME don't raise here */
4598 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4602 mono_environment_exitcode_set (rval);
4605 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4606 if (*exc == NULL && !mono_error_ok (&error))
4607 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4609 mono_error_cleanup (&error);
4611 mono_runtime_invoke_checked (method, NULL, pa, &error);
4612 mono_error_raise_exception (&error); /* FIXME don't raise here */
4618 /* If the return type of Main is void, only
4619 * set the exitcode if an exception was thrown
4620 * (we don't want to blow away an
4621 * explicitly-set exit code)
4624 mono_environment_exitcode_set (rval);
4632 * mono_runtime_invoke_array:
4633 * @method: method to invoke
4634 * @obJ: object instance
4635 * @params: arguments to the method
4636 * @exc: exception information.
4638 * Invokes the method represented by @method on the object @obj.
4640 * obj is the 'this' pointer, it should be NULL for static
4641 * methods, a MonoObject* for object instances and a pointer to
4642 * the value type for value types.
4644 * The params array contains the arguments to the method with the
4645 * same convention: MonoObject* pointers for object instances and
4646 * pointers to the value type otherwise. The _invoke_array
4647 * variant takes a C# object[] as the params argument (MonoArray
4648 * *params): in this case the value types are boxed inside the
4649 * respective reference representation.
4651 * From unmanaged code you'll usually use the
4652 * mono_runtime_invoke_checked() variant.
4654 * Note that this function doesn't handle virtual methods for
4655 * you, it will exec the exact method you pass: we still need to
4656 * expose a function to lookup the derived class implementation
4657 * of a virtual method (there are examples of this in the code,
4660 * You can pass NULL as the exc argument if you don't want to
4661 * catch exceptions, otherwise, *exc will be set to the exception
4662 * thrown, if any. if an exception is thrown, you can't use the
4663 * MonoObject* result from the function.
4665 * If the method returns a value type, it is boxed in an object
4669 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4672 MONO_REQ_GC_UNSAFE_MODE;
4675 MonoMethodSignature *sig = mono_method_signature (method);
4676 gpointer *pa = NULL;
4679 gboolean has_byref_nullables = FALSE;
4681 if (NULL != params) {
4682 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4683 for (i = 0; i < mono_array_length (params); i++) {
4684 MonoType *t = sig->params [i];
4690 case MONO_TYPE_BOOLEAN:
4693 case MONO_TYPE_CHAR:
4702 case MONO_TYPE_VALUETYPE:
4703 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4704 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4705 pa [i] = mono_array_get (params, MonoObject*, i);
4707 has_byref_nullables = TRUE;
4709 /* MS seems to create the objects if a null is passed in */
4710 if (!mono_array_get (params, MonoObject*, i)) {
4711 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4712 mono_error_raise_exception (&error); /* FIXME don't raise here */
4713 mono_array_setref (params, i, o);
4718 * We can't pass the unboxed vtype byref to the callee, since
4719 * that would mean the callee would be able to modify boxed
4720 * primitive types. So we (and MS) make a copy of the boxed
4721 * object, pass that to the callee, and replace the original
4722 * boxed object in the arg array with the copy.
4724 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4725 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), &error);
4726 mono_error_raise_exception (&error); /* FIXME don't raise here */
4727 mono_array_setref (params, i, copy);
4730 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4733 case MONO_TYPE_STRING:
4734 case MONO_TYPE_OBJECT:
4735 case MONO_TYPE_CLASS:
4736 case MONO_TYPE_ARRAY:
4737 case MONO_TYPE_SZARRAY:
4739 pa [i] = mono_array_addr (params, MonoObject*, i);
4740 // FIXME: I need to check this code path
4742 pa [i] = mono_array_get (params, MonoObject*, i);
4744 case MONO_TYPE_GENERICINST:
4746 t = &t->data.generic_class->container_class->this_arg;
4748 t = &t->data.generic_class->container_class->byval_arg;
4750 case MONO_TYPE_PTR: {
4753 /* The argument should be an IntPtr */
4754 arg = mono_array_get (params, MonoObject*, i);
4758 g_assert (arg->vtable->klass == mono_defaults.int_class);
4759 pa [i] = ((MonoIntPtr*)arg)->m_value;
4764 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4769 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4772 if (mono_class_is_nullable (method->klass)) {
4773 /* Need to create a boxed vtype instead */
4779 MonoObject *result = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], &error);
4780 mono_error_raise_exception (&error); /* FIXME don't raise here */
4786 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4787 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4788 #ifndef DISABLE_REMOTING
4789 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4790 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4793 if (method->klass->valuetype)
4794 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4797 } else if (method->klass->valuetype) {
4798 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, &error);
4799 mono_error_raise_exception (&error); /* FIXME don't raise here */
4803 mono_runtime_try_invoke (method, o, pa, exc, &error);
4804 if (*exc == NULL && !mono_error_ok (&error))
4805 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4807 mono_error_cleanup (&error);
4809 mono_runtime_invoke_checked (method, o, pa, &error);
4810 mono_error_raise_exception (&error); /* FIXME don't raise here */
4813 return (MonoObject *)obj;
4815 if (mono_class_is_nullable (method->klass)) {
4816 MonoObject *nullable;
4818 /* Convert the unboxed vtype into a Nullable structure */
4819 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4820 mono_error_raise_exception (&error); /* FIXME don't raise here */
4822 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, &error);
4823 mono_error_raise_exception (&error); /* FIXME don't raise here */
4824 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
4825 obj = mono_object_unbox (nullable);
4828 /* obj must be already unboxed if needed */
4830 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4831 if (*exc == NULL && !mono_error_ok (&error))
4832 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4834 mono_error_cleanup (&error);
4836 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4837 mono_error_raise_exception (&error); /* FIXME don't raise here */
4840 if (sig->ret->type == MONO_TYPE_PTR) {
4841 MonoClass *pointer_class;
4842 static MonoMethod *box_method;
4844 MonoObject *box_exc;
4847 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4848 * convert it to a Pointer object.
4850 pointer_class = mono_class_get_pointer_class ();
4852 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4854 g_assert (res->vtable->klass == mono_defaults.int_class);
4855 box_args [0] = ((MonoIntPtr*)res)->m_value;
4856 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4857 mono_error_raise_exception (&error); /* FIXME don't raise here */
4859 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4860 g_assert (box_exc == NULL);
4861 mono_error_assert_ok (&error);
4864 if (has_byref_nullables) {
4866 * The runtime invoke wrapper already converted byref nullables back,
4867 * and stored them in pa, we just need to copy them back to the
4870 for (i = 0; i < mono_array_length (params); i++) {
4871 MonoType *t = sig->params [i];
4873 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4874 mono_array_setref (params, i, pa [i]);
4884 * @klass: the class of the object that we want to create
4886 * Returns: a newly created object whose definition is
4887 * looked up using @klass. This will not invoke any constructors,
4888 * so the consumer of this routine has to invoke any constructors on
4889 * its own to initialize the object.
4891 * It returns NULL on failure.
4894 mono_object_new (MonoDomain *domain, MonoClass *klass)
4896 MONO_REQ_GC_UNSAFE_MODE;
4900 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4902 mono_error_cleanup (&error);
4907 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4909 MONO_REQ_GC_UNSAFE_MODE;
4913 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4915 mono_error_set_pending_exception (&error);
4920 * mono_object_new_checked:
4921 * @klass: the class of the object that we want to create
4922 * @error: set on error
4924 * Returns: a newly created object whose definition is
4925 * looked up using @klass. This will not invoke any constructors,
4926 * so the consumer of this routine has to invoke any constructors on
4927 * its own to initialize the object.
4929 * It returns NULL on failure and sets @error.
4932 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4934 MONO_REQ_GC_UNSAFE_MODE;
4938 vtable = mono_class_vtable (domain, klass);
4939 g_assert (vtable); /* FIXME don't swallow the error */
4941 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4946 * mono_object_new_pinned:
4948 * Same as mono_object_new, but the returned object will be pinned.
4949 * For SGEN, these objects will only be freed at appdomain unload.
4952 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4954 MONO_REQ_GC_UNSAFE_MODE;
4958 mono_error_init (error);
4960 vtable = mono_class_vtable (domain, klass);
4961 g_assert (vtable); /* FIXME don't swallow the error */
4963 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4965 if (G_UNLIKELY (!o))
4966 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4967 else if (G_UNLIKELY (vtable->klass->has_finalize))
4968 mono_object_register_finalizer (o, error);
4974 * mono_object_new_specific:
4975 * @vtable: the vtable of the object that we want to create
4977 * Returns: A newly created object with class and domain specified
4981 mono_object_new_specific (MonoVTable *vtable)
4984 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4985 mono_error_cleanup (&error);
4991 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4993 MONO_REQ_GC_UNSAFE_MODE;
4997 mono_error_init (error);
4999 /* check for is_com_object for COM Interop */
5000 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5003 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5006 MonoClass *klass = mono_class_get_activation_services_class ();
5009 mono_class_init (klass);
5011 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5013 mono_error_set_not_supported (error, "Linked away.");
5016 vtable->domain->create_proxy_for_type_method = im;
5019 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5020 if (!mono_error_ok (error))
5023 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5024 if (!mono_error_ok (error))
5031 return mono_object_new_alloc_specific_checked (vtable, error);
5035 ves_icall_object_new_specific (MonoVTable *vtable)
5038 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5039 mono_error_set_pending_exception (&error);
5045 * mono_object_new_alloc_specific:
5046 * @vtable: virtual table for the object.
5048 * This function allocates a new `MonoObject` with the type derived
5049 * from the @vtable information. If the class of this object has a
5050 * finalizer, then the object will be tracked for finalization.
5052 * This method might raise an exception on errors. Use the
5053 * `mono_object_new_fast_checked` method if you want to manually raise
5056 * Returns: the allocated object.
5059 mono_object_new_alloc_specific (MonoVTable *vtable)
5062 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5063 mono_error_cleanup (&error);
5069 * mono_object_new_alloc_specific_checked:
5070 * @vtable: virtual table for the object.
5071 * @error: holds the error return value.
5073 * This function allocates a new `MonoObject` with the type derived
5074 * from the @vtable information. If the class of this object has a
5075 * finalizer, then the object will be tracked for finalization.
5077 * If there is not enough memory, the @error parameter will be set
5078 * and will contain a user-visible message with the amount of bytes
5079 * that were requested.
5081 * Returns: the allocated object, or NULL if there is not enough memory
5085 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5087 MONO_REQ_GC_UNSAFE_MODE;
5091 mono_error_init (error);
5093 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5095 if (G_UNLIKELY (!o))
5096 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5097 else if (G_UNLIKELY (vtable->klass->has_finalize))
5098 mono_object_register_finalizer (o, error);
5104 * mono_object_new_fast:
5105 * @vtable: virtual table for the object.
5107 * This function allocates a new `MonoObject` with the type derived
5108 * from the @vtable information. The returned object is not tracked
5109 * for finalization. If your object implements a finalizer, you should
5110 * use `mono_object_new_alloc_specific` instead.
5112 * This method might raise an exception on errors. Use the
5113 * `mono_object_new_fast_checked` method if you want to manually raise
5116 * Returns: the allocated object.
5119 mono_object_new_fast (MonoVTable *vtable)
5122 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5123 mono_error_cleanup (&error);
5129 * mono_object_new_fast_checked:
5130 * @vtable: virtual table for the object.
5131 * @error: holds the error return value.
5133 * This function allocates a new `MonoObject` with the type derived
5134 * from the @vtable information. The returned object is not tracked
5135 * for finalization. If your object implements a finalizer, you should
5136 * use `mono_object_new_alloc_specific_checked` instead.
5138 * If there is not enough memory, the @error parameter will be set
5139 * and will contain a user-visible message with the amount of bytes
5140 * that were requested.
5142 * Returns: the allocated object, or NULL if there is not enough memory
5146 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5148 MONO_REQ_GC_UNSAFE_MODE;
5152 mono_error_init (error);
5154 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5156 if (G_UNLIKELY (!o))
5157 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5163 ves_icall_object_new_fast (MonoVTable *vtable)
5166 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5167 mono_error_set_pending_exception (&error);
5173 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5175 MONO_REQ_GC_UNSAFE_MODE;
5179 mono_error_init (error);
5181 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5183 if (G_UNLIKELY (!o))
5184 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5185 else if (G_UNLIKELY (vtable->klass->has_finalize))
5186 mono_object_register_finalizer (o, error);
5192 * mono_class_get_allocation_ftn:
5194 * @for_box: the object will be used for boxing
5195 * @pass_size_in_words:
5197 * Return the allocation function appropriate for the given class.
5201 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5203 MONO_REQ_GC_NEUTRAL_MODE;
5205 *pass_size_in_words = FALSE;
5207 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5208 return ves_icall_object_new_specific;
5210 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5212 return ves_icall_object_new_fast;
5215 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5216 * of the overhead of parameter passing.
5219 *pass_size_in_words = TRUE;
5220 #ifdef GC_REDIRECT_TO_LOCAL
5221 return GC_local_gcj_fast_malloc;
5223 return GC_gcj_fast_malloc;
5228 return ves_icall_object_new_specific;
5232 * mono_object_new_from_token:
5233 * @image: Context where the type_token is hosted
5234 * @token: a token of the type that we want to create
5236 * Returns: A newly created object whose definition is
5237 * looked up using @token in the @image image
5240 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5242 MONO_REQ_GC_UNSAFE_MODE;
5248 klass = mono_class_get_checked (image, token, &error);
5249 mono_error_assert_ok (&error);
5251 result = mono_object_new_checked (domain, klass, &error);
5253 mono_error_cleanup (&error);
5260 * mono_object_clone:
5261 * @obj: the object to clone
5263 * Returns: A newly created object who is a shallow copy of @obj
5266 mono_object_clone (MonoObject *obj)
5269 MonoObject *o = mono_object_clone_checked (obj, &error);
5270 mono_error_cleanup (&error);
5276 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5278 MONO_REQ_GC_UNSAFE_MODE;
5283 mono_error_init (error);
5285 size = obj->vtable->klass->instance_size;
5287 if (obj->vtable->klass->rank)
5288 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5290 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5292 if (G_UNLIKELY (!o)) {
5293 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5297 /* If the object doesn't contain references this will do a simple memmove. */
5298 mono_gc_wbarrier_object_copy (o, obj);
5300 if (obj->vtable->klass->has_finalize)
5301 mono_object_register_finalizer (o, error);
5306 * mono_array_full_copy:
5307 * @src: source array to copy
5308 * @dest: destination array
5310 * Copies the content of one array to another with exactly the same type and size.
5313 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5315 MONO_REQ_GC_UNSAFE_MODE;
5318 MonoClass *klass = src->obj.vtable->klass;
5320 g_assert (klass == dest->obj.vtable->klass);
5322 size = mono_array_length (src);
5323 g_assert (size == mono_array_length (dest));
5324 size *= mono_array_element_size (klass);
5326 if (klass->element_class->valuetype) {
5327 if (klass->element_class->has_references)
5328 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5330 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5332 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5335 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5340 * mono_array_clone_in_domain:
5341 * @domain: the domain in which the array will be cloned into
5342 * @array: the array to clone
5343 * @error: set on error
5345 * This routine returns a copy of the array that is hosted on the
5346 * specified MonoDomain. On failure returns NULL and sets @error.
5349 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5351 MONO_REQ_GC_UNSAFE_MODE;
5356 MonoClass *klass = array->obj.vtable->klass;
5358 mono_error_init (error);
5360 if (array->bounds == NULL) {
5361 size = mono_array_length (array);
5362 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5363 return_val_if_nok (error, NULL);
5365 size *= mono_array_element_size (klass);
5367 if (klass->element_class->valuetype) {
5368 if (klass->element_class->has_references)
5369 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5371 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5373 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5376 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5381 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5382 size = mono_array_element_size (klass);
5383 for (i = 0; i < klass->rank; ++i) {
5384 sizes [i] = array->bounds [i].length;
5385 size *= array->bounds [i].length;
5386 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5388 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5389 return_val_if_nok (error, NULL);
5391 if (klass->element_class->valuetype) {
5392 if (klass->element_class->has_references)
5393 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5395 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5397 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5400 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5408 * @array: the array to clone
5410 * Returns: A newly created array who is a shallow copy of @array
5413 mono_array_clone (MonoArray *array)
5415 MONO_REQ_GC_UNSAFE_MODE;
5418 MonoArray *result = mono_array_clone_checked (array, &error);
5419 mono_error_cleanup (&error);
5424 * mono_array_clone_checked:
5425 * @array: the array to clone
5426 * @error: set on error
5428 * Returns: A newly created array who is a shallow copy of @array. On
5429 * failure returns NULL and sets @error.
5432 mono_array_clone_checked (MonoArray *array, MonoError *error)
5435 MONO_REQ_GC_UNSAFE_MODE;
5436 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5439 /* helper macros to check for overflow when calculating the size of arrays */
5440 #ifdef MONO_BIG_ARRAYS
5441 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5442 #define MYGUINT_MAX MYGUINT64_MAX
5443 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5444 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5445 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5446 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5447 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5449 #define MYGUINT32_MAX 4294967295U
5450 #define MYGUINT_MAX MYGUINT32_MAX
5451 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5452 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5453 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5454 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5455 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5459 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5461 MONO_REQ_GC_NEUTRAL_MODE;
5465 byte_len = mono_array_element_size (klass);
5466 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5469 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5471 byte_len += MONO_SIZEOF_MONO_ARRAY;
5479 * mono_array_new_full:
5480 * @domain: domain where the object is created
5481 * @array_class: array class
5482 * @lengths: lengths for each dimension in the array
5483 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5485 * This routine creates a new array objects with the given dimensions,
5486 * lower bounds and type.
5489 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5492 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5493 mono_error_cleanup (&error);
5499 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5501 MONO_REQ_GC_UNSAFE_MODE;
5503 uintptr_t byte_len = 0, len, bounds_size;
5506 MonoArrayBounds *bounds;
5510 mono_error_init (error);
5512 if (!array_class->inited)
5513 mono_class_init (array_class);
5517 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5518 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5520 if (len > MONO_ARRAY_MAX_INDEX) {
5521 mono_error_set_generic_error (error, "System", "OverflowException", "");
5526 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5528 for (i = 0; i < array_class->rank; ++i) {
5529 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5530 mono_error_set_generic_error (error, "System", "OverflowException", "");
5533 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5534 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5541 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5542 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5548 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5549 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5552 byte_len = (byte_len + 3) & ~3;
5553 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5554 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5557 byte_len += bounds_size;
5560 * Following three lines almost taken from mono_object_new ():
5561 * they need to be kept in sync.
5563 vtable = mono_class_vtable_full (domain, array_class, error);
5564 return_val_if_nok (error, NULL);
5567 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5569 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5571 if (G_UNLIKELY (!o)) {
5572 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5576 array = (MonoArray*)o;
5578 bounds = array->bounds;
5581 for (i = 0; i < array_class->rank; ++i) {
5582 bounds [i].length = lengths [i];
5584 bounds [i].lower_bound = lower_bounds [i];
5593 * @domain: domain where the object is created
5594 * @eclass: element class
5595 * @n: number of array elements
5597 * This routine creates a new szarray with @n elements of type @eclass.
5600 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5602 MONO_REQ_GC_UNSAFE_MODE;
5605 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5606 mono_error_cleanup (&error);
5611 * mono_array_new_checked:
5612 * @domain: domain where the object is created
5613 * @eclass: element class
5614 * @n: number of array elements
5615 * @error: set on error
5617 * This routine creates a new szarray with @n elements of type @eclass.
5618 * On failure returns NULL and sets @error.
5621 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5625 mono_error_init (error);
5627 ac = mono_array_class_get (eclass, 1);
5630 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5631 return_val_if_nok (error, NULL);
5633 return mono_array_new_specific_checked (vtable, n, error);
5637 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5640 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5641 mono_error_set_pending_exception (&error);
5647 * mono_array_new_specific:
5648 * @vtable: a vtable in the appropriate domain for an initialized class
5649 * @n: number of array elements
5651 * This routine is a fast alternative to mono_array_new() for code which
5652 * can be sure about the domain it operates in.
5655 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5658 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5659 mono_error_cleanup (&error);
5665 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5667 MONO_REQ_GC_UNSAFE_MODE;
5672 mono_error_init (error);
5674 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5675 mono_error_set_generic_error (error, "System", "OverflowException", "");
5679 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5680 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5683 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5685 if (G_UNLIKELY (!o)) {
5686 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5690 return (MonoArray*)o;
5694 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5697 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5698 mono_error_set_pending_exception (&error);
5704 * mono_string_new_utf16:
5705 * @text: a pointer to an utf16 string
5706 * @len: the length of the string
5708 * Returns: A newly created string object which contains @text.
5711 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5713 MONO_REQ_GC_UNSAFE_MODE;
5716 MonoString *res = NULL;
5717 res = mono_string_new_utf16_checked (domain, text, len, &error);
5718 mono_error_cleanup (&error);
5724 * mono_string_new_utf16_checked:
5725 * @text: a pointer to an utf16 string
5726 * @len: the length of the string
5727 * @error: written on error.
5729 * Returns: A newly created string object which contains @text.
5730 * On error, returns NULL and sets @error.
5733 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5735 MONO_REQ_GC_UNSAFE_MODE;
5739 mono_error_init (error);
5741 s = mono_string_new_size_checked (domain, len, error);
5743 memcpy (mono_string_chars (s), text, len * 2);
5749 * mono_string_new_utf32:
5750 * @text: a pointer to an utf32 string
5751 * @len: the length of the string
5752 * @error: set on failure.
5754 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5757 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5759 MONO_REQ_GC_UNSAFE_MODE;
5762 mono_unichar2 *utf16_output = NULL;
5763 gint32 utf16_len = 0;
5764 GError *gerror = NULL;
5765 glong items_written;
5767 mono_error_init (error);
5768 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5771 g_error_free (gerror);
5773 while (utf16_output [utf16_len]) utf16_len++;
5775 s = mono_string_new_size_checked (domain, utf16_len, error);
5776 return_val_if_nok (error, NULL);
5778 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5780 g_free (utf16_output);
5786 * mono_string_new_utf32:
5787 * @text: a pointer to an utf32 string
5788 * @len: the length of the string
5790 * Returns: A newly created string object which contains @text.
5793 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5796 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
5797 mono_error_cleanup (&error);
5802 * mono_string_new_size:
5803 * @text: a pointer to an utf16 string
5804 * @len: the length of the string
5806 * Returns: A newly created string object of @len
5809 mono_string_new_size (MonoDomain *domain, gint32 len)
5812 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5813 mono_error_cleanup (&error);
5819 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5821 MONO_REQ_GC_UNSAFE_MODE;
5827 mono_error_init (error);
5829 /* check for overflow */
5830 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5831 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5835 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5836 g_assert (size > 0);
5838 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5841 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5843 if (G_UNLIKELY (!s)) {
5844 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5852 * mono_string_new_len:
5853 * @text: a pointer to an utf8 string
5854 * @length: number of bytes in @text to consider
5856 * Returns: A newly created string object which contains @text.
5859 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5861 MONO_REQ_GC_UNSAFE_MODE;
5864 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
5865 mono_error_cleanup (&error);
5870 * mono_string_new_len_checked:
5871 * @text: a pointer to an utf8 string
5872 * @length: number of bytes in @text to consider
5873 * @error: set on error
5875 * Returns: A newly created string object which contains @text. On
5876 * failure returns NULL and sets @error.
5879 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
5881 MONO_REQ_GC_UNSAFE_MODE;
5883 mono_error_init (error);
5885 GError *eg_error = NULL;
5886 MonoString *o = NULL;
5888 glong items_written;
5890 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5893 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5895 g_error_free (eg_error);
5904 * @text: a pointer to an utf8 string
5906 * Returns: A newly created string object which contains @text.
5908 * This function asserts if it cannot allocate a new string.
5910 * @deprecated Use mono_string_new_checked in new code.
5913 mono_string_new (MonoDomain *domain, const char *text)
5916 MonoString *res = NULL;
5917 res = mono_string_new_checked (domain, text, &error);
5918 mono_error_assert_ok (&error);
5923 * mono_string_new_checked:
5924 * @text: a pointer to an utf8 string
5925 * @merror: set on error
5927 * Returns: A newly created string object which contains @text.
5928 * On error returns NULL and sets @merror.
5931 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5933 MONO_REQ_GC_UNSAFE_MODE;
5935 GError *eg_error = NULL;
5936 MonoString *o = NULL;
5938 glong items_written;
5941 mono_error_init (error);
5945 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5948 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5950 g_error_free (eg_error);
5954 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5959 MonoString *o = NULL;
5961 if (!g_utf8_validate (text, -1, &end)) {
5962 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5966 len = g_utf8_strlen (text, -1);
5967 o = mono_string_new_size_checked (domain, len, error);
5970 str = mono_string_chars (o);
5972 while (text < end) {
5973 *str++ = g_utf8_get_char (text);
5974 text = g_utf8_next_char (text);
5983 * mono_string_new_wrapper:
5984 * @text: pointer to utf8 characters.
5986 * Helper function to create a string object from @text in the current domain.
5989 mono_string_new_wrapper (const char *text)
5991 MONO_REQ_GC_UNSAFE_MODE;
5993 MonoDomain *domain = mono_domain_get ();
5996 return mono_string_new (domain, text);
6003 * @class: the class of the value
6004 * @value: a pointer to the unboxed data
6006 * Returns: A newly created object which contains @value.
6009 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6012 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6013 mono_error_cleanup (&error);
6018 * mono_value_box_checked:
6019 * @domain: the domain of the new object
6020 * @class: the class of the value
6021 * @value: a pointer to the unboxed data
6022 * @error: set on error
6024 * Returns: A newly created object which contains @value. On failure
6025 * returns NULL and sets @error.
6028 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6030 MONO_REQ_GC_UNSAFE_MODE;
6035 mono_error_init (error);
6037 g_assert (klass->valuetype);
6038 if (mono_class_is_nullable (klass))
6039 return mono_nullable_box ((guint8 *)value, klass, error);
6041 vtable = mono_class_vtable (domain, klass);
6044 size = mono_class_instance_size (klass);
6045 res = mono_object_new_alloc_specific_checked (vtable, error);
6046 return_val_if_nok (error, NULL);
6048 size = size - sizeof (MonoObject);
6051 g_assert (size == mono_class_value_size (klass, NULL));
6052 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6054 #if NO_UNALIGNED_ACCESS
6055 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6059 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6062 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6065 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6068 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6071 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6075 if (klass->has_finalize) {
6076 mono_object_register_finalizer (res, error);
6077 return_val_if_nok (error, NULL);
6084 * @dest: destination pointer
6085 * @src: source pointer
6086 * @klass: a valuetype class
6088 * Copy a valuetype from @src to @dest. This function must be used
6089 * when @klass contains references fields.
6092 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6094 MONO_REQ_GC_UNSAFE_MODE;
6096 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6100 * mono_value_copy_array:
6101 * @dest: destination array
6102 * @dest_idx: index in the @dest array
6103 * @src: source pointer
6104 * @count: number of items
6106 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6107 * This function must be used when @klass contains references fields.
6108 * Overlap is handled.
6111 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6113 MONO_REQ_GC_UNSAFE_MODE;
6115 int size = mono_array_element_size (dest->obj.vtable->klass);
6116 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6117 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6118 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6122 * mono_object_get_domain:
6123 * @obj: object to query
6125 * Returns: the MonoDomain where the object is hosted
6128 mono_object_get_domain (MonoObject *obj)
6130 MONO_REQ_GC_UNSAFE_MODE;
6132 return mono_object_domain (obj);
6136 * mono_object_get_class:
6137 * @obj: object to query
6139 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6141 * Returns: the MonoClass of the object.
6144 mono_object_get_class (MonoObject *obj)
6146 MONO_REQ_GC_UNSAFE_MODE;
6148 return mono_object_class (obj);
6151 * mono_object_get_size:
6152 * @o: object to query
6154 * Returns: the size, in bytes, of @o
6157 mono_object_get_size (MonoObject* o)
6159 MONO_REQ_GC_UNSAFE_MODE;
6161 MonoClass* klass = mono_object_class (o);
6162 if (klass == mono_defaults.string_class) {
6163 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6164 } else if (o->vtable->rank) {
6165 MonoArray *array = (MonoArray*)o;
6166 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6167 if (array->bounds) {
6170 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6174 return mono_class_instance_size (klass);
6179 * mono_object_unbox:
6180 * @obj: object to unbox
6182 * Returns: a pointer to the start of the valuetype boxed in this
6185 * This method will assert if the object passed is not a valuetype.
6188 mono_object_unbox (MonoObject *obj)
6190 MONO_REQ_GC_UNSAFE_MODE;
6192 /* add assert for valuetypes? */
6193 g_assert (obj->vtable->klass->valuetype);
6194 return ((char*)obj) + sizeof (MonoObject);
6198 * mono_object_isinst:
6200 * @klass: a pointer to a class
6202 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6205 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6207 MONO_REQ_GC_UNSAFE_MODE;
6210 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6211 mono_error_cleanup (&error);
6217 * mono_object_isinst_checked:
6219 * @klass: a pointer to a class
6220 * @error: set on error
6222 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6223 * On failure returns NULL and sets @error.
6226 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6228 MONO_REQ_GC_UNSAFE_MODE;
6230 mono_error_init (error);
6232 MonoObject *result = NULL;
6235 mono_class_init (klass);
6237 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6238 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6245 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6249 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6251 MONO_REQ_GC_UNSAFE_MODE;
6254 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6255 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6260 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6262 MONO_REQ_GC_UNSAFE_MODE;
6266 mono_error_init (error);
6273 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6274 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6278 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6279 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6282 MonoClass *oklass = vt->klass;
6283 if (mono_class_is_transparent_proxy (oklass))
6284 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6286 mono_class_setup_supertypes (klass);
6287 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6290 #ifndef DISABLE_REMOTING
6291 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6293 MonoDomain *domain = mono_domain_get ();
6295 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6296 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6297 MonoMethod *im = NULL;
6300 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6302 mono_error_set_not_supported (error, "Linked away.");
6305 im = mono_object_get_virtual_method (rp, im);
6308 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6309 return_val_if_nok (error, NULL);
6312 res = mono_runtime_invoke_checked (im, rp, pa, error);
6313 return_val_if_nok (error, NULL);
6315 if (*(MonoBoolean *) mono_object_unbox(res)) {
6316 /* Update the vtable of the remote type, so it can safely cast to this new type */
6317 mono_upgrade_remote_class (domain, obj, klass);
6321 #endif /* DISABLE_REMOTING */
6326 * mono_object_castclass_mbyref:
6328 * @klass: a pointer to a class
6330 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6333 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6335 MONO_REQ_GC_UNSAFE_MODE;
6338 if (!obj) return NULL;
6339 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6340 mono_error_cleanup (&error);
6345 MonoDomain *orig_domain;
6351 str_lookup (MonoDomain *domain, gpointer user_data)
6353 MONO_REQ_GC_UNSAFE_MODE;
6355 LDStrInfo *info = (LDStrInfo *)user_data;
6356 if (info->res || domain == info->orig_domain)
6358 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6362 mono_string_get_pinned (MonoString *str, MonoError *error)
6364 MONO_REQ_GC_UNSAFE_MODE;
6366 mono_error_init (error);
6368 /* We only need to make a pinned version of a string if this is a moving GC */
6369 if (!mono_gc_is_moving ())
6373 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6374 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6376 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6377 news->length = mono_string_length (str);
6379 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6385 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6387 MONO_REQ_GC_UNSAFE_MODE;
6389 MonoGHashTable *ldstr_table;
6390 MonoString *s, *res;
6393 mono_error_init (error);
6395 domain = ((MonoObject *)str)->vtable->domain;
6396 ldstr_table = domain->ldstr_table;
6398 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6404 /* Allocate outside the lock */
6406 s = mono_string_get_pinned (str, error);
6407 return_val_if_nok (error, NULL);
6410 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6415 mono_g_hash_table_insert (ldstr_table, s, s);
6420 LDStrInfo ldstr_info;
6421 ldstr_info.orig_domain = domain;
6422 ldstr_info.ins = str;
6423 ldstr_info.res = NULL;
6425 mono_domain_foreach (str_lookup, &ldstr_info);
6426 if (ldstr_info.res) {
6428 * the string was already interned in some other domain:
6429 * intern it in the current one as well.
6431 mono_g_hash_table_insert (ldstr_table, str, str);
6441 * mono_string_is_interned:
6442 * @o: String to probe
6444 * Returns whether the string has been interned.
6447 mono_string_is_interned (MonoString *o)
6450 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6451 /* This function does not fail. */
6452 mono_error_assert_ok (&error);
6457 * mono_string_intern:
6458 * @o: String to intern
6460 * Interns the string passed.
6461 * Returns: The interned string.
6464 mono_string_intern (MonoString *str)
6467 MonoString *result = mono_string_intern_checked (str, &error);
6468 mono_error_assert_ok (&error);
6473 * mono_string_intern_checked:
6474 * @o: String to intern
6475 * @error: set on error.
6477 * Interns the string passed.
6478 * Returns: The interned string. On failure returns NULL and sets @error
6481 mono_string_intern_checked (MonoString *str, MonoError *error)
6483 MONO_REQ_GC_UNSAFE_MODE;
6485 mono_error_init (error);
6487 return mono_string_is_interned_lookup (str, TRUE, error);
6492 * @domain: the domain where the string will be used.
6493 * @image: a metadata context
6494 * @idx: index into the user string table.
6496 * Implementation for the ldstr opcode.
6497 * Returns: a loaded string from the @image/@idx combination.
6500 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6502 MONO_REQ_GC_UNSAFE_MODE;
6505 if (image->dynamic) {
6506 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, &error);
6507 mono_error_raise_exception (&error); /* FIXME don't raise here */
6510 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6511 return NULL; /*FIXME we should probably be raising an exception here*/
6512 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), &error);
6513 mono_error_raise_exception (&error); /* FIXME don't raise here */
6519 * mono_ldstr_metadata_sig
6520 * @domain: the domain for the string
6521 * @sig: the signature of a metadata string
6522 * @error: set on error
6524 * Returns: a MonoString for a string stored in the metadata. On
6525 * failure returns NULL and sets @error.
6528 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6530 MONO_REQ_GC_UNSAFE_MODE;
6532 mono_error_init (error);
6533 const char *str = sig;
6534 MonoString *o, *interned;
6537 len2 = mono_metadata_decode_blob_size (str, &str);
6540 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6541 return_val_if_nok (error, NULL);
6542 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6545 guint16 *p2 = (guint16*)mono_string_chars (o);
6546 for (i = 0; i < len2; ++i) {
6547 *p2 = GUINT16_FROM_LE (*p2);
6553 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6556 return interned; /* o will get garbage collected */
6558 o = mono_string_get_pinned (o, error);
6561 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6563 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6573 * mono_string_to_utf8:
6574 * @s: a System.String
6576 * Returns the UTF8 representation for @s.
6577 * The resulting buffer needs to be freed with mono_free().
6579 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6582 mono_string_to_utf8 (MonoString *s)
6584 MONO_REQ_GC_UNSAFE_MODE;
6587 char *result = mono_string_to_utf8_checked (s, &error);
6589 if (!mono_error_ok (&error))
6590 mono_error_raise_exception (&error);
6595 * mono_string_to_utf8_checked:
6596 * @s: a System.String
6597 * @error: a MonoError.
6599 * Converts a MonoString to its UTF8 representation. May fail; check
6600 * @error to determine whether the conversion was successful.
6601 * The resulting buffer should be freed with mono_free().
6604 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6606 MONO_REQ_GC_UNSAFE_MODE;
6610 GError *gerror = NULL;
6612 mono_error_init (error);
6618 return g_strdup ("");
6620 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6622 mono_error_set_argument (error, "string", "%s", gerror->message);
6623 g_error_free (gerror);
6626 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6627 if (s->length > written) {
6628 /* allocate the total length and copy the part of the string that has been converted */
6629 char *as2 = (char *)g_malloc0 (s->length);
6630 memcpy (as2, as, written);
6639 * mono_string_to_utf8_ignore:
6642 * Converts a MonoString to its UTF8 representation. Will ignore
6643 * invalid surrogate pairs.
6644 * The resulting buffer should be freed with mono_free().
6648 mono_string_to_utf8_ignore (MonoString *s)
6650 MONO_REQ_GC_UNSAFE_MODE;
6659 return g_strdup ("");
6661 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6663 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6664 if (s->length > written) {
6665 /* allocate the total length and copy the part of the string that has been converted */
6666 char *as2 = (char *)g_malloc0 (s->length);
6667 memcpy (as2, as, written);
6676 * mono_string_to_utf8_image_ignore:
6677 * @s: a System.String
6679 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6682 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6684 MONO_REQ_GC_UNSAFE_MODE;
6686 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6690 * mono_string_to_utf8_mp_ignore:
6691 * @s: a System.String
6693 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6696 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6698 MONO_REQ_GC_UNSAFE_MODE;
6700 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6705 * mono_string_to_utf16:
6708 * Return an null-terminated array of the utf-16 chars
6709 * contained in @s. The result must be freed with g_free().
6710 * This is a temporary helper until our string implementation
6711 * is reworked to always include the null terminating char.
6714 mono_string_to_utf16 (MonoString *s)
6716 MONO_REQ_GC_UNSAFE_MODE;
6723 as = (char *)g_malloc ((s->length * 2) + 2);
6724 as [(s->length * 2)] = '\0';
6725 as [(s->length * 2) + 1] = '\0';
6728 return (gunichar2 *)(as);
6731 memcpy (as, mono_string_chars(s), s->length * 2);
6732 return (gunichar2 *)(as);
6736 * mono_string_to_utf32:
6739 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6740 * contained in @s. The result must be freed with g_free().
6743 mono_string_to_utf32 (MonoString *s)
6745 MONO_REQ_GC_UNSAFE_MODE;
6747 mono_unichar4 *utf32_output = NULL;
6748 GError *error = NULL;
6749 glong items_written;
6754 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6757 g_error_free (error);
6759 return utf32_output;
6763 * mono_string_from_utf16:
6764 * @data: the UTF16 string (LPWSTR) to convert
6766 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6768 * Returns: a MonoString.
6771 mono_string_from_utf16 (gunichar2 *data)
6774 MonoString *result = mono_string_from_utf16_checked (data, &error);
6775 mono_error_cleanup (&error);
6780 * mono_string_from_utf16_checked:
6781 * @data: the UTF16 string (LPWSTR) to convert
6782 * @error: set on error
6784 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6786 * Returns: a MonoString. On failure sets @error and returns NULL.
6789 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
6792 MONO_REQ_GC_UNSAFE_MODE;
6794 mono_error_init (error);
6795 MonoDomain *domain = mono_domain_get ();
6801 while (data [len]) len++;
6803 return mono_string_new_utf16_checked (domain, data, len, error);
6807 * mono_string_from_utf32:
6808 * @data: the UTF32 string (LPWSTR) to convert
6810 * Converts a UTF32 (UCS-4)to a MonoString.
6812 * Returns: a MonoString.
6815 mono_string_from_utf32 (mono_unichar4 *data)
6818 MonoString *result = mono_string_from_utf32_checked (data, &error);
6819 mono_error_cleanup (&error);
6824 * mono_string_from_utf32_checked:
6825 * @data: the UTF32 string (LPWSTR) to convert
6826 * @error: set on error
6828 * Converts a UTF32 (UCS-4)to a MonoString.
6830 * Returns: a MonoString. On failure returns NULL and sets @error.
6833 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
6835 MONO_REQ_GC_UNSAFE_MODE;
6837 mono_error_init (error);
6838 MonoString* result = NULL;
6839 mono_unichar2 *utf16_output = NULL;
6840 GError *gerror = NULL;
6841 glong items_written;
6847 while (data [len]) len++;
6849 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
6852 g_error_free (gerror);
6854 result = mono_string_from_utf16_checked (utf16_output, error);
6855 g_free (utf16_output);
6860 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6862 MONO_REQ_GC_UNSAFE_MODE;
6869 r = mono_string_to_utf8_ignore (s);
6871 r = mono_string_to_utf8_checked (s, error);
6872 if (!mono_error_ok (error))
6879 len = strlen (r) + 1;
6881 mp_s = (char *)mono_mempool_alloc (mp, len);
6883 mp_s = (char *)mono_image_alloc (image, len);
6885 memcpy (mp_s, r, len);
6893 * mono_string_to_utf8_image:
6894 * @s: a System.String
6896 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6899 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6901 MONO_REQ_GC_UNSAFE_MODE;
6903 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6907 * mono_string_to_utf8_mp:
6908 * @s: a System.String
6910 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6913 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6915 MONO_REQ_GC_UNSAFE_MODE;
6917 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6921 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6924 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6926 eh_callbacks = *cbs;
6929 MonoRuntimeExceptionHandlingCallbacks *
6930 mono_get_eh_callbacks (void)
6932 return &eh_callbacks;
6936 * mono_raise_exception:
6937 * @ex: exception object
6939 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6942 mono_raise_exception (MonoException *ex)
6944 MONO_REQ_GC_UNSAFE_MODE;
6947 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6948 * that will cause gcc to omit the function epilog, causing problems when
6949 * the JIT tries to walk the stack, since the return address on the stack
6950 * will point into the next function in the executable, not this one.
6952 eh_callbacks.mono_raise_exception (ex);
6956 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6958 MONO_REQ_GC_UNSAFE_MODE;
6960 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6964 * mono_wait_handle_new:
6965 * @domain: Domain where the object will be created
6966 * @handle: Handle for the wait handle
6967 * @error: set on error.
6969 * Returns: A new MonoWaitHandle created in the given domain for the
6970 * given handle. On failure returns NULL and sets @rror.
6973 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
6975 MONO_REQ_GC_UNSAFE_MODE;
6977 MonoWaitHandle *res;
6978 gpointer params [1];
6979 static MonoMethod *handle_set;
6981 mono_error_init (error);
6982 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
6983 return_val_if_nok (error, NULL);
6985 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6987 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6989 params [0] = &handle;
6991 mono_runtime_invoke_checked (handle_set, res, params, error);
6996 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6998 MONO_REQ_GC_UNSAFE_MODE;
7000 static MonoClassField *f_safe_handle = NULL;
7003 if (!f_safe_handle) {
7004 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7005 g_assert (f_safe_handle);
7008 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7014 mono_runtime_capture_context (MonoDomain *domain)
7016 MONO_REQ_GC_UNSAFE_MODE;
7018 RuntimeInvokeFunction runtime_invoke;
7020 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7021 MonoMethod *method = mono_get_context_capture_method ();
7022 MonoMethod *wrapper;
7025 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7026 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
7027 domain->capture_context_method = mono_compile_method (method);
7030 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7032 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7035 * mono_async_result_new:
7036 * @domain:domain where the object will be created.
7037 * @handle: wait handle.
7038 * @state: state to pass to AsyncResult
7039 * @data: C closure data.
7041 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7042 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7046 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
7048 MONO_REQ_GC_UNSAFE_MODE;
7051 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
7052 mono_error_raise_exception (&error); /* FIXME don't raise here */
7053 MonoObject *context = mono_runtime_capture_context (domain);
7054 /* we must capture the execution context from the original thread */
7056 MONO_OBJECT_SETREF (res, execution_context, context);
7057 /* note: result may be null if the flow is suppressed */
7060 res->data = (void **)data;
7061 MONO_OBJECT_SETREF (res, object_data, object_data);
7062 MONO_OBJECT_SETREF (res, async_state, state);
7063 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, &error);
7064 mono_error_raise_exception (&error); /* FIXME don't raise here */
7066 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7068 res->sync_completed = FALSE;
7069 res->completed = FALSE;
7075 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7077 MONO_REQ_GC_UNSAFE_MODE;
7084 g_assert (ares->async_delegate);
7086 ac = (MonoAsyncCall*) ares->object_data;
7088 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
7090 gpointer wait_event = NULL;
7092 ac->msg->exc = NULL;
7093 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
7094 MONO_OBJECT_SETREF (ac, res, res);
7096 mono_monitor_enter ((MonoObject*) ares);
7097 ares->completed = 1;
7099 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7100 mono_monitor_exit ((MonoObject*) ares);
7102 if (wait_event != NULL)
7103 SetEvent (wait_event);
7105 if (ac->cb_method) {
7106 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7107 if (mono_error_set_pending_exception (&error))
7116 mono_message_init (MonoDomain *domain,
7117 MonoMethodMessage *this_obj,
7118 MonoReflectionMethod *method,
7119 MonoArray *out_args)
7121 MONO_REQ_GC_UNSAFE_MODE;
7123 static MonoClass *object_array_klass;
7124 static MonoClass *byte_array_klass;
7125 static MonoClass *string_array_klass;
7127 MonoMethodSignature *sig = mono_method_signature (method->method);
7134 if (!object_array_klass) {
7137 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7139 byte_array_klass = klass;
7141 klass = mono_array_class_get (mono_defaults.string_class, 1);
7143 string_array_klass = klass;
7145 klass = mono_array_class_get (mono_defaults.object_class, 1);
7148 mono_atomic_store_release (&object_array_klass, klass);
7151 MONO_OBJECT_SETREF (this_obj, method, method);
7153 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
7154 mono_error_raise_exception (&error); /* FIXME don't raise here */
7156 MONO_OBJECT_SETREF (this_obj, args, arr);
7158 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
7159 mono_error_raise_exception (&error); /* FIXME don't raise here */
7161 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7163 this_obj->async_result = NULL;
7164 this_obj->call_type = CallType_Sync;
7166 names = g_new (char *, sig->param_count);
7167 mono_method_get_param_names (method->method, (const char **) names);
7169 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
7170 mono_error_raise_exception (&error); /* FIXME don't raise here */
7172 MONO_OBJECT_SETREF (this_obj, names, arr);
7174 for (i = 0; i < sig->param_count; i++) {
7175 name = mono_string_new (domain, names [i]);
7176 mono_array_setref (this_obj->names, i, name);
7180 for (i = 0, j = 0; i < sig->param_count; i++) {
7181 if (sig->params [i]->byref) {
7183 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7184 mono_array_setref (this_obj->args, i, arg);
7188 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7192 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7195 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7199 #ifndef DISABLE_REMOTING
7201 * mono_remoting_invoke:
7202 * @real_proxy: pointer to a RealProxy object
7203 * @msg: The MonoMethodMessage to execute
7204 * @exc: used to store exceptions
7205 * @out_args: used to store output arguments
7207 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7208 * IMessage interface and it is not trivial to extract results from there. So
7209 * we call an helper method PrivateInvoke instead of calling
7210 * RealProxy::Invoke() directly.
7212 * Returns: the result object.
7215 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7217 MONO_REQ_GC_UNSAFE_MODE;
7220 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7225 mono_error_init (error);
7227 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7230 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7232 mono_error_set_not_supported (error, "Linked away.");
7235 real_proxy->vtable->domain->private_invoke_method = im;
7238 pa [0] = real_proxy;
7243 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7244 return_val_if_nok (error, NULL);
7251 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7252 MonoObject **exc, MonoArray **out_args)
7254 MONO_REQ_GC_UNSAFE_MODE;
7256 static MonoClass *object_array_klass;
7260 MonoMethodSignature *sig;
7263 int i, j, outarg_count = 0;
7265 #ifndef DISABLE_REMOTING
7266 if (target && mono_object_is_transparent_proxy (target)) {
7267 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7268 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7269 target = tp->rp->unwrapped_server;
7271 ret = mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, &error);
7272 mono_error_raise_exception (&error); /* FIXME don't raise here */
7279 domain = mono_domain_get ();
7280 method = msg->method->method;
7281 sig = mono_method_signature (method);
7283 for (i = 0; i < sig->param_count; i++) {
7284 if (sig->params [i]->byref)
7288 if (!object_array_klass) {
7291 klass = mono_array_class_get (mono_defaults.object_class, 1);
7294 mono_memory_barrier ();
7295 object_array_klass = klass;
7298 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
7299 mono_error_raise_exception (&error); /* FIXME don't raise here */
7301 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7304 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
7306 for (i = 0, j = 0; i < sig->param_count; i++) {
7307 if (sig->params [i]->byref) {
7309 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7310 mono_array_setref (*out_args, j, arg);
7319 * mono_object_to_string:
7321 * @exc: Any exception thrown by ToString (). May be NULL.
7323 * Returns: the result of calling ToString () on an object.
7326 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7328 MONO_REQ_GC_UNSAFE_MODE;
7330 static MonoMethod *to_string = NULL;
7339 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7341 method = mono_object_get_virtual_method (obj, to_string);
7343 // Unbox value type if needed
7344 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7345 target = mono_object_unbox (obj);
7349 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7350 if (*exc == NULL && !mono_error_ok (&error))
7351 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7353 mono_error_cleanup (&error);
7355 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7356 mono_error_raise_exception (&error); /* FIXME don't raise here */
7363 * mono_print_unhandled_exception:
7364 * @exc: The exception
7366 * Prints the unhandled exception.
7369 mono_print_unhandled_exception (MonoObject *exc)
7371 MONO_REQ_GC_UNSAFE_MODE;
7374 char *message = (char*)"";
7375 gboolean free_message = FALSE;
7378 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7379 message = g_strdup ("OutOfMemoryException");
7380 free_message = TRUE;
7381 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7382 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7383 free_message = TRUE;
7386 if (((MonoException*)exc)->native_trace_ips) {
7387 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7388 free_message = TRUE;
7390 MonoObject *other_exc = NULL;
7391 str = mono_object_to_string (exc, &other_exc);
7393 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7394 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7396 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7397 original_backtrace, nested_backtrace);
7399 g_free (original_backtrace);
7400 g_free (nested_backtrace);
7401 free_message = TRUE;
7403 message = mono_string_to_utf8_checked (str, &error);
7404 if (!mono_error_ok (&error)) {
7405 mono_error_cleanup (&error);
7406 message = (char *) "";
7408 free_message = TRUE;
7415 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7416 * exc->vtable->klass->name, message);
7418 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7425 * mono_delegate_ctor:
7426 * @this: pointer to an uninitialized delegate object
7427 * @target: target object
7428 * @addr: pointer to native code
7431 * Initialize a delegate and sets a specific method, not the one
7432 * associated with addr. This is useful when sharing generic code.
7433 * In that case addr will most probably not be associated with the
7434 * correct instantiation of the method.
7437 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7439 MONO_REQ_GC_UNSAFE_MODE;
7441 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7443 g_assert (this_obj);
7446 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7449 delegate->method = method;
7451 mono_stats.delegate_creations++;
7453 #ifndef DISABLE_REMOTING
7454 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7456 method = mono_marshal_get_remoting_invoke (method);
7457 delegate->method_ptr = mono_compile_method (method);
7458 MONO_OBJECT_SETREF (delegate, target, target);
7462 delegate->method_ptr = addr;
7463 MONO_OBJECT_SETREF (delegate, target, target);
7466 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7467 if (callbacks.init_delegate)
7468 callbacks.init_delegate (delegate);
7472 * mono_delegate_ctor:
7473 * @this: pointer to an uninitialized delegate object
7474 * @target: target object
7475 * @addr: pointer to native code
7477 * This is used to initialize a delegate.
7480 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7482 MONO_REQ_GC_UNSAFE_MODE;
7484 MonoDomain *domain = mono_domain_get ();
7486 MonoMethod *method = NULL;
7490 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7492 if (!ji && domain != mono_get_root_domain ())
7493 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7495 method = mono_jit_info_get_method (ji);
7496 g_assert (!method->klass->generic_container);
7499 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7503 * mono_method_call_message_new:
7504 * @method: method to encapsulate
7505 * @params: parameters to the method
7506 * @invoke: optional, delegate invoke.
7507 * @cb: async callback delegate.
7508 * @state: state passed to the async callback.
7510 * Translates arguments pointers into a MonoMethodMessage.
7513 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7514 MonoDelegate **cb, MonoObject **state)
7516 MONO_REQ_GC_UNSAFE_MODE;
7520 MonoDomain *domain = mono_domain_get ();
7521 MonoMethodSignature *sig = mono_method_signature (method);
7522 MonoMethodMessage *msg;
7525 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7526 mono_error_raise_exception (&error); /* FIXME don't raise here */
7529 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7530 mono_error_raise_exception (&error); /* FIXME don't raise here */
7531 mono_message_init (domain, msg, rm, NULL);
7532 count = sig->param_count - 2;
7534 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7535 mono_error_raise_exception (&error); /* FIXME don't raise here */
7536 mono_message_init (domain, msg, rm, NULL);
7537 count = sig->param_count;
7540 for (i = 0; i < count; i++) {
7545 if (sig->params [i]->byref)
7546 vpos = *((gpointer *)params [i]);
7550 klass = mono_class_from_mono_type (sig->params [i]);
7552 if (klass->valuetype) {
7553 arg = mono_value_box_checked (domain, klass, vpos, &error);
7554 mono_error_raise_exception (&error); /* FIXME don't raise here */
7556 arg = *((MonoObject **)vpos);
7558 mono_array_setref (msg->args, i, arg);
7561 if (cb != NULL && state != NULL) {
7562 *cb = *((MonoDelegate **)params [i]);
7564 *state = *((MonoObject **)params [i]);
7571 * mono_method_return_message_restore:
7573 * Restore results from message based processing back to arguments pointers
7576 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7578 MONO_REQ_GC_UNSAFE_MODE;
7580 mono_error_init (error);
7582 MonoMethodSignature *sig = mono_method_signature (method);
7583 int i, j, type, size, out_len;
7585 if (out_args == NULL)
7587 out_len = mono_array_length (out_args);
7591 for (i = 0, j = 0; i < sig->param_count; i++) {
7592 MonoType *pt = sig->params [i];
7597 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7601 arg = (char *)mono_array_get (out_args, gpointer, j);
7604 g_assert (type != MONO_TYPE_VOID);
7606 if (MONO_TYPE_IS_REFERENCE (pt)) {
7607 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7610 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7611 size = mono_class_value_size (klass, NULL);
7612 if (klass->has_references)
7613 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7615 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7617 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7618 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7627 #ifndef DISABLE_REMOTING
7630 * mono_load_remote_field:
7631 * @this: pointer to an object
7632 * @klass: klass of the object containing @field
7633 * @field: the field to load
7634 * @res: a storage to store the result
7636 * This method is called by the runtime on attempts to load fields of
7637 * transparent proxy objects. @this points to such TP, @klass is the class of
7638 * the object containing @field. @res is a storage location which can be
7639 * used to store the result.
7641 * Returns: an address pointing to the value of field.
7644 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7647 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7648 mono_error_cleanup (&error);
7653 * mono_load_remote_field_checked:
7654 * @this: pointer to an object
7655 * @klass: klass of the object containing @field
7656 * @field: the field to load
7657 * @res: a storage to store the result
7658 * @error: set on error
7660 * This method is called by the runtime on attempts to load fields of
7661 * transparent proxy objects. @this points to such TP, @klass is the class of
7662 * the object containing @field. @res is a storage location which can be
7663 * used to store the result.
7665 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
7668 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
7670 MONO_REQ_GC_UNSAFE_MODE;
7672 static MonoMethod *getter = NULL;
7674 mono_error_init (error);
7676 MonoDomain *domain = mono_domain_get ();
7677 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7678 MonoClass *field_class;
7679 MonoMethodMessage *msg;
7680 MonoArray *out_args;
7684 g_assert (mono_object_is_transparent_proxy (this_obj));
7685 g_assert (res != NULL);
7687 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7688 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7693 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7695 mono_error_set_not_supported (error, "Linked away.");
7700 field_class = mono_class_from_mono_type (field->type);
7702 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7703 return_val_if_nok (error, NULL);
7704 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
7705 return_val_if_nok (error, NULL);
7706 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
7707 return_val_if_nok (error, NULL);
7708 mono_message_init (domain, msg, rm, out_args);
7710 full_name = mono_type_get_full_name (klass);
7711 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7712 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7715 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7716 return_val_if_nok (error, NULL);
7719 mono_error_set_exception_instance (error, (MonoException *)exc);
7723 if (mono_array_length (out_args) == 0)
7726 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
7728 if (field_class->valuetype) {
7729 return ((char *)*res) + sizeof (MonoObject);
7735 * mono_load_remote_field_new:
7740 * Missing documentation.
7743 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7747 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
7748 mono_error_cleanup (&error);
7753 * mono_load_remote_field_new_icall:
7754 * @this: pointer to an object
7755 * @klass: klass of the object containing @field
7756 * @field: the field to load
7758 * This method is called by the runtime on attempts to load fields of
7759 * transparent proxy objects. @this points to such TP, @klass is the class of
7760 * the object containing @field.
7762 * Returns: a freshly allocated object containing the value of the
7763 * field. On failure returns NULL and throws an exception.
7766 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7769 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
7770 mono_error_set_pending_exception (&error);
7775 * mono_load_remote_field_new_checked:
7776 * @this: pointer to an object
7777 * @klass: klass of the object containing @field
7778 * @field: the field to load
7779 * @error: set on error.
7781 * This method is called by the runtime on attempts to load fields of
7782 * transparent proxy objects. @this points to such TP, @klass is the class of
7783 * the object containing @field.
7785 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
7788 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
7790 MONO_REQ_GC_UNSAFE_MODE;
7792 mono_error_init (error);
7794 static MonoMethod *getter = NULL;
7795 MonoDomain *domain = mono_domain_get ();
7796 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7797 MonoClass *field_class;
7798 MonoMethodMessage *msg;
7799 MonoArray *out_args;
7800 MonoObject *exc, *res;
7803 g_assert (mono_object_is_transparent_proxy (this_obj));
7805 field_class = mono_class_from_mono_type (field->type);
7807 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7809 if (field_class->valuetype) {
7810 res = mono_object_new_checked (domain, field_class, error);
7811 return_val_if_nok (error, NULL);
7812 val = ((gchar *) res) + sizeof (MonoObject);
7816 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7821 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7823 mono_error_set_not_supported (error, "Linked away.");
7828 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7829 return_val_if_nok (error, NULL);
7830 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
7831 return_val_if_nok (error, NULL);
7833 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
7834 return_val_if_nok (error, NULL);
7835 mono_message_init (domain, msg, rm, out_args);
7837 full_name = mono_type_get_full_name (klass);
7838 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7839 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7842 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7843 return_val_if_nok (error, NULL);
7846 mono_error_set_exception_instance (error, (MonoException *)exc);
7850 if (mono_array_length (out_args) == 0)
7853 res = mono_array_get (out_args, MonoObject *, 0);
7859 * mono_store_remote_field:
7860 * @this_obj: pointer to an object
7861 * @klass: klass of the object containing @field
7862 * @field: the field to load
7863 * @val: the value/object to store
7865 * This method is called by the runtime on attempts to store fields of
7866 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7867 * the object containing @field. @val is the new value to store in @field.
7870 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7873 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
7874 mono_error_cleanup (&error);
7878 * mono_store_remote_field_checked:
7879 * @this_obj: pointer to an object
7880 * @klass: klass of the object containing @field
7881 * @field: the field to load
7882 * @val: the value/object to store
7883 * @error: set on error
7885 * This method is called by the runtime on attempts to store fields of
7886 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7887 * the object containing @field. @val is the new value to store in @field.
7889 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
7892 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
7895 MONO_REQ_GC_UNSAFE_MODE;
7897 static MonoMethod *setter = NULL;
7899 MonoDomain *domain = mono_domain_get ();
7900 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7901 MonoClass *field_class;
7902 MonoMethodMessage *msg;
7903 MonoArray *out_args;
7908 mono_error_init (error);
7910 g_assert (mono_object_is_transparent_proxy (this_obj));
7912 field_class = mono_class_from_mono_type (field->type);
7914 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7915 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7916 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7921 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7923 mono_error_set_not_supported (error, "Linked away.");
7928 if (field_class->valuetype) {
7929 arg = mono_value_box_checked (domain, field_class, val, error);
7930 return_val_if_nok (error, FALSE);
7932 arg = *((MonoObject **)val);
7935 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7936 return_val_if_nok (error, FALSE);
7937 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
7938 return_val_if_nok (error, FALSE);
7939 mono_message_init (domain, msg, rm, NULL);
7941 full_name = mono_type_get_full_name (klass);
7942 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7943 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7944 mono_array_setref (msg->args, 2, arg);
7947 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
7948 return_val_if_nok (error, FALSE);
7951 mono_error_set_exception_instance (error, (MonoException *)exc);
7958 * mono_store_remote_field_new:
7964 * Missing documentation
7967 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7970 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
7971 mono_error_cleanup (&error);
7975 * mono_store_remote_field_new_icall:
7981 * Missing documentation
7984 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7987 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
7988 mono_error_set_pending_exception (&error);
7992 * mono_store_remote_field_new_checked:
7999 * Missing documentation
8002 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8004 MONO_REQ_GC_UNSAFE_MODE;
8006 static MonoMethod *setter = NULL;
8007 MonoDomain *domain = mono_domain_get ();
8008 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8009 MonoClass *field_class;
8010 MonoMethodMessage *msg;
8011 MonoArray *out_args;
8015 mono_error_init (error);
8017 g_assert (mono_object_is_transparent_proxy (this_obj));
8019 field_class = mono_class_from_mono_type (field->type);
8021 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8022 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8023 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8028 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8030 mono_error_set_not_supported (error, "Linked away.");
8035 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8036 return_val_if_nok (error, FALSE);
8037 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8038 return_val_if_nok (error, FALSE);
8039 mono_message_init (domain, msg, rm, NULL);
8041 full_name = mono_type_get_full_name (klass);
8042 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8043 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8044 mono_array_setref (msg->args, 2, arg);
8047 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8048 return_val_if_nok (error, FALSE);
8051 mono_error_set_exception_instance (error, (MonoException *)exc);
8059 * mono_create_ftnptr:
8061 * Given a function address, create a function descriptor for it.
8062 * This is only needed on some platforms.
8065 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8067 return callbacks.create_ftnptr (domain, addr);
8071 * mono_get_addr_from_ftnptr:
8073 * Given a pointer to a function descriptor, return the function address.
8074 * This is only needed on some platforms.
8077 mono_get_addr_from_ftnptr (gpointer descr)
8079 return callbacks.get_addr_from_ftnptr (descr);
8083 * mono_string_chars:
8086 * Returns a pointer to the UCS16 characters stored in the MonoString
8089 mono_string_chars (MonoString *s)
8091 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8097 * mono_string_length:
8100 * Returns the lenght in characters of the string
8103 mono_string_length (MonoString *s)
8105 MONO_REQ_GC_UNSAFE_MODE;
8111 * mono_array_length:
8112 * @array: a MonoArray*
8114 * Returns the total number of elements in the array. This works for
8115 * both vectors and multidimensional arrays.
8118 mono_array_length (MonoArray *array)
8120 MONO_REQ_GC_UNSAFE_MODE;
8122 return array->max_length;
8126 * mono_array_addr_with_size:
8127 * @array: a MonoArray*
8128 * @size: size of the array elements
8129 * @idx: index into the array
8131 * Use this function to obtain the address for the @idx item on the
8132 * @array containing elements of size @size.
8134 * This method performs no bounds checking or type checking.
8136 * Returns the address of the @idx element in the array.
8139 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8141 MONO_REQ_GC_UNSAFE_MODE;
8143 return ((char*)(array)->vector) + size * idx;
8148 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8150 MonoDomain *domain = mono_domain_get ();
8154 mono_error_init (error);
8158 len = g_list_length (list);
8159 res = mono_array_new_checked (domain, eclass, len, error);
8160 return_val_if_nok (error, NULL);
8162 for (i = 0; list; list = list->next, i++)
8163 mono_array_set (res, gpointer, i, list->data);
8170 * The following section is purely to declare prototypes and
8171 * document the API, as these C files are processed by our
8177 * @array: array to alter
8178 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8179 * @index: index into the array
8180 * @value: value to set
8182 * Value Type version: This sets the @index's element of the @array
8183 * with elements of size sizeof(type) to the provided @value.
8185 * This macro does not attempt to perform type checking or bounds checking.
8187 * Use this to set value types in a `MonoArray`.
8189 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8194 * mono_array_setref:
8195 * @array: array to alter
8196 * @index: index into the array
8197 * @value: value to set
8199 * Reference Type version: This sets the @index's element of the
8200 * @array with elements of size sizeof(type) to the provided @value.
8202 * This macro does not attempt to perform type checking or bounds checking.
8204 * Use this to reference types in a `MonoArray`.
8206 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8212 * @array: array on which to operate on
8213 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8214 * @index: index into the array
8216 * Use this macro to retrieve the @index element of an @array and
8217 * extract the value assuming that the elements of the array match
8218 * the provided type value.
8220 * This method can be used with both arrays holding value types and
8221 * reference types. For reference types, the @type parameter should
8222 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8224 * This macro does not attempt to perform type checking or bounds checking.
8226 * Returns: The element at the @index position in the @array.
8228 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)