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/metadata/w32event.h>
45 #include <mono/utils/strenc.h>
46 #include <mono/utils/mono-counters.h>
47 #include <mono/utils/mono-error-internals.h>
48 #include <mono/utils/mono-memory-model.h>
49 #include <mono/utils/checked-build.h>
50 #include <mono/utils/mono-threads.h>
51 #include <mono/utils/mono-threads-coop.h>
52 #include "cominterop.h"
53 #include <mono/io-layer/io-layer.h>
56 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
59 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
62 free_main_args (void);
65 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
68 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
70 /* Class lazy loading functions */
71 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
72 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
73 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
74 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
75 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
78 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
79 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
80 static mono_mutex_t ldstr_section;
84 * mono_runtime_object_init:
85 * @this_obj: the object to initialize
87 * This function calls the zero-argument constructor (which must
88 * exist) for the given object.
91 mono_runtime_object_init (MonoObject *this_obj)
94 mono_runtime_object_init_checked (this_obj, &error);
95 mono_error_assert_ok (&error);
99 * mono_runtime_object_init_checked:
100 * @this_obj: the object to initialize
101 * @error: set on error.
103 * This function calls the zero-argument constructor (which must
104 * exist) for the given object and returns TRUE on success, or FALSE
105 * on error and sets @error.
108 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
110 MONO_REQ_GC_UNSAFE_MODE;
112 MonoMethod *method = NULL;
113 MonoClass *klass = this_obj->vtable->klass;
115 mono_error_init (error);
116 method = mono_class_get_method_from_name (klass, ".ctor", 0);
118 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
120 if (method->klass->valuetype)
121 this_obj = (MonoObject *)mono_object_unbox (this_obj);
123 mono_runtime_invoke_checked (method, this_obj, NULL, error);
124 return is_ok (error);
127 /* The pseudo algorithm for type initialization from the spec
128 Note it doesn't say anything about domains - only threads.
130 2. If the type is initialized you are done.
131 2.1. If the type is not yet initialized, try to take an
133 2.2. If successful, record this thread as responsible for
134 initializing the type and proceed to step 2.3.
135 2.2.1. If not, see whether this thread or any thread
136 waiting for this thread to complete already holds the lock.
137 2.2.2. If so, return since blocking would create a deadlock. This thread
138 will now see an incompletely initialized state for the type,
139 but no deadlock will arise.
140 2.2.3 If not, block until the type is initialized then return.
141 2.3 Initialize the parent type and then all interfaces implemented
143 2.4 Execute the type initialization code for this type.
144 2.5 Mark the type as initialized, release the initialization lock,
145 awaken any threads waiting for this type to be initialized,
152 MonoNativeThreadId initializing_tid;
153 guint32 waiting_count;
155 MonoCoopMutex initialization_section;
156 } TypeInitializationLock;
158 /* for locking access to type_initialization_hash and blocked_thread_hash */
159 static MonoCoopMutex type_initialization_section;
162 mono_type_initialization_lock (void)
164 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
165 mono_coop_mutex_lock (&type_initialization_section);
169 mono_type_initialization_unlock (void)
171 mono_coop_mutex_unlock (&type_initialization_section);
175 mono_type_init_lock (TypeInitializationLock *lock)
177 MONO_REQ_GC_NEUTRAL_MODE;
179 mono_coop_mutex_lock (&lock->initialization_section);
183 mono_type_init_unlock (TypeInitializationLock *lock)
185 mono_coop_mutex_unlock (&lock->initialization_section);
188 /* from vtable to lock */
189 static GHashTable *type_initialization_hash;
191 /* from thread id to thread id being waited on */
192 static GHashTable *blocked_thread_hash;
195 static MonoThread *main_thread;
197 /* Functions supplied by the runtime */
198 static MonoRuntimeCallbacks callbacks;
201 * mono_thread_set_main:
202 * @thread: thread to set as the main thread
204 * This function can be used to instruct the runtime to treat @thread
205 * as the main thread, ie, the thread that would normally execute the Main()
206 * method. This basically means that at the end of @thread, the runtime will
207 * wait for the existing foreground threads to quit and other such details.
210 mono_thread_set_main (MonoThread *thread)
212 MONO_REQ_GC_UNSAFE_MODE;
214 static gboolean registered = FALSE;
217 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 main_thread = thread;
225 mono_thread_get_main (void)
227 MONO_REQ_GC_UNSAFE_MODE;
233 mono_type_initialization_init (void)
235 mono_coop_mutex_init_recursive (&type_initialization_section);
236 type_initialization_hash = g_hash_table_new (NULL, NULL);
237 blocked_thread_hash = g_hash_table_new (NULL, NULL);
238 mono_os_mutex_init_recursive (&ldstr_section);
242 mono_type_initialization_cleanup (void)
245 /* This is causing race conditions with
246 * mono_release_type_locks
248 mono_coop_mutex_destroy (&type_initialization_section);
249 g_hash_table_destroy (type_initialization_hash);
250 type_initialization_hash = NULL;
252 mono_os_mutex_destroy (&ldstr_section);
253 g_hash_table_destroy (blocked_thread_hash);
254 blocked_thread_hash = NULL;
260 * get_type_init_exception_for_vtable:
262 * Return the stored type initialization exception for VTABLE.
264 static MonoException*
265 get_type_init_exception_for_vtable (MonoVTable *vtable)
267 MONO_REQ_GC_UNSAFE_MODE;
270 MonoDomain *domain = vtable->domain;
271 MonoClass *klass = vtable->klass;
275 if (!vtable->init_failed)
276 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
279 * If the initializing thread was rudely aborted, the exception is not stored
283 mono_domain_lock (domain);
284 if (domain->type_init_exception_hash)
285 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
286 mono_domain_unlock (domain);
289 if (klass->name_space && *klass->name_space)
290 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
292 full_name = g_strdup (klass->name);
293 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
295 return_val_if_nok (&error, NULL);
302 * mono_runtime_class_init:
303 * @vtable: vtable that needs to be initialized
305 * This routine calls the class constructor for @vtable.
308 mono_runtime_class_init (MonoVTable *vtable)
310 MONO_REQ_GC_UNSAFE_MODE;
313 mono_runtime_class_init_full (vtable, &error);
314 mono_error_assert_ok (&error);
318 * mono_runtime_class_init_full:
319 * @vtable that neeeds to be initialized
320 * @error set on error
322 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
326 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
328 MONO_REQ_GC_UNSAFE_MODE;
330 MonoMethod *method = NULL;
333 MonoDomain *domain = vtable->domain;
334 TypeInitializationLock *lock;
335 MonoNativeThreadId tid;
336 int do_initialization = 0;
337 MonoDomain *last_domain = NULL;
338 MonoException * pending_tae = NULL;
340 mono_error_init (error);
342 if (vtable->initialized)
345 klass = vtable->klass;
347 if (!klass->image->checked_module_cctor) {
348 mono_image_check_for_module_cctor (klass->image);
349 if (klass->image->has_module_cctor) {
350 MonoClass *module_klass;
351 MonoVTable *module_vtable;
353 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
358 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
361 if (!mono_runtime_class_init_full (module_vtable, error))
365 method = mono_class_get_cctor (klass);
367 vtable->initialized = 1;
371 tid = mono_native_thread_id_get ();
373 mono_type_initialization_lock ();
374 /* double check... */
375 if (vtable->initialized) {
376 mono_type_initialization_unlock ();
379 if (vtable->init_failed) {
380 mono_type_initialization_unlock ();
382 /* The type initialization already failed once, rethrow the same exception */
383 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
386 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
388 /* This thread will get to do the initialization */
389 if (mono_domain_get () != domain) {
390 /* Transfer into the target domain */
391 last_domain = mono_domain_get ();
392 if (!mono_domain_set (domain, FALSE)) {
393 vtable->initialized = 1;
394 mono_type_initialization_unlock ();
395 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
399 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
400 mono_coop_mutex_init_recursive (&lock->initialization_section);
401 lock->initializing_tid = tid;
402 lock->waiting_count = 1;
404 /* grab the vtable lock while this thread still owns type_initialization_section */
405 /* This is why type_initialization_lock needs to enter blocking mode */
406 mono_type_init_lock (lock);
407 g_hash_table_insert (type_initialization_hash, vtable, lock);
408 do_initialization = 1;
411 TypeInitializationLock *pending_lock;
413 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
414 mono_type_initialization_unlock ();
417 /* see if the thread doing the initialization is already blocked on this thread */
418 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
419 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
420 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
421 if (!pending_lock->done) {
422 mono_type_initialization_unlock ();
425 /* the thread doing the initialization is blocked on this thread,
426 but on a lock that has already been freed. It just hasn't got
431 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
433 ++lock->waiting_count;
434 /* record the fact that we are waiting on the initializing thread */
435 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
437 mono_type_initialization_unlock ();
439 if (do_initialization) {
440 MonoException *exc = NULL;
442 mono_threads_begin_abort_protected_block ();
443 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
444 mono_threads_end_abort_protected_block ();
446 //exception extracted, error will be set to the right value later
447 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
448 exc = mono_error_convert_to_exception (error);
450 mono_error_cleanup (error);
452 mono_error_init (error);
454 /* If the initialization failed, mark the class as unusable. */
455 /* Avoid infinite loops */
457 (klass->image == mono_defaults.corlib &&
458 !strcmp (klass->name_space, "System") &&
459 !strcmp (klass->name, "TypeInitializationException")))) {
460 vtable->init_failed = 1;
462 if (klass->name_space && *klass->name_space)
463 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
465 full_name = g_strdup (klass->name);
467 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
470 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
473 * Store the exception object so it could be thrown on subsequent
476 mono_domain_lock (domain);
477 if (!domain->type_init_exception_hash)
478 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");
479 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
480 mono_domain_unlock (domain);
484 mono_domain_set (last_domain, TRUE);
486 mono_type_init_unlock (lock);
487 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
489 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
490 if (!pending_tae && mono_get_eh_callbacks ()->mono_above_abort_threshold ())
491 pending_tae = mono_thread_try_resume_interruption ();
493 /* this just blocks until the initializing thread is done */
494 mono_type_init_lock (lock);
495 mono_type_init_unlock (lock);
498 mono_type_initialization_lock ();
499 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
500 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
501 --lock->waiting_count;
502 if (lock->waiting_count == 0) {
503 mono_coop_mutex_destroy (&lock->initialization_section);
504 g_hash_table_remove (type_initialization_hash, vtable);
507 mono_memory_barrier ();
508 if (!vtable->init_failed)
509 vtable->initialized = 1;
510 mono_type_initialization_unlock ();
514 mono_error_set_exception_instance (error, pending_tae);
515 else if (vtable->init_failed) {
516 /* Either we were the initializing thread or we waited for the initialization */
517 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
524 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
526 MONO_REQ_GC_NEUTRAL_MODE;
528 MonoVTable *vtable = (MonoVTable*)key;
530 TypeInitializationLock *lock = (TypeInitializationLock*) value;
531 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
534 * Have to set this since it cannot be set by the normal code in
535 * mono_runtime_class_init (). In this case, the exception object is not stored,
536 * and get_type_init_exception_for_class () needs to be aware of this.
538 vtable->init_failed = 1;
539 mono_type_init_unlock (lock);
540 --lock->waiting_count;
541 if (lock->waiting_count == 0) {
542 mono_coop_mutex_destroy (&lock->initialization_section);
551 mono_release_type_locks (MonoInternalThread *thread)
553 MONO_REQ_GC_UNSAFE_MODE;
555 mono_type_initialization_lock ();
556 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
557 mono_type_initialization_unlock ();
560 #ifndef DISABLE_REMOTING
563 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
565 if (!callbacks.create_remoting_trampoline)
566 g_error ("remoting not installed");
567 return callbacks.create_remoting_trampoline (domain, method, target, error);
572 static MonoImtTrampolineBuilder imt_trampoline_builder;
573 static gboolean always_build_imt_trampolines;
575 #if (MONO_IMT_SIZE > 32)
576 #error "MONO_IMT_SIZE cannot be larger than 32"
580 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
582 memcpy (&callbacks, cbs, sizeof (*cbs));
585 MonoRuntimeCallbacks*
586 mono_get_runtime_callbacks (void)
592 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
594 imt_trampoline_builder = func;
598 mono_set_always_build_imt_trampolines (gboolean value)
600 always_build_imt_trampolines = value;
604 * mono_compile_method:
605 * @method: The method to compile.
607 * This JIT-compiles the method, and returns the pointer to the native code
611 mono_compile_method (MonoMethod *method)
614 gpointer result = mono_compile_method_checked (method, &error);
615 mono_error_cleanup (&error);
620 * mono_compile_method:
621 * @method: The method to compile.
622 * @error: set on error.
624 * This JIT-compiles the method, and returns the pointer to the native code
625 * produced. On failure returns NULL and sets @error.
628 mono_compile_method_checked (MonoMethod *method, MonoError *error)
632 MONO_REQ_GC_NEUTRAL_MODE
634 mono_error_init (error);
636 g_assert (callbacks.compile_method);
637 res = callbacks.compile_method (method, error);
642 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
646 MONO_REQ_GC_NEUTRAL_MODE;
648 mono_error_init (error);
649 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
654 mono_runtime_create_delegate_trampoline (MonoClass *klass)
656 MONO_REQ_GC_NEUTRAL_MODE
658 g_assert (callbacks.create_delegate_trampoline);
659 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
663 * mono_runtime_free_method:
664 * @domain; domain where the method is hosted
665 * @method: method to release
667 * This routine is invoked to free the resources associated with
668 * a method that has been JIT compiled. This is used to discard
669 * methods that were used only temporarily (for example, used in marshalling)
673 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
675 MONO_REQ_GC_NEUTRAL_MODE
677 if (callbacks.free_method)
678 callbacks.free_method (domain, method);
680 mono_method_clear_object (domain, method);
682 mono_free_method (method);
686 * The vtables in the root appdomain are assumed to be reachable by other
687 * roots, and we don't use typed allocation in the other domains.
690 /* The sync block is no longer a GC pointer */
691 #define GC_HEADER_BITMAP (0)
693 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
696 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
698 MONO_REQ_GC_NEUTRAL_MODE;
700 MonoClassField *field;
706 max_size = mono_class_data_size (klass) / sizeof (gpointer);
708 max_size = klass->instance_size / sizeof (gpointer);
709 if (max_size > size) {
710 g_assert (offset <= 0);
711 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
716 /*An Ephemeron cannot be marked by sgen*/
717 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
719 memset (bitmap, 0, size / 8);
724 for (p = klass; p != NULL; p = p->parent) {
725 gpointer iter = NULL;
726 while ((field = mono_class_get_fields (p, &iter))) {
730 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
732 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
735 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
738 /* FIXME: should not happen, flag as type load error */
739 if (field->type->byref)
742 if (static_fields && field->offset == -1)
746 pos = field->offset / sizeof (gpointer);
749 type = mono_type_get_underlying_type (field->type);
750 switch (type->type) {
754 case MONO_TYPE_FNPTR:
756 case MONO_TYPE_STRING:
757 case MONO_TYPE_SZARRAY:
758 case MONO_TYPE_CLASS:
759 case MONO_TYPE_OBJECT:
760 case MONO_TYPE_ARRAY:
761 g_assert ((field->offset % sizeof(gpointer)) == 0);
763 g_assert (pos < size || pos <= max_size);
764 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
765 *max_set = MAX (*max_set, pos);
767 case MONO_TYPE_GENERICINST:
768 if (!mono_type_generic_inst_is_valuetype (type)) {
769 g_assert ((field->offset % sizeof(gpointer)) == 0);
771 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
772 *max_set = MAX (*max_set, pos);
777 case MONO_TYPE_VALUETYPE: {
778 MonoClass *fclass = mono_class_from_mono_type (field->type);
779 if (fclass->has_references) {
780 /* remove the object header */
781 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
795 case MONO_TYPE_BOOLEAN:
799 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
810 * mono_class_compute_bitmap:
812 * Mono internal function to compute a bitmap of reference fields in a class.
815 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
817 MONO_REQ_GC_NEUTRAL_MODE;
819 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
824 * similar to the above, but sets the bits in the bitmap for any non-ref field
825 * and ignores static fields
828 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
830 MonoClassField *field;
835 max_size = class->instance_size / sizeof (gpointer);
836 if (max_size >= size) {
837 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
840 for (p = class; p != NULL; p = p->parent) {
841 gpointer iter = NULL;
842 while ((field = mono_class_get_fields (p, &iter))) {
845 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
847 /* FIXME: should not happen, flag as type load error */
848 if (field->type->byref)
851 pos = field->offset / sizeof (gpointer);
854 type = mono_type_get_underlying_type (field->type);
855 switch (type->type) {
856 #if SIZEOF_VOID_P == 8
860 case MONO_TYPE_FNPTR:
865 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
866 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
867 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
870 #if SIZEOF_VOID_P == 4
874 case MONO_TYPE_FNPTR:
879 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
880 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
881 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
887 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
888 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
889 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
892 case MONO_TYPE_BOOLEAN:
895 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
897 case MONO_TYPE_STRING:
898 case MONO_TYPE_SZARRAY:
899 case MONO_TYPE_CLASS:
900 case MONO_TYPE_OBJECT:
901 case MONO_TYPE_ARRAY:
903 case MONO_TYPE_GENERICINST:
904 if (!mono_type_generic_inst_is_valuetype (type)) {
909 case MONO_TYPE_VALUETYPE: {
910 MonoClass *fclass = mono_class_from_mono_type (field->type);
911 /* remove the object header */
912 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
916 g_assert_not_reached ();
925 * mono_class_insecure_overlapping:
926 * check if a class with explicit layout has references and non-references
927 * fields overlapping.
929 * Returns: TRUE if it is insecure to load the type.
932 mono_class_insecure_overlapping (MonoClass *klass)
936 gsize default_bitmap [4] = {0};
938 gsize default_nrbitmap [4] = {0};
939 int i, insecure = FALSE;
942 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
943 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
945 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
946 int idx = i % (sizeof (bitmap [0]) * 8);
947 if (bitmap [idx] & nrbitmap [idx]) {
952 if (bitmap != default_bitmap)
954 if (nrbitmap != default_nrbitmap)
957 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
965 ves_icall_string_alloc (int length)
968 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
969 mono_error_set_pending_exception (&error);
974 /* LOCKING: Acquires the loader lock */
976 mono_class_compute_gc_descriptor (MonoClass *klass)
978 MONO_REQ_GC_NEUTRAL_MODE;
982 gsize default_bitmap [4] = {0};
983 static gboolean gcj_inited = FALSE;
984 MonoGCDescriptor gc_descr;
989 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
990 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
993 mono_loader_unlock ();
997 mono_class_init (klass);
999 if (klass->gc_descr_inited)
1002 bitmap = default_bitmap;
1003 if (klass == mono_defaults.string_class) {
1004 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1005 } else if (klass->rank) {
1006 mono_class_compute_gc_descriptor (klass->element_class);
1007 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1009 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1010 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1011 class->name_space, class->name);*/
1013 /* remove the object header */
1014 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1015 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1016 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1017 class->name_space, class->name);*/
1018 if (bitmap != default_bitmap)
1022 /*static int count = 0;
1025 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1026 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1028 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1029 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1031 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1032 if (bitmap != default_bitmap)
1036 /* Publish the data */
1037 mono_loader_lock ();
1038 klass->gc_descr = gc_descr;
1039 mono_memory_barrier ();
1040 klass->gc_descr_inited = TRUE;
1041 mono_loader_unlock ();
1045 * field_is_special_static:
1046 * @fklass: The MonoClass to look up.
1047 * @field: The MonoClassField describing the field.
1049 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1050 * SPECIAL_STATIC_NONE otherwise.
1053 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1055 MONO_REQ_GC_NEUTRAL_MODE;
1058 MonoCustomAttrInfo *ainfo;
1060 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1061 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1064 for (i = 0; i < ainfo->num_attrs; ++i) {
1065 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1066 if (klass->image == mono_defaults.corlib) {
1067 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1068 mono_custom_attrs_free (ainfo);
1069 return SPECIAL_STATIC_THREAD;
1071 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1072 mono_custom_attrs_free (ainfo);
1073 return SPECIAL_STATIC_CONTEXT;
1077 mono_custom_attrs_free (ainfo);
1078 return SPECIAL_STATIC_NONE;
1081 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1082 #define mix(a,b,c) { \
1083 a -= c; a ^= rot(c, 4); c += b; \
1084 b -= a; b ^= rot(a, 6); a += c; \
1085 c -= b; c ^= rot(b, 8); b += a; \
1086 a -= c; a ^= rot(c,16); c += b; \
1087 b -= a; b ^= rot(a,19); a += c; \
1088 c -= b; c ^= rot(b, 4); b += a; \
1090 #define final(a,b,c) { \
1091 c ^= b; c -= rot(b,14); \
1092 a ^= c; a -= rot(c,11); \
1093 b ^= a; b -= rot(a,25); \
1094 c ^= b; c -= rot(b,16); \
1095 a ^= c; a -= rot(c,4); \
1096 b ^= a; b -= rot(a,14); \
1097 c ^= b; c -= rot(b,24); \
1101 * mono_method_get_imt_slot:
1103 * The IMT slot is embedded into AOTed code, so this must return the same value
1104 * for the same method across all executions. This means:
1105 * - pointers shouldn't be used as hash values.
1106 * - mono_metadata_str_hash () should be used for hashing strings.
1109 mono_method_get_imt_slot (MonoMethod *method)
1111 MONO_REQ_GC_NEUTRAL_MODE;
1113 MonoMethodSignature *sig;
1115 guint32 *hashes_start, *hashes;
1119 /* This can be used to stress tests the collision code */
1123 * We do this to simplify generic sharing. It will hurt
1124 * performance in cases where a class implements two different
1125 * instantiations of the same generic interface.
1126 * The code in build_imt_slots () depends on this.
1128 if (method->is_inflated)
1129 method = ((MonoMethodInflated*)method)->declaring;
1131 sig = mono_method_signature (method);
1132 hashes_count = sig->param_count + 4;
1133 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1134 hashes = hashes_start;
1136 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1137 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1138 method->klass->name_space, method->klass->name, method->name);
1141 /* Initialize hashes */
1142 hashes [0] = mono_metadata_str_hash (method->klass->name);
1143 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1144 hashes [2] = mono_metadata_str_hash (method->name);
1145 hashes [3] = mono_metadata_type_hash (sig->ret);
1146 for (i = 0; i < sig->param_count; i++) {
1147 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1150 /* Setup internal state */
1151 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1153 /* Handle most of the hashes */
1154 while (hashes_count > 3) {
1163 /* Handle the last 3 hashes (all the case statements fall through) */
1164 switch (hashes_count) {
1165 case 3 : c += hashes [2];
1166 case 2 : b += hashes [1];
1167 case 1 : a += hashes [0];
1169 case 0: /* nothing left to add */
1173 g_free (hashes_start);
1174 /* Report the result */
1175 return c % MONO_IMT_SIZE;
1184 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1185 MONO_REQ_GC_NEUTRAL_MODE;
1187 guint32 imt_slot = mono_method_get_imt_slot (method);
1188 MonoImtBuilderEntry *entry;
1190 if (slot_num >= 0 && imt_slot != slot_num) {
1191 /* we build just a single imt slot and this is not it */
1195 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1196 entry->key = method;
1197 entry->value.vtable_slot = vtable_slot;
1198 entry->next = imt_builder [imt_slot];
1199 if (imt_builder [imt_slot] != NULL) {
1200 entry->children = imt_builder [imt_slot]->children + 1;
1201 if (entry->children == 1) {
1202 mono_stats.imt_slots_with_collisions++;
1203 *imt_collisions_bitmap |= (1 << imt_slot);
1206 entry->children = 0;
1207 mono_stats.imt_used_slots++;
1209 imt_builder [imt_slot] = entry;
1212 char *method_name = mono_method_full_name (method, TRUE);
1213 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1214 method, method_name, imt_slot, vtable_slot, entry->children);
1215 g_free (method_name);
1222 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1224 MonoMethod *method = e->key;
1225 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1229 method->klass->name_space,
1230 method->klass->name,
1233 printf (" * %s: NULL\n", message);
1239 compare_imt_builder_entries (const void *p1, const void *p2) {
1240 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1241 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1243 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1247 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1249 MONO_REQ_GC_NEUTRAL_MODE;
1251 int count = end - start;
1252 int chunk_start = out_array->len;
1255 for (i = start; i < end; ++i) {
1256 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1257 item->key = sorted_array [i]->key;
1258 item->value = sorted_array [i]->value;
1259 item->has_target_code = sorted_array [i]->has_target_code;
1260 item->is_equals = TRUE;
1262 item->check_target_idx = out_array->len + 1;
1264 item->check_target_idx = 0;
1265 g_ptr_array_add (out_array, item);
1268 int middle = start + count / 2;
1269 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1271 item->key = sorted_array [middle]->key;
1272 item->is_equals = FALSE;
1273 g_ptr_array_add (out_array, item);
1274 imt_emit_ir (sorted_array, start, middle, out_array);
1275 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1281 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1282 MONO_REQ_GC_NEUTRAL_MODE;
1284 int number_of_entries = entries->children + 1;
1285 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1286 GPtrArray *result = g_ptr_array_new ();
1287 MonoImtBuilderEntry *current_entry;
1290 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1291 sorted_array [i] = current_entry;
1293 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1295 /*for (i = 0; i < number_of_entries; i++) {
1296 print_imt_entry (" sorted array:", sorted_array [i], i);
1299 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1301 g_free (sorted_array);
1306 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1308 MONO_REQ_GC_NEUTRAL_MODE;
1310 if (imt_builder_entry != NULL) {
1311 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1312 /* No collision, return the vtable slot contents */
1313 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1315 /* Collision, build the trampoline */
1316 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1319 result = imt_trampoline_builder (vtable, domain,
1320 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1321 for (i = 0; i < imt_ir->len; ++i)
1322 g_free (g_ptr_array_index (imt_ir, i));
1323 g_ptr_array_free (imt_ir, TRUE);
1335 static MonoImtBuilderEntry*
1336 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1339 * LOCKING: requires the loader and domain locks.
1343 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1345 MONO_REQ_GC_NEUTRAL_MODE;
1349 guint32 imt_collisions_bitmap = 0;
1350 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1351 int method_count = 0;
1352 gboolean record_method_count_for_max_collisions = FALSE;
1353 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1356 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1358 for (i = 0; i < klass->interface_offsets_count; ++i) {
1359 MonoClass *iface = klass->interfaces_packed [i];
1360 int interface_offset = klass->interface_offsets_packed [i];
1361 int method_slot_in_interface, vt_slot;
1363 if (mono_class_has_variant_generic_params (iface))
1364 has_variant_iface = TRUE;
1366 mono_class_setup_methods (iface);
1367 vt_slot = interface_offset;
1368 int mcount = mono_class_get_method_count (iface);
1369 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1372 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1374 * The imt slot of the method is the same as for its declaring method,
1375 * see the comment in mono_method_get_imt_slot (), so we can
1376 * avoid inflating methods which will be discarded by
1377 * add_imt_builder_entry anyway.
1379 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1380 if (mono_method_get_imt_slot (method) != slot_num) {
1385 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1386 if (method->is_generic) {
1387 has_generic_virtual = TRUE;
1392 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1393 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1398 if (extra_interfaces) {
1399 int interface_offset = klass->vtable_size;
1401 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1402 MonoClass* iface = (MonoClass *)list_item->data;
1403 int method_slot_in_interface;
1404 int mcount = mono_class_get_method_count (iface);
1405 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1406 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1408 if (method->is_generic)
1409 has_generic_virtual = TRUE;
1410 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1412 interface_offset += mcount;
1415 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1416 /* overwrite the imt slot only if we're building all the entries or if
1417 * we're building this specific one
1419 if (slot_num < 0 || i == slot_num) {
1420 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1423 if (imt_builder [i]) {
1424 MonoImtBuilderEntry *entry;
1426 /* Link entries with imt_builder [i] */
1427 for (entry = entries; entry->next; entry = entry->next) {
1429 MonoMethod *method = (MonoMethod*)entry->key;
1430 char *method_name = mono_method_full_name (method, TRUE);
1431 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1432 g_free (method_name);
1435 entry->next = imt_builder [i];
1436 entries->children += imt_builder [i]->children + 1;
1438 imt_builder [i] = entries;
1441 if (has_generic_virtual || has_variant_iface) {
1443 * There might be collisions later when the the trampoline is expanded.
1445 imt_collisions_bitmap |= (1 << i);
1448 * The IMT trampoline might be called with an instance of one of the
1449 * generic virtual methods, so has to fallback to the IMT trampoline.
1451 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1453 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1456 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1460 if (imt_builder [i] != NULL) {
1461 int methods_in_slot = imt_builder [i]->children + 1;
1462 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1463 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1464 record_method_count_for_max_collisions = TRUE;
1466 method_count += methods_in_slot;
1470 mono_stats.imt_number_of_methods += method_count;
1471 if (record_method_count_for_max_collisions) {
1472 mono_stats.imt_method_count_when_max_collisions = method_count;
1475 for (i = 0; i < MONO_IMT_SIZE; i++) {
1476 MonoImtBuilderEntry* entry = imt_builder [i];
1477 while (entry != NULL) {
1478 MonoImtBuilderEntry* next = entry->next;
1483 g_free (imt_builder);
1484 /* we OR the bitmap since we may build just a single imt slot at a time */
1485 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1489 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1490 MONO_REQ_GC_NEUTRAL_MODE;
1492 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1496 * mono_vtable_build_imt_slot:
1497 * @vtable: virtual object table struct
1498 * @imt_slot: slot in the IMT table
1500 * Fill the given @imt_slot in the IMT table of @vtable with
1501 * a trampoline or a trampoline for the case of collisions.
1502 * This is part of the internal mono API.
1504 * LOCKING: Take the domain lock.
1507 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1509 MONO_REQ_GC_NEUTRAL_MODE;
1511 gpointer *imt = (gpointer*)vtable;
1512 imt -= MONO_IMT_SIZE;
1513 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1515 /* no support for extra interfaces: the proxy objects will need
1516 * to build the complete IMT
1517 * Update and heck needs to ahppen inside the proper domain lock, as all
1518 * the changes made to a MonoVTable.
1520 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1521 mono_domain_lock (vtable->domain);
1522 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1523 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1524 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1525 mono_domain_unlock (vtable->domain);
1526 mono_loader_unlock ();
1529 #define THUNK_THRESHOLD 10
1532 * mono_method_alloc_generic_virtual_trampoline:
1534 * @size: size in bytes
1536 * Allocs size bytes to be used for the code of a generic virtual
1537 * trampoline. It's either allocated from the domain's code manager or
1538 * reused from a previously invalidated piece.
1540 * LOCKING: The domain lock must be held.
1543 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1545 MONO_REQ_GC_NEUTRAL_MODE;
1547 static gboolean inited = FALSE;
1548 static int generic_virtual_trampolines_size = 0;
1551 mono_counters_register ("Generic virtual trampoline bytes",
1552 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1555 generic_virtual_trampolines_size += size;
1557 return mono_domain_code_reserve (domain, size);
1560 typedef struct _GenericVirtualCase {
1564 struct _GenericVirtualCase *next;
1565 } GenericVirtualCase;
1568 * get_generic_virtual_entries:
1570 * Return IMT entries for the generic virtual method instances and
1571 * variant interface methods for vtable slot
1574 static MonoImtBuilderEntry*
1575 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1577 MONO_REQ_GC_NEUTRAL_MODE;
1579 GenericVirtualCase *list;
1580 MonoImtBuilderEntry *entries;
1582 mono_domain_lock (domain);
1583 if (!domain->generic_virtual_cases)
1584 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1586 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1589 for (; list; list = list->next) {
1590 MonoImtBuilderEntry *entry;
1592 if (list->count < THUNK_THRESHOLD)
1595 entry = g_new0 (MonoImtBuilderEntry, 1);
1596 entry->key = list->method;
1597 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1598 entry->has_target_code = 1;
1600 entry->children = entries->children + 1;
1601 entry->next = entries;
1605 mono_domain_unlock (domain);
1607 /* FIXME: Leaking memory ? */
1612 * mono_method_add_generic_virtual_invocation:
1614 * @vtable_slot: pointer to the vtable slot
1615 * @method: the inflated generic virtual method
1616 * @code: the method's code
1618 * Registers a call via unmanaged code to a generic virtual method
1619 * instantiation or variant interface method. If the number of calls reaches a threshold
1620 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1621 * virtual method trampoline.
1624 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1625 gpointer *vtable_slot,
1626 MonoMethod *method, gpointer code)
1628 MONO_REQ_GC_NEUTRAL_MODE;
1630 static gboolean inited = FALSE;
1631 static int num_added = 0;
1632 static int num_freed = 0;
1634 GenericVirtualCase *gvc, *list;
1635 MonoImtBuilderEntry *entries;
1639 mono_domain_lock (domain);
1640 if (!domain->generic_virtual_cases)
1641 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1644 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1645 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1649 /* Check whether the case was already added */
1650 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1653 if (gvc->method == method)
1658 /* If not found, make a new one */
1660 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1661 gvc->method = method;
1664 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1666 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1671 if (++gvc->count == THUNK_THRESHOLD) {
1672 gpointer *old_thunk = (void **)*vtable_slot;
1673 gpointer vtable_trampoline = NULL;
1674 gpointer imt_trampoline = NULL;
1676 if ((gpointer)vtable_slot < (gpointer)vtable) {
1677 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1678 int imt_slot = MONO_IMT_SIZE + displacement;
1680 /* Force the rebuild of the trampoline at the next call */
1681 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1682 *vtable_slot = imt_trampoline;
1684 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1686 entries = get_generic_virtual_entries (domain, vtable_slot);
1688 sorted = imt_sort_slot_entries (entries);
1690 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1694 MonoImtBuilderEntry *next = entries->next;
1699 for (i = 0; i < sorted->len; ++i)
1700 g_free (g_ptr_array_index (sorted, i));
1701 g_ptr_array_free (sorted, TRUE);
1703 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1708 mono_domain_unlock (domain);
1711 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1714 * mono_class_vtable:
1715 * @domain: the application domain
1716 * @class: the class to initialize
1718 * VTables are domain specific because we create domain specific code, and
1719 * they contain the domain specific static class data.
1720 * On failure, NULL is returned, and class->exception_type is set.
1723 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1726 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1727 mono_error_cleanup (&error);
1732 * mono_class_vtable_full:
1733 * @domain: the application domain
1734 * @class: the class to initialize
1735 * @error set on failure.
1737 * VTables are domain specific because we create domain specific code, and
1738 * they contain the domain specific static class data.
1741 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1743 MONO_REQ_GC_UNSAFE_MODE;
1745 MonoClassRuntimeInfo *runtime_info;
1747 mono_error_init (error);
1751 if (mono_class_has_failure (klass)) {
1752 mono_error_set_for_class_failure (error, klass);
1756 /* this check can be inlined in jitted code, too */
1757 runtime_info = klass->runtime_info;
1758 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1759 return runtime_info->domain_vtables [domain->domain_id];
1760 return mono_class_create_runtime_vtable (domain, klass, error);
1764 * mono_class_try_get_vtable:
1765 * @domain: the application domain
1766 * @class: the class to initialize
1768 * This function tries to get the associated vtable from @class if
1769 * it was already created.
1772 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1774 MONO_REQ_GC_NEUTRAL_MODE;
1776 MonoClassRuntimeInfo *runtime_info;
1780 runtime_info = klass->runtime_info;
1781 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1782 return runtime_info->domain_vtables [domain->domain_id];
1787 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1789 MONO_REQ_GC_NEUTRAL_MODE;
1791 size_t alloc_offset;
1794 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1795 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1796 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1798 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1799 g_assert ((imt_table_bytes & 7) == 4);
1806 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1810 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1812 MONO_REQ_GC_UNSAFE_MODE;
1815 MonoClassRuntimeInfo *runtime_info, *old_info;
1816 MonoClassField *field;
1818 int i, vtable_slots;
1819 size_t imt_table_bytes;
1821 guint32 vtable_size, class_size;
1823 gpointer *interface_offsets;
1825 mono_error_init (error);
1827 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1828 mono_domain_lock (domain);
1829 runtime_info = klass->runtime_info;
1830 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1831 mono_domain_unlock (domain);
1832 mono_loader_unlock ();
1833 return runtime_info->domain_vtables [domain->domain_id];
1835 if (!klass->inited || mono_class_has_failure (klass)) {
1836 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1837 mono_domain_unlock (domain);
1838 mono_loader_unlock ();
1839 mono_error_set_for_class_failure (error, klass);
1844 /* Array types require that their element type be valid*/
1845 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1846 MonoClass *element_class = klass->element_class;
1847 if (!element_class->inited)
1848 mono_class_init (element_class);
1850 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1851 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1852 mono_class_setup_vtable (element_class);
1854 if (mono_class_has_failure (element_class)) {
1855 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1856 if (!mono_class_has_failure (klass))
1857 mono_class_set_type_load_failure (klass, "");
1858 mono_domain_unlock (domain);
1859 mono_loader_unlock ();
1860 mono_error_set_for_class_failure (error, klass);
1866 * For some classes, mono_class_init () already computed klass->vtable_size, and
1867 * that is all that is needed because of the vtable trampolines.
1869 if (!klass->vtable_size)
1870 mono_class_setup_vtable (klass);
1872 if (mono_class_is_ginst (klass) && !klass->vtable)
1873 mono_class_check_vtable_constraints (klass, NULL);
1875 /* Initialize klass->has_finalize */
1876 mono_class_has_finalizer (klass);
1878 if (mono_class_has_failure (klass)) {
1879 mono_domain_unlock (domain);
1880 mono_loader_unlock ();
1881 mono_error_set_for_class_failure (error, klass);
1885 vtable_slots = klass->vtable_size;
1886 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1887 class_size = mono_class_data_size (klass);
1891 if (klass->interface_offsets_count) {
1892 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1893 mono_stats.imt_number_of_tables++;
1894 mono_stats.imt_tables_size += imt_table_bytes;
1896 imt_table_bytes = 0;
1899 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1901 mono_stats.used_class_count++;
1902 mono_stats.class_vtable_size += vtable_size;
1904 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1905 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1906 g_assert (!((gsize)vt & 7));
1909 vt->rank = klass->rank;
1910 vt->domain = domain;
1912 mono_class_compute_gc_descriptor (klass);
1914 * We can't use typed allocation in the non-root domains, since the
1915 * collector needs the GC descriptor stored in the vtable even after
1916 * the mempool containing the vtable is destroyed when the domain is
1917 * unloaded. An alternative might be to allocate vtables in the GC
1918 * heap, but this does not seem to work (it leads to crashes inside
1919 * libgc). If that approach is tried, two gc descriptors need to be
1920 * allocated for each class: one for the root domain, and one for all
1921 * other domains. The second descriptor should contain a bit for the
1922 * vtable field in MonoObject, since we can no longer assume the
1923 * vtable is reachable by other roots after the appdomain is unloaded.
1925 #ifdef HAVE_BOEHM_GC
1926 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1927 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1930 vt->gc_descr = klass->gc_descr;
1932 gc_bits = mono_gc_get_vtable_bits (klass);
1933 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1935 vt->gc_bits = gc_bits;
1938 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1939 if (klass->has_static_refs) {
1940 MonoGCDescriptor statics_gc_descr;
1942 gsize default_bitmap [4] = {0};
1945 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1946 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1947 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1948 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1949 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1950 if (bitmap != default_bitmap)
1953 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1955 vt->has_static_fields = TRUE;
1956 mono_stats.class_static_data_size += class_size;
1960 while ((field = mono_class_get_fields (klass, &iter))) {
1961 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1963 if (mono_field_is_deleted (field))
1965 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1966 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1967 if (special_static != SPECIAL_STATIC_NONE) {
1968 guint32 size, offset;
1970 gsize default_bitmap [4] = {0};
1975 if (mono_type_is_reference (field->type)) {
1976 default_bitmap [0] = 1;
1978 bitmap = default_bitmap;
1979 } else if (mono_type_is_struct (field->type)) {
1980 fclass = mono_class_from_mono_type (field->type);
1981 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1982 numbits = max_set + 1;
1984 default_bitmap [0] = 0;
1986 bitmap = default_bitmap;
1988 size = mono_type_size (field->type, &align);
1989 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1990 if (!domain->special_static_fields)
1991 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1992 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1993 if (bitmap != default_bitmap)
1996 * This marks the field as special static to speed up the
1997 * checks in mono_field_static_get/set_value ().
2003 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2004 MonoClass *fklass = mono_class_from_mono_type (field->type);
2005 const char *data = mono_field_get_data (field);
2007 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2008 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2009 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2012 if (fklass->valuetype) {
2013 memcpy (t, data, mono_class_value_size (fklass, NULL));
2015 /* it's a pointer type: add check */
2016 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2023 vt->max_interface_id = klass->max_interface_id;
2024 vt->interface_bitmap = klass->interface_bitmap;
2026 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2027 // class->name, klass->interface_offsets_count);
2029 /* Initialize vtable */
2030 if (callbacks.get_vtable_trampoline) {
2031 // This also covers the AOT case
2032 for (i = 0; i < klass->vtable_size; ++i) {
2033 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2036 mono_class_setup_vtable (klass);
2038 for (i = 0; i < klass->vtable_size; ++i) {
2041 cm = klass->vtable [i];
2043 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2044 if (!is_ok (error)) {
2045 mono_domain_unlock (domain);
2046 mono_loader_unlock ();
2053 if (imt_table_bytes) {
2054 /* Now that the vtable is full, we can actually fill up the IMT */
2055 for (i = 0; i < MONO_IMT_SIZE; ++i)
2056 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2060 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2061 * re-acquire them and check if another thread has created the vtable in the meantime.
2063 /* Special case System.MonoType to avoid infinite recursion */
2064 if (klass != mono_defaults.runtimetype_class) {
2065 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2066 if (!is_ok (error)) {
2067 mono_domain_unlock (domain);
2068 mono_loader_unlock ();
2072 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2073 /* This is unregistered in
2074 unregister_vtable_reflection_type() in
2076 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2079 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2081 /* class_vtable_array keeps an array of created vtables
2083 g_ptr_array_add (domain->class_vtable_array, vt);
2084 /* klass->runtime_info is protected by the loader lock, both when
2085 * it it enlarged and when it is stored info.
2089 * Store the vtable in klass->runtime_info.
2090 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2092 mono_memory_barrier ();
2094 old_info = klass->runtime_info;
2095 if (old_info && old_info->max_domain >= domain->domain_id) {
2096 /* someone already created a large enough runtime info */
2097 old_info->domain_vtables [domain->domain_id] = vt;
2099 int new_size = domain->domain_id;
2101 new_size = MAX (new_size, old_info->max_domain);
2103 /* make the new size a power of two */
2105 while (new_size > i)
2108 /* this is a bounded memory retention issue: may want to
2109 * handle it differently when we'll have a rcu-like system.
2111 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2112 runtime_info->max_domain = new_size - 1;
2113 /* copy the stuff from the older info */
2115 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2117 runtime_info->domain_vtables [domain->domain_id] = vt;
2119 mono_memory_barrier ();
2120 klass->runtime_info = runtime_info;
2123 if (klass == mono_defaults.runtimetype_class) {
2124 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2125 if (!is_ok (error)) {
2126 mono_domain_unlock (domain);
2127 mono_loader_unlock ();
2131 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2132 /* This is unregistered in
2133 unregister_vtable_reflection_type() in
2135 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2138 mono_domain_unlock (domain);
2139 mono_loader_unlock ();
2141 /* make sure the parent is initialized */
2142 /*FIXME shouldn't this fail the current type?*/
2144 mono_class_vtable_full (domain, klass->parent, error);
2149 #ifndef DISABLE_REMOTING
2151 * mono_class_proxy_vtable:
2152 * @domain: the application domain
2153 * @remove_class: the remote class
2154 * @error: set on error
2156 * Creates a vtable for transparent proxies. It is basically
2157 * a copy of the real vtable of the class wrapped in @remote_class,
2158 * but all function pointers invoke the remoting functions, and
2159 * vtable->klass points to the transparent proxy class, and not to @class.
2161 * On failure returns NULL and sets @error
2164 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2166 MONO_REQ_GC_UNSAFE_MODE;
2168 MonoVTable *vt, *pvt;
2169 int i, j, vtsize, extra_interface_vtsize = 0;
2170 guint32 max_interface_id;
2172 GSList *extra_interfaces = NULL;
2173 MonoClass *klass = remote_class->proxy_class;
2174 gpointer *interface_offsets;
2175 uint8_t *bitmap = NULL;
2177 size_t imt_table_bytes;
2179 #ifdef COMPRESSED_INTERFACE_BITMAP
2183 mono_error_init (error);
2185 vt = mono_class_vtable (domain, klass);
2186 g_assert (vt); /*FIXME property handle failure*/
2187 max_interface_id = vt->max_interface_id;
2189 /* Calculate vtable space for extra interfaces */
2190 for (j = 0; j < remote_class->interface_count; j++) {
2191 MonoClass* iclass = remote_class->interfaces[j];
2195 /*FIXME test for interfaces with variant generic arguments*/
2196 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2197 continue; /* interface implemented by the class */
2198 if (g_slist_find (extra_interfaces, iclass))
2201 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2203 method_count = mono_class_num_methods (iclass);
2205 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2209 for (i = 0; i < ifaces->len; ++i) {
2210 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2211 /*FIXME test for interfaces with variant generic arguments*/
2212 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2213 continue; /* interface implemented by the class */
2214 if (g_slist_find (extra_interfaces, ic))
2216 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2217 method_count += mono_class_num_methods (ic);
2219 g_ptr_array_free (ifaces, TRUE);
2223 extra_interface_vtsize += method_count * sizeof (gpointer);
2224 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2227 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2228 mono_stats.imt_number_of_tables++;
2229 mono_stats.imt_tables_size += imt_table_bytes;
2231 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2233 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2235 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2236 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2237 g_assert (!((gsize)pvt & 7));
2239 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2241 pvt->klass = mono_defaults.transparent_proxy_class;
2242 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2243 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2245 /* initialize vtable */
2246 mono_class_setup_vtable (klass);
2247 for (i = 0; i < klass->vtable_size; ++i) {
2250 if ((cm = klass->vtable [i])) {
2251 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2255 pvt->vtable [i] = NULL;
2258 if (mono_class_is_abstract (klass)) {
2259 /* create trampolines for abstract methods */
2260 for (k = klass; k; k = k->parent) {
2262 gpointer iter = NULL;
2263 while ((m = mono_class_get_methods (k, &iter)))
2264 if (!pvt->vtable [m->slot]) {
2265 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2272 pvt->max_interface_id = max_interface_id;
2273 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2274 #ifdef COMPRESSED_INTERFACE_BITMAP
2275 bitmap = (uint8_t *)g_malloc0 (bsize);
2277 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2280 for (i = 0; i < klass->interface_offsets_count; ++i) {
2281 int interface_id = klass->interfaces_packed [i]->interface_id;
2282 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2285 if (extra_interfaces) {
2286 int slot = klass->vtable_size;
2292 /* Create trampolines for the methods of the interfaces */
2293 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2294 interf = (MonoClass *)list_item->data;
2296 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2300 while ((cm = mono_class_get_methods (interf, &iter))) {
2301 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2306 slot += mono_class_num_methods (interf);
2310 /* Now that the vtable is full, we can actually fill up the IMT */
2311 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2312 if (extra_interfaces) {
2313 g_slist_free (extra_interfaces);
2316 #ifdef COMPRESSED_INTERFACE_BITMAP
2317 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2318 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2319 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2322 pvt->interface_bitmap = bitmap;
2326 if (extra_interfaces)
2327 g_slist_free (extra_interfaces);
2328 #ifdef COMPRESSED_INTERFACE_BITMAP
2334 #endif /* DISABLE_REMOTING */
2337 * mono_class_field_is_special_static:
2339 * Returns whether @field is a thread/context static field.
2342 mono_class_field_is_special_static (MonoClassField *field)
2344 MONO_REQ_GC_NEUTRAL_MODE
2346 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2348 if (mono_field_is_deleted (field))
2350 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2351 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2358 * mono_class_field_get_special_static_type:
2359 * @field: The MonoClassField describing the field.
2361 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2362 * SPECIAL_STATIC_NONE otherwise.
2365 mono_class_field_get_special_static_type (MonoClassField *field)
2367 MONO_REQ_GC_NEUTRAL_MODE
2369 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2370 return SPECIAL_STATIC_NONE;
2371 if (mono_field_is_deleted (field))
2372 return SPECIAL_STATIC_NONE;
2373 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2374 return field_is_special_static (field->parent, field);
2375 return SPECIAL_STATIC_NONE;
2379 * mono_class_has_special_static_fields:
2381 * Returns whenever @klass has any thread/context static fields.
2384 mono_class_has_special_static_fields (MonoClass *klass)
2386 MONO_REQ_GC_NEUTRAL_MODE
2388 MonoClassField *field;
2392 while ((field = mono_class_get_fields (klass, &iter))) {
2393 g_assert (field->parent == klass);
2394 if (mono_class_field_is_special_static (field))
2401 #ifndef DISABLE_REMOTING
2403 * create_remote_class_key:
2404 * Creates an array of pointers that can be used as a hash key for a remote class.
2405 * The first element of the array is the number of pointers.
2408 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2410 MONO_REQ_GC_NEUTRAL_MODE;
2415 if (remote_class == NULL) {
2416 if (mono_class_is_interface (extra_class)) {
2417 key = (void **)g_malloc (sizeof(gpointer) * 3);
2418 key [0] = GINT_TO_POINTER (2);
2419 key [1] = mono_defaults.marshalbyrefobject_class;
2420 key [2] = extra_class;
2422 key = (void **)g_malloc (sizeof(gpointer) * 2);
2423 key [0] = GINT_TO_POINTER (1);
2424 key [1] = extra_class;
2427 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2428 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2429 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2430 key [1] = remote_class->proxy_class;
2432 // Keep the list of interfaces sorted
2433 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2434 if (extra_class && remote_class->interfaces [i] > extra_class) {
2435 key [j++] = extra_class;
2438 key [j] = remote_class->interfaces [i];
2441 key [j] = extra_class;
2443 // Replace the old class. The interface list is the same
2444 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2445 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2446 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2447 for (i = 0; i < remote_class->interface_count; i++)
2448 key [2 + i] = remote_class->interfaces [i];
2456 * copy_remote_class_key:
2458 * Make a copy of KEY in the domain and return the copy.
2461 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2463 MONO_REQ_GC_NEUTRAL_MODE
2465 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2466 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2468 memcpy (mp_key, key, key_size);
2474 * mono_remote_class:
2475 * @domain: the application domain
2476 * @class_name: name of the remote class
2477 * @error: set on error
2479 * Creates and initializes a MonoRemoteClass object for a remote type.
2481 * On failure returns NULL and sets @error
2484 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2486 MONO_REQ_GC_UNSAFE_MODE;
2488 MonoRemoteClass *rc;
2489 gpointer* key, *mp_key;
2492 mono_error_init (error);
2494 key = create_remote_class_key (NULL, proxy_class);
2496 mono_domain_lock (domain);
2497 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2501 mono_domain_unlock (domain);
2505 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2506 if (!is_ok (error)) {
2508 mono_domain_unlock (domain);
2512 mp_key = copy_remote_class_key (domain, key);
2516 if (mono_class_is_interface (proxy_class)) {
2517 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2518 rc->interface_count = 1;
2519 rc->interfaces [0] = proxy_class;
2520 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2522 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2523 rc->interface_count = 0;
2524 rc->proxy_class = proxy_class;
2527 rc->default_vtable = NULL;
2528 rc->xdomain_vtable = NULL;
2529 rc->proxy_class_name = name;
2530 #ifndef DISABLE_PERFCOUNTERS
2531 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2534 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2536 mono_domain_unlock (domain);
2541 * clone_remote_class:
2542 * Creates a copy of the remote_class, adding the provided class or interface
2544 static MonoRemoteClass*
2545 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2547 MONO_REQ_GC_NEUTRAL_MODE;
2549 MonoRemoteClass *rc;
2550 gpointer* key, *mp_key;
2552 key = create_remote_class_key (remote_class, extra_class);
2553 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2559 mp_key = copy_remote_class_key (domain, key);
2563 if (mono_class_is_interface (extra_class)) {
2565 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2566 rc->proxy_class = remote_class->proxy_class;
2567 rc->interface_count = remote_class->interface_count + 1;
2569 // Keep the list of interfaces sorted, since the hash key of
2570 // the remote class depends on this
2571 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2572 if (remote_class->interfaces [i] > extra_class && i == j)
2573 rc->interfaces [j++] = extra_class;
2574 rc->interfaces [j] = remote_class->interfaces [i];
2577 rc->interfaces [j] = extra_class;
2579 // Replace the old class. The interface array is the same
2580 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2581 rc->proxy_class = extra_class;
2582 rc->interface_count = remote_class->interface_count;
2583 if (rc->interface_count > 0)
2584 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2587 rc->default_vtable = NULL;
2588 rc->xdomain_vtable = NULL;
2589 rc->proxy_class_name = remote_class->proxy_class_name;
2591 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2597 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2599 MONO_REQ_GC_UNSAFE_MODE;
2601 mono_error_init (error);
2603 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2604 mono_domain_lock (domain);
2605 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2606 if (target_domain_id != -1) {
2607 if (remote_class->xdomain_vtable == NULL)
2608 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2609 mono_domain_unlock (domain);
2610 mono_loader_unlock ();
2611 return_val_if_nok (error, NULL);
2612 return remote_class->xdomain_vtable;
2614 if (remote_class->default_vtable == NULL) {
2615 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2616 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2618 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2619 MonoClass *klass = mono_class_from_mono_type (type);
2621 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)))
2622 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2625 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2626 /* N.B. both branches of the if modify error */
2627 if (!is_ok (error)) {
2628 mono_domain_unlock (domain);
2629 mono_loader_unlock ();
2634 mono_domain_unlock (domain);
2635 mono_loader_unlock ();
2636 return remote_class->default_vtable;
2640 * mono_upgrade_remote_class:
2641 * @domain: the application domain
2642 * @tproxy: the proxy whose remote class has to be upgraded.
2643 * @klass: class to which the remote class can be casted.
2644 * @error: set on error
2646 * Updates the vtable of the remote class by adding the necessary method slots
2647 * and interface offsets so it can be safely casted to klass. klass can be a
2648 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2651 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2653 MONO_REQ_GC_UNSAFE_MODE;
2655 mono_error_init (error);
2657 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2658 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2660 gboolean redo_vtable;
2661 if (mono_class_is_interface (klass)) {
2664 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2665 if (remote_class->interfaces [i] == klass)
2666 redo_vtable = FALSE;
2669 redo_vtable = (remote_class->proxy_class != klass);
2672 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2673 mono_domain_lock (domain);
2675 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2676 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2677 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2678 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2679 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2685 mono_domain_unlock (domain);
2686 mono_loader_unlock ();
2687 return is_ok (error);
2689 #endif /* DISABLE_REMOTING */
2693 * mono_object_get_virtual_method:
2694 * @obj: object to operate on.
2697 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2698 * the instance of a callvirt of method.
2701 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2703 MONO_REQ_GC_UNSAFE_MODE;
2704 HANDLE_FUNCTION_ENTER ();
2706 MONO_HANDLE_DCL (MonoObject, obj);
2707 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2708 mono_error_assert_ok (&error);
2709 HANDLE_FUNCTION_RETURN_VAL (result);
2713 * mono_object_get_virtual_method:
2714 * @obj: object to operate on.
2717 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2718 * the instance of a callvirt of method.
2721 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2723 mono_error_init (error);
2725 gboolean is_proxy = FALSE;
2726 MonoClass *klass = mono_handle_class (obj);
2727 if (mono_class_is_transparent_proxy (klass)) {
2728 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2729 klass = remote_class->proxy_class;
2732 return class_get_virtual_method (klass, method, is_proxy, error);
2736 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2738 mono_error_init (error);
2741 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2744 mono_class_setup_vtable (klass);
2745 MonoMethod **vtable = klass->vtable;
2747 if (method->slot == -1) {
2748 /* method->slot might not be set for instances of generic methods */
2749 if (method->is_inflated) {
2750 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2751 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2754 g_assert_not_reached ();
2758 MonoMethod *res = NULL;
2759 /* check method->slot is a valid index: perform isinstance? */
2760 if (method->slot != -1) {
2761 if (mono_class_is_interface (method->klass)) {
2763 gboolean variance_used = FALSE;
2764 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2765 g_assert (iface_offset > 0);
2766 res = vtable [iface_offset + method->slot];
2769 res = vtable [method->slot];
2773 #ifndef DISABLE_REMOTING
2775 /* It may be an interface, abstract class method or generic method */
2776 if (!res || mono_method_signature (res)->generic_param_count)
2779 /* generic methods demand invoke_with_check */
2780 if (mono_method_signature (res)->generic_param_count)
2781 res = mono_marshal_get_remoting_invoke_with_check (res);
2784 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2785 res = mono_cominterop_get_invoke (res);
2788 res = mono_marshal_get_remoting_invoke (res);
2793 if (method->is_inflated) {
2794 /* Have to inflate the result */
2795 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2803 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2805 MONO_REQ_GC_UNSAFE_MODE;
2807 MonoObject *result = NULL;
2809 g_assert (callbacks.runtime_invoke);
2811 mono_error_init (error);
2813 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2814 mono_profiler_method_start_invoke (method);
2816 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2818 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2819 mono_profiler_method_end_invoke (method);
2821 if (!mono_error_ok (error))
2828 * mono_runtime_invoke:
2829 * @method: method to invoke
2830 * @obJ: object instance
2831 * @params: arguments to the method
2832 * @exc: exception information.
2834 * Invokes the method represented by @method on the object @obj.
2836 * obj is the 'this' pointer, it should be NULL for static
2837 * methods, a MonoObject* for object instances and a pointer to
2838 * the value type for value types.
2840 * The params array contains the arguments to the method with the
2841 * same convention: MonoObject* pointers for object instances and
2842 * pointers to the value type otherwise.
2844 * From unmanaged code you'll usually use the
2845 * mono_runtime_invoke() variant.
2847 * Note that this function doesn't handle virtual methods for
2848 * you, it will exec the exact method you pass: we still need to
2849 * expose a function to lookup the derived class implementation
2850 * of a virtual method (there are examples of this in the code,
2853 * You can pass NULL as the exc argument if you don't want to
2854 * catch exceptions, otherwise, *exc will be set to the exception
2855 * thrown, if any. if an exception is thrown, you can't use the
2856 * MonoObject* result from the function.
2858 * If the method returns a value type, it is boxed in an object
2862 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2867 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2868 if (*exc == NULL && !mono_error_ok(&error)) {
2869 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2871 mono_error_cleanup (&error);
2873 res = mono_runtime_invoke_checked (method, obj, params, &error);
2874 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2880 * mono_runtime_try_invoke:
2881 * @method: method to invoke
2882 * @obJ: object instance
2883 * @params: arguments to the method
2884 * @exc: exception information.
2885 * @error: set on error
2887 * Invokes the method represented by @method on the object @obj.
2889 * obj is the 'this' pointer, it should be NULL for static
2890 * methods, a MonoObject* for object instances and a pointer to
2891 * the value type for value types.
2893 * The params array contains the arguments to the method with the
2894 * same convention: MonoObject* pointers for object instances and
2895 * pointers to the value type otherwise.
2897 * From unmanaged code you'll usually use the
2898 * mono_runtime_invoke() variant.
2900 * Note that this function doesn't handle virtual methods for
2901 * you, it will exec the exact method you pass: we still need to
2902 * expose a function to lookup the derived class implementation
2903 * of a virtual method (there are examples of this in the code,
2906 * For this function, you must not pass NULL as the exc argument if
2907 * you don't want to catch exceptions, use
2908 * mono_runtime_invoke_checked(). If an exception is thrown, you
2909 * can't use the MonoObject* result from the function.
2911 * If this method cannot be invoked, @error will be set and @exc and
2912 * the return value must not be used.
2914 * If the method returns a value type, it is boxed in an object
2918 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2920 MONO_REQ_GC_UNSAFE_MODE;
2922 g_assert (exc != NULL);
2924 if (mono_runtime_get_no_exec ())
2925 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2927 return do_runtime_invoke (method, obj, params, exc, error);
2931 * mono_runtime_invoke_checked:
2932 * @method: method to invoke
2933 * @obJ: object instance
2934 * @params: arguments to the method
2935 * @error: set on error
2937 * Invokes the method represented by @method on the object @obj.
2939 * obj is the 'this' pointer, it should be NULL for static
2940 * methods, a MonoObject* for object instances and a pointer to
2941 * the value type for value types.
2943 * The params array contains the arguments to the method with the
2944 * same convention: MonoObject* pointers for object instances and
2945 * pointers to the value type otherwise.
2947 * From unmanaged code you'll usually use the
2948 * mono_runtime_invoke() variant.
2950 * Note that this function doesn't handle virtual methods for
2951 * you, it will exec the exact method you pass: we still need to
2952 * expose a function to lookup the derived class implementation
2953 * of a virtual method (there are examples of this in the code,
2956 * If an exception is thrown, you can't use the MonoObject* result
2957 * from the function.
2959 * If this method cannot be invoked, @error will be set. If the
2960 * method throws an exception (and we're in coop mode) the exception
2961 * will be set in @error.
2963 * If the method returns a value type, it is boxed in an object
2967 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2969 MONO_REQ_GC_UNSAFE_MODE;
2971 if (mono_runtime_get_no_exec ())
2972 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2974 return do_runtime_invoke (method, obj, params, NULL, error);
2978 * mono_method_get_unmanaged_thunk:
2979 * @method: method to generate a thunk for.
2981 * Returns an unmanaged->managed thunk that can be used to call
2982 * a managed method directly from C.
2984 * The thunk's C signature closely matches the managed signature:
2986 * C#: public bool Equals (object obj);
2987 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2988 * MonoObject*, MonoException**);
2990 * The 1st ("this") parameter must not be used with static methods:
2992 * C#: public static bool ReferenceEquals (object a, object b);
2993 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2996 * The last argument must be a non-null pointer of a MonoException* pointer.
2997 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2998 * exception has been thrown in managed code. Otherwise it will point
2999 * to the MonoException* caught by the thunk. In this case, the result of
3000 * the thunk is undefined:
3002 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3003 * MonoException *ex = NULL;
3004 * Equals func = mono_method_get_unmanaged_thunk (method);
3005 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3007 * // handle exception
3010 * The calling convention of the thunk matches the platform's default
3011 * convention. This means that under Windows, C declarations must
3012 * contain the __stdcall attribute:
3014 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3015 * MonoObject*, MonoException**);
3019 * Value type arguments and return values are treated as they were objects:
3021 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3022 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3024 * Arguments must be properly boxed upon trunk's invocation, while return
3025 * values must be unboxed.
3028 mono_method_get_unmanaged_thunk (MonoMethod *method)
3030 MONO_REQ_GC_NEUTRAL_MODE;
3031 MONO_REQ_API_ENTRYPOINT;
3036 g_assert (!mono_threads_is_coop_enabled ());
3038 MONO_ENTER_GC_UNSAFE;
3039 method = mono_marshal_get_thunk_invoke_wrapper (method);
3040 res = mono_compile_method_checked (method, &error);
3041 mono_error_cleanup (&error);
3042 MONO_EXIT_GC_UNSAFE;
3048 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3050 MONO_REQ_GC_UNSAFE_MODE;
3054 /* object fields cannot be byref, so we don't need a
3056 gpointer *p = (gpointer*)dest;
3063 case MONO_TYPE_BOOLEAN:
3065 case MONO_TYPE_U1: {
3066 guint8 *p = (guint8*)dest;
3067 *p = value ? *(guint8*)value : 0;
3072 case MONO_TYPE_CHAR: {
3073 guint16 *p = (guint16*)dest;
3074 *p = value ? *(guint16*)value : 0;
3077 #if SIZEOF_VOID_P == 4
3082 case MONO_TYPE_U4: {
3083 gint32 *p = (gint32*)dest;
3084 *p = value ? *(gint32*)value : 0;
3087 #if SIZEOF_VOID_P == 8
3092 case MONO_TYPE_U8: {
3093 gint64 *p = (gint64*)dest;
3094 *p = value ? *(gint64*)value : 0;
3097 case MONO_TYPE_R4: {
3098 float *p = (float*)dest;
3099 *p = value ? *(float*)value : 0;
3102 case MONO_TYPE_R8: {
3103 double *p = (double*)dest;
3104 *p = value ? *(double*)value : 0;
3107 case MONO_TYPE_STRING:
3108 case MONO_TYPE_SZARRAY:
3109 case MONO_TYPE_CLASS:
3110 case MONO_TYPE_OBJECT:
3111 case MONO_TYPE_ARRAY:
3112 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3114 case MONO_TYPE_FNPTR:
3115 case MONO_TYPE_PTR: {
3116 gpointer *p = (gpointer*)dest;
3117 *p = deref_pointer? *(gpointer*)value: value;
3120 case MONO_TYPE_VALUETYPE:
3121 /* note that 't' and 'type->type' can be different */
3122 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3123 t = mono_class_enum_basetype (type->data.klass)->type;
3126 MonoClass *klass = mono_class_from_mono_type (type);
3127 int size = mono_class_value_size (klass, NULL);
3129 mono_gc_bzero_atomic (dest, size);
3131 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3134 case MONO_TYPE_GENERICINST:
3135 t = type->data.generic_class->container_class->byval_arg.type;
3138 g_error ("got type %x", type->type);
3143 * mono_field_set_value:
3144 * @obj: Instance object
3145 * @field: MonoClassField describing the field to set
3146 * @value: The value to be set
3148 * Sets the value of the field described by @field in the object instance @obj
3149 * to the value passed in @value. This method should only be used for instance
3150 * fields. For static fields, use mono_field_static_set_value.
3152 * The value must be on the native format of the field type.
3155 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3157 MONO_REQ_GC_UNSAFE_MODE;
3161 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3163 dest = (char*)obj + field->offset;
3164 mono_copy_value (field->type, dest, value, FALSE);
3168 * mono_field_static_set_value:
3169 * @field: MonoClassField describing the field to set
3170 * @value: The value to be set
3172 * Sets the value of the static field described by @field
3173 * to the value passed in @value.
3175 * The value must be on the native format of the field type.
3178 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3180 MONO_REQ_GC_UNSAFE_MODE;
3184 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3185 /* you cant set a constant! */
3186 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3188 if (field->offset == -1) {
3189 /* Special static */
3192 mono_domain_lock (vt->domain);
3193 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3194 mono_domain_unlock (vt->domain);
3195 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3197 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3199 mono_copy_value (field->type, dest, value, FALSE);
3203 * mono_vtable_get_static_field_data:
3205 * Internal use function: return a pointer to the memory holding the static fields
3206 * for a class or NULL if there are no static fields.
3207 * This is exported only for use by the debugger.
3210 mono_vtable_get_static_field_data (MonoVTable *vt)
3212 MONO_REQ_GC_NEUTRAL_MODE
3214 if (!vt->has_static_fields)
3216 return vt->vtable [vt->klass->vtable_size];
3220 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3222 MONO_REQ_GC_UNSAFE_MODE;
3226 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3227 if (field->offset == -1) {
3228 /* Special static */
3231 mono_domain_lock (vt->domain);
3232 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3233 mono_domain_unlock (vt->domain);
3234 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3236 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3239 src = (guint8*)obj + field->offset;
3246 * mono_field_get_value:
3247 * @obj: Object instance
3248 * @field: MonoClassField describing the field to fetch information from
3249 * @value: pointer to the location where the value will be stored
3251 * Use this routine to get the value of the field @field in the object
3254 * The pointer provided by value must be of the field type, for reference
3255 * types this is a MonoObject*, for value types its the actual pointer to
3260 * mono_field_get_value (obj, int_field, &i);
3263 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3265 MONO_REQ_GC_UNSAFE_MODE;
3271 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3273 src = (char*)obj + field->offset;
3274 mono_copy_value (field->type, value, src, TRUE);
3278 * mono_field_get_value_object:
3279 * @domain: domain where the object will be created (if boxing)
3280 * @field: MonoClassField describing the field to fetch information from
3281 * @obj: The object instance for the field.
3283 * Returns: a new MonoObject with the value from the given field. If the
3284 * field represents a value type, the value is boxed.
3288 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3291 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3292 mono_error_assert_ok (&error);
3297 * mono_field_get_value_object_checked:
3298 * @domain: domain where the object will be created (if boxing)
3299 * @field: MonoClassField describing the field to fetch information from
3300 * @obj: The object instance for the field.
3301 * @error: Set on error.
3303 * Returns: a new MonoObject with the value from the given field. If the
3304 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3308 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3310 MONO_REQ_GC_UNSAFE_MODE;
3312 mono_error_init (error);
3316 MonoVTable *vtable = NULL;
3318 gboolean is_static = FALSE;
3319 gboolean is_ref = FALSE;
3320 gboolean is_literal = FALSE;
3321 gboolean is_ptr = FALSE;
3322 MonoType *type = mono_field_get_type_checked (field, error);
3324 return_val_if_nok (error, NULL);
3326 switch (type->type) {
3327 case MONO_TYPE_STRING:
3328 case MONO_TYPE_OBJECT:
3329 case MONO_TYPE_CLASS:
3330 case MONO_TYPE_ARRAY:
3331 case MONO_TYPE_SZARRAY:
3336 case MONO_TYPE_BOOLEAN:
3339 case MONO_TYPE_CHAR:
3348 case MONO_TYPE_VALUETYPE:
3349 is_ref = type->byref;
3351 case MONO_TYPE_GENERICINST:
3352 is_ref = !mono_type_generic_inst_is_valuetype (type);
3358 g_error ("type 0x%x not handled in "
3359 "mono_field_get_value_object", type->type);
3363 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3366 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3370 vtable = mono_class_vtable_full (domain, field->parent, error);
3371 return_val_if_nok (error, NULL);
3373 if (!vtable->initialized) {
3374 mono_runtime_class_init_full (vtable, error);
3375 return_val_if_nok (error, NULL);
3384 get_default_field_value (domain, field, &o, error);
3385 return_val_if_nok (error, NULL);
3386 } else if (is_static) {
3387 mono_field_static_get_value_checked (vtable, field, &o, error);
3388 return_val_if_nok (error, NULL);
3390 mono_field_get_value (obj, field, &o);
3396 static MonoMethod *m;
3402 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3403 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3409 get_default_field_value (domain, field, v, error);
3410 return_val_if_nok (error, NULL);
3411 } else if (is_static) {
3412 mono_field_static_get_value_checked (vtable, field, v, error);
3413 return_val_if_nok (error, NULL);
3415 mono_field_get_value (obj, field, v);
3418 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3419 args [0] = ptr ? *ptr : NULL;
3420 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3421 return_val_if_nok (error, NULL);
3423 o = mono_runtime_invoke_checked (m, NULL, args, error);
3424 return_val_if_nok (error, NULL);
3429 /* boxed value type */
3430 klass = mono_class_from_mono_type (type);
3432 if (mono_class_is_nullable (klass))
3433 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3435 o = mono_object_new_checked (domain, klass, error);
3436 return_val_if_nok (error, NULL);
3437 v = ((gchar *) o) + sizeof (MonoObject);
3440 get_default_field_value (domain, field, v, error);
3441 return_val_if_nok (error, NULL);
3442 } else if (is_static) {
3443 mono_field_static_get_value_checked (vtable, field, v, error);
3444 return_val_if_nok (error, NULL);
3446 mono_field_get_value (obj, field, v);
3453 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3455 MONO_REQ_GC_UNSAFE_MODE;
3457 mono_error_init (error);
3459 const char *p = blob;
3460 mono_metadata_decode_blob_size (p, &p);
3463 case MONO_TYPE_BOOLEAN:
3466 *(guint8 *) value = *p;
3468 case MONO_TYPE_CHAR:
3471 *(guint16*) value = read16 (p);
3475 *(guint32*) value = read32 (p);
3479 *(guint64*) value = read64 (p);
3482 readr4 (p, (float*) value);
3485 readr8 (p, (double*) value);
3487 case MONO_TYPE_STRING:
3488 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3490 case MONO_TYPE_CLASS:
3491 *(gpointer*) value = NULL;
3495 g_warning ("type 0x%02x should not be in constant table", type);
3501 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3503 MONO_REQ_GC_NEUTRAL_MODE;
3505 MonoTypeEnum def_type;
3508 mono_error_init (error);
3510 data = mono_class_get_field_default_value (field, &def_type);
3511 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3515 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3517 MONO_REQ_GC_UNSAFE_MODE;
3521 mono_error_init (error);
3523 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3525 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3526 get_default_field_value (vt->domain, field, value, error);
3530 if (field->offset == -1) {
3531 /* Special static */
3532 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3533 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3535 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3537 mono_copy_value (field->type, value, src, TRUE);
3541 * mono_field_static_get_value:
3542 * @vt: vtable to the object
3543 * @field: MonoClassField describing the field to fetch information from
3544 * @value: where the value is returned
3546 * Use this routine to get the value of the static field @field value.
3548 * The pointer provided by value must be of the field type, for reference
3549 * types this is a MonoObject*, for value types its the actual pointer to
3554 * mono_field_static_get_value (vt, int_field, &i);
3557 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3559 MONO_REQ_GC_NEUTRAL_MODE;
3562 mono_field_static_get_value_checked (vt, field, value, &error);
3563 mono_error_cleanup (&error);
3567 * mono_field_static_get_value_checked:
3568 * @vt: vtable to the object
3569 * @field: MonoClassField describing the field to fetch information from
3570 * @value: where the value is returned
3571 * @error: set on error
3573 * Use this routine to get the value of the static field @field value.
3575 * The pointer provided by value must be of the field type, for reference
3576 * types this is a MonoObject*, for value types its the actual pointer to
3581 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3582 * if (!is_ok (error)) { ... }
3584 * On failure sets @error.
3587 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3589 MONO_REQ_GC_NEUTRAL_MODE;
3591 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3595 * mono_property_set_value:
3596 * @prop: MonoProperty to set
3597 * @obj: instance object on which to act
3598 * @params: parameters to pass to the propery
3599 * @exc: optional exception
3601 * Invokes the property's set method with the given arguments on the
3602 * object instance obj (or NULL for static properties).
3604 * You can pass NULL as the exc argument if you don't want to
3605 * catch exceptions, otherwise, *exc will be set to the exception
3606 * thrown, if any. if an exception is thrown, you can't use the
3607 * MonoObject* result from the function.
3610 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3612 MONO_REQ_GC_UNSAFE_MODE;
3615 do_runtime_invoke (prop->set, obj, params, exc, &error);
3616 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3617 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3619 mono_error_cleanup (&error);
3624 * mono_property_set_value_checked:
3625 * @prop: MonoProperty to set
3626 * @obj: instance object on which to act
3627 * @params: parameters to pass to the propery
3628 * @error: set on error
3630 * Invokes the property's set method with the given arguments on the
3631 * object instance obj (or NULL for static properties).
3633 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3634 * If an exception is thrown, it will be caught and returned via @error.
3637 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3639 MONO_REQ_GC_UNSAFE_MODE;
3643 mono_error_init (error);
3644 do_runtime_invoke (prop->set, obj, params, &exc, error);
3645 if (exc != NULL && is_ok (error))
3646 mono_error_set_exception_instance (error, (MonoException*)exc);
3647 return is_ok (error);
3651 * mono_property_get_value:
3652 * @prop: MonoProperty to fetch
3653 * @obj: instance object on which to act
3654 * @params: parameters to pass to the propery
3655 * @exc: optional exception
3657 * Invokes the property's get method with the given arguments on the
3658 * object instance obj (or NULL for static properties).
3660 * You can pass NULL as the exc argument if you don't want to
3661 * catch exceptions, otherwise, *exc will be set to the exception
3662 * thrown, if any. if an exception is thrown, you can't use the
3663 * MonoObject* result from the function.
3665 * Returns: the value from invoking the get method on the property.
3668 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3670 MONO_REQ_GC_UNSAFE_MODE;
3673 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3674 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3675 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3677 mono_error_cleanup (&error); /* FIXME don't raise here */
3684 * mono_property_get_value_checked:
3685 * @prop: MonoProperty to fetch
3686 * @obj: instance object on which to act
3687 * @params: parameters to pass to the propery
3688 * @error: set on error
3690 * Invokes the property's get method with the given arguments on the
3691 * object instance obj (or NULL for static properties).
3693 * If an exception is thrown, you can't use the
3694 * MonoObject* result from the function. The exception will be propagated via @error.
3696 * Returns: the value from invoking the get method on the property. On
3697 * failure returns NULL and sets @error.
3700 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3702 MONO_REQ_GC_UNSAFE_MODE;
3705 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3706 if (exc != NULL && !is_ok (error))
3707 mono_error_set_exception_instance (error, (MonoException*) exc);
3715 * mono_nullable_init:
3716 * @buf: The nullable structure to initialize.
3717 * @value: the value to initialize from
3718 * @klass: the type for the object
3720 * Initialize the nullable structure pointed to by @buf from @value which
3721 * should be a boxed value type. The size of @buf should be able to hold
3722 * as much data as the @klass->instance_size (which is the number of bytes
3723 * that will be copies).
3725 * Since Nullables have variable structure, we can not define a C
3726 * structure for them.
3729 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3731 MONO_REQ_GC_UNSAFE_MODE;
3733 MonoClass *param_class = klass->cast_class;
3735 mono_class_setup_fields (klass);
3736 g_assert (klass->fields_inited);
3738 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3739 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3741 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3743 if (param_class->has_references)
3744 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3746 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3748 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3753 * mono_nullable_box:
3754 * @buf: The buffer representing the data to be boxed
3755 * @klass: the type to box it as.
3756 * @error: set on oerr
3758 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3759 * @buf. On failure returns NULL and sets @error
3762 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3764 MONO_REQ_GC_UNSAFE_MODE;
3766 mono_error_init (error);
3767 MonoClass *param_class = klass->cast_class;
3769 mono_class_setup_fields (klass);
3770 g_assert (klass->fields_inited);
3772 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3773 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3775 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3776 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3777 return_val_if_nok (error, NULL);
3778 if (param_class->has_references)
3779 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3781 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3789 * mono_get_delegate_invoke:
3790 * @klass: The delegate class
3792 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3795 mono_get_delegate_invoke (MonoClass *klass)
3797 MONO_REQ_GC_NEUTRAL_MODE;
3801 /* This is called at runtime, so avoid the slower search in metadata */
3802 mono_class_setup_methods (klass);
3803 if (mono_class_has_failure (klass))
3805 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3810 * mono_get_delegate_begin_invoke:
3811 * @klass: The delegate class
3813 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3816 mono_get_delegate_begin_invoke (MonoClass *klass)
3818 MONO_REQ_GC_NEUTRAL_MODE;
3822 /* This is called at runtime, so avoid the slower search in metadata */
3823 mono_class_setup_methods (klass);
3824 if (mono_class_has_failure (klass))
3826 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3831 * mono_get_delegate_end_invoke:
3832 * @klass: The delegate class
3834 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3837 mono_get_delegate_end_invoke (MonoClass *klass)
3839 MONO_REQ_GC_NEUTRAL_MODE;
3843 /* This is called at runtime, so avoid the slower search in metadata */
3844 mono_class_setup_methods (klass);
3845 if (mono_class_has_failure (klass))
3847 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3852 * mono_runtime_delegate_invoke:
3853 * @delegate: pointer to a delegate object.
3854 * @params: parameters for the delegate.
3855 * @exc: Pointer to the exception result.
3857 * Invokes the delegate method @delegate with the parameters provided.
3859 * You can pass NULL as the exc argument if you don't want to
3860 * catch exceptions, otherwise, *exc will be set to the exception
3861 * thrown, if any. if an exception is thrown, you can't use the
3862 * MonoObject* result from the function.
3865 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3867 MONO_REQ_GC_UNSAFE_MODE;
3871 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3873 mono_error_cleanup (&error);
3876 if (!is_ok (&error))
3877 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3881 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3882 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3888 * mono_runtime_delegate_try_invoke:
3889 * @delegate: pointer to a delegate object.
3890 * @params: parameters for the delegate.
3891 * @exc: Pointer to the exception result.
3892 * @error: set on error
3894 * Invokes the delegate method @delegate with the parameters provided.
3896 * You can pass NULL as the exc argument if you don't want to
3897 * catch exceptions, otherwise, *exc will be set to the exception
3898 * thrown, if any. On failure to execute, @error will be set.
3899 * if an exception is thrown, you can't use the
3900 * MonoObject* result from the function.
3903 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3905 MONO_REQ_GC_UNSAFE_MODE;
3907 mono_error_init (error);
3909 MonoClass *klass = delegate->vtable->klass;
3912 im = mono_get_delegate_invoke (klass);
3914 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3917 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3919 o = mono_runtime_invoke_checked (im, delegate, params, error);
3926 * mono_runtime_delegate_invoke_checked:
3927 * @delegate: pointer to a delegate object.
3928 * @params: parameters for the delegate.
3929 * @error: set on error
3931 * Invokes the delegate method @delegate with the parameters provided.
3933 * On failure @error will be set and you can't use the MonoObject*
3934 * result from the function.
3937 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3939 mono_error_init (error);
3940 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3943 static char **main_args = NULL;
3944 static int num_main_args = 0;
3947 * mono_runtime_get_main_args:
3949 * Returns: a MonoArray with the arguments passed to the main program
3952 mono_runtime_get_main_args (void)
3954 MONO_REQ_GC_UNSAFE_MODE;
3956 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3957 mono_error_assert_ok (&error);
3962 * mono_runtime_get_main_args:
3963 * @error: set on error
3965 * Returns: a MonoArray with the arguments passed to the main
3966 * program. On failure returns NULL and sets @error.
3969 mono_runtime_get_main_args_checked (MonoError *error)
3973 MonoDomain *domain = mono_domain_get ();
3975 mono_error_init (error);
3977 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3978 return_val_if_nok (error, NULL);
3980 for (i = 0; i < num_main_args; ++i)
3981 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3987 free_main_args (void)
3989 MONO_REQ_GC_NEUTRAL_MODE;
3993 for (i = 0; i < num_main_args; ++i)
3994 g_free (main_args [i]);
4001 * mono_runtime_set_main_args:
4002 * @argc: number of arguments from the command line
4003 * @argv: array of strings from the command line
4005 * Set the command line arguments from an embedding application that doesn't otherwise call
4006 * mono_runtime_run_main ().
4009 mono_runtime_set_main_args (int argc, char* argv[])
4011 MONO_REQ_GC_NEUTRAL_MODE;
4016 main_args = g_new0 (char*, argc);
4017 num_main_args = argc;
4019 for (i = 0; i < argc; ++i) {
4022 utf8_arg = mono_utf8_from_external (argv[i]);
4023 if (utf8_arg == NULL) {
4024 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4025 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4029 main_args [i] = utf8_arg;
4036 * Prepare an array of arguments in order to execute a standard Main()
4037 * method (argc/argv contains the executable name). This method also
4038 * sets the command line argument value needed by System.Environment.
4042 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4044 MONO_REQ_GC_UNSAFE_MODE;
4048 MonoArray *args = NULL;
4049 MonoDomain *domain = mono_domain_get ();
4050 gchar *utf8_fullpath;
4051 MonoMethodSignature *sig;
4053 g_assert (method != NULL);
4055 mono_thread_set_main (mono_thread_current ());
4057 main_args = g_new0 (char*, argc);
4058 num_main_args = argc;
4060 if (!g_path_is_absolute (argv [0])) {
4061 gchar *basename = g_path_get_basename (argv [0]);
4062 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4066 utf8_fullpath = mono_utf8_from_external (fullpath);
4067 if(utf8_fullpath == NULL) {
4068 /* Printing the arg text will cause glib to
4069 * whinge about "Invalid UTF-8", but at least
4070 * its relevant, and shows the problem text
4073 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4074 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4081 utf8_fullpath = mono_utf8_from_external (argv[0]);
4082 if(utf8_fullpath == NULL) {
4083 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4084 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4089 main_args [0] = utf8_fullpath;
4091 for (i = 1; i < argc; ++i) {
4094 utf8_arg=mono_utf8_from_external (argv[i]);
4095 if(utf8_arg==NULL) {
4096 /* Ditto the comment about Invalid UTF-8 here */
4097 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4098 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4102 main_args [i] = utf8_arg;
4107 sig = mono_method_signature (method);
4109 g_print ("Unable to load Main method.\n");
4113 if (sig->param_count) {
4114 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4115 mono_error_assert_ok (&error);
4116 for (i = 0; i < argc; ++i) {
4117 /* The encodings should all work, given that
4118 * we've checked all these args for the
4121 gchar *str = mono_utf8_from_external (argv [i]);
4122 MonoString *arg = mono_string_new (domain, str);
4123 mono_array_setref (args, i, arg);
4127 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4128 mono_error_assert_ok (&error);
4131 mono_assembly_set_main (method->klass->image->assembly);
4137 * mono_runtime_run_main:
4138 * @method: the method to start the application with (usually Main)
4139 * @argc: number of arguments from the command line
4140 * @argv: array of strings from the command line
4141 * @exc: excetption results
4143 * Execute a standard Main() method (argc/argv contains the
4144 * executable name). This method also sets the command line argument value
4145 * needed by System.Environment.
4150 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4153 MONO_REQ_GC_UNSAFE_MODE;
4156 MonoArray *args = prepare_run_main (method, argc, argv);
4159 res = mono_runtime_try_exec_main (method, args, exc);
4161 res = mono_runtime_exec_main_checked (method, args, &error);
4162 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4168 * mono_runtime_run_main_checked:
4169 * @method: the method to start the application with (usually Main)
4170 * @argc: number of arguments from the command line
4171 * @argv: array of strings from the command line
4172 * @error: set on error
4174 * Execute a standard Main() method (argc/argv contains the
4175 * executable name). This method also sets the command line argument value
4176 * needed by System.Environment. On failure sets @error.
4181 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4184 mono_error_init (error);
4185 MonoArray *args = prepare_run_main (method, argc, argv);
4186 return mono_runtime_exec_main_checked (method, args, error);
4190 * mono_runtime_try_run_main:
4191 * @method: the method to start the application with (usually Main)
4192 * @argc: number of arguments from the command line
4193 * @argv: array of strings from the command line
4194 * @exc: set if Main throws an exception
4195 * @error: set if Main can't be executed
4197 * Execute a standard Main() method (argc/argv contains the executable
4198 * name). This method also sets the command line argument value needed
4199 * by System.Environment. On failure sets @error if Main can't be
4200 * executed or @exc if it threw and exception.
4205 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4209 MonoArray *args = prepare_run_main (method, argc, argv);
4210 return mono_runtime_try_exec_main (method, args, exc);
4215 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4217 static MonoMethod *serialize_method;
4223 if (!serialize_method) {
4224 MonoClass *klass = mono_class_get_remoting_services_class ();
4225 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4228 if (!serialize_method) {
4233 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4238 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4239 if (*exc == NULL && !mono_error_ok (&error))
4240 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4242 mono_error_cleanup (&error);
4251 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4253 MONO_REQ_GC_UNSAFE_MODE;
4255 static MonoMethod *deserialize_method;
4261 if (!deserialize_method) {
4262 MonoClass *klass = mono_class_get_remoting_services_class ();
4263 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4265 if (!deserialize_method) {
4273 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4274 if (*exc == NULL && !mono_error_ok (&error))
4275 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4277 mono_error_cleanup (&error);
4285 #ifndef DISABLE_REMOTING
4287 make_transparent_proxy (MonoObject *obj, MonoError *error)
4289 MONO_REQ_GC_UNSAFE_MODE;
4291 static MonoMethod *get_proxy_method;
4293 MonoDomain *domain = mono_domain_get ();
4294 MonoRealProxy *real_proxy;
4295 MonoReflectionType *reflection_type;
4296 MonoTransparentProxy *transparent_proxy;
4298 mono_error_init (error);
4300 if (!get_proxy_method)
4301 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4303 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4305 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4306 return_val_if_nok (error, NULL);
4307 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4308 return_val_if_nok (error, NULL);
4310 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4311 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4313 MonoObject *exc = NULL;
4315 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4316 if (exc != NULL && is_ok (error))
4317 mono_error_set_exception_instance (error, (MonoException*)exc);
4319 return (MonoObject*) transparent_proxy;
4321 #endif /* DISABLE_REMOTING */
4324 * mono_object_xdomain_representation
4326 * @target_domain: a domain
4327 * @error: set on error.
4329 * Creates a representation of obj in the domain target_domain. This
4330 * is either a copy of obj arrived through via serialization and
4331 * deserialization or a proxy, depending on whether the object is
4332 * serializable or marshal by ref. obj must not be in target_domain.
4334 * If the object cannot be represented in target_domain, NULL is
4335 * returned and @error is set appropriately.
4338 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4340 MONO_REQ_GC_UNSAFE_MODE;
4342 mono_error_init (error);
4343 MonoObject *deserialized = NULL;
4345 #ifndef DISABLE_REMOTING
4346 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4347 deserialized = make_transparent_proxy (obj, error);
4352 gboolean failure = FALSE;
4353 MonoDomain *domain = mono_domain_get ();
4354 MonoObject *serialized;
4355 MonoObject *exc = NULL;
4357 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4358 serialized = serialize_object (obj, &failure, &exc);
4359 mono_domain_set_internal_with_options (target_domain, FALSE);
4361 deserialized = deserialize_object (serialized, &failure, &exc);
4362 if (domain != target_domain)
4363 mono_domain_set_internal_with_options (domain, FALSE);
4365 mono_error_set_exception_instance (error, (MonoException*)exc);
4368 return deserialized;
4371 /* Used in call_unhandled_exception_delegate */
4373 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4375 MONO_REQ_GC_UNSAFE_MODE;
4377 mono_error_init (error);
4380 MonoMethod *method = NULL;
4381 MonoBoolean is_terminating = TRUE;
4384 klass = mono_class_get_unhandled_exception_event_args_class ();
4385 mono_class_init (klass);
4387 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4388 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4392 args [1] = &is_terminating;
4394 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4395 return_val_if_nok (error, NULL);
4397 mono_runtime_invoke_checked (method, obj, args, error);
4398 return_val_if_nok (error, NULL);
4403 /* Used in mono_unhandled_exception */
4405 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4406 MONO_REQ_GC_UNSAFE_MODE;
4409 MonoObject *e = NULL;
4411 MonoDomain *current_domain = mono_domain_get ();
4413 if (domain != current_domain)
4414 mono_domain_set_internal_with_options (domain, FALSE);
4416 g_assert (domain == mono_object_domain (domain->domain));
4418 if (mono_object_domain (exc) != domain) {
4420 exc = mono_object_xdomain_representation (exc, domain, &error);
4422 if (!is_ok (&error)) {
4423 MonoError inner_error;
4424 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4425 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4426 mono_error_assert_ok (&inner_error);
4428 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4429 "System.Runtime.Serialization", "SerializationException",
4430 "Could not serialize unhandled exception.");
4434 g_assert (mono_object_domain (exc) == domain);
4436 pa [0] = domain->domain;
4437 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4438 mono_error_assert_ok (&error);
4439 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4440 if (!is_ok (&error)) {
4442 e = (MonoObject*)mono_error_convert_to_exception (&error);
4444 mono_error_cleanup (&error);
4447 if (domain != current_domain)
4448 mono_domain_set_internal_with_options (current_domain, FALSE);
4451 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4452 if (!mono_error_ok (&error)) {
4453 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4454 mono_error_cleanup (&error);
4456 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4462 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4465 * mono_runtime_unhandled_exception_policy_set:
4466 * @policy: the new policy
4468 * This is a VM internal routine.
4470 * Sets the runtime policy for handling unhandled exceptions.
4473 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4474 runtime_unhandled_exception_policy = policy;
4478 * mono_runtime_unhandled_exception_policy_get:
4480 * This is a VM internal routine.
4482 * Gets the runtime policy for handling unhandled exceptions.
4484 MonoRuntimeUnhandledExceptionPolicy
4485 mono_runtime_unhandled_exception_policy_get (void) {
4486 return runtime_unhandled_exception_policy;
4490 * mono_unhandled_exception:
4491 * @exc: exception thrown
4493 * This is a VM internal routine.
4495 * We call this function when we detect an unhandled exception
4496 * in the default domain.
4498 * It invokes the * UnhandledException event in AppDomain or prints
4499 * a warning to the console
4502 mono_unhandled_exception (MonoObject *exc)
4504 MONO_REQ_GC_UNSAFE_MODE;
4507 MonoClassField *field;
4508 MonoDomain *current_domain, *root_domain;
4509 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4511 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4514 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4517 current_domain = mono_domain_get ();
4518 root_domain = mono_get_root_domain ();
4520 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4521 mono_error_assert_ok (&error);
4522 if (current_domain != root_domain) {
4523 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4524 mono_error_assert_ok (&error);
4527 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4528 mono_print_unhandled_exception (exc);
4530 /* unhandled exception callbacks must not be aborted */
4531 mono_threads_begin_abort_protected_block ();
4532 if (root_appdomain_delegate)
4533 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4534 if (current_appdomain_delegate)
4535 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4536 mono_threads_end_abort_protected_block ();
4539 /* set exitcode only if we will abort the process */
4540 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4541 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4543 mono_environment_exitcode_set (1);
4548 * mono_runtime_exec_managed_code:
4549 * @domain: Application domain
4550 * @main_func: function to invoke from the execution thread
4551 * @main_args: parameter to the main_func
4553 * Launch a new thread to execute a function
4555 * main_func is called back from the thread with main_args as the
4556 * parameter. The callback function is expected to start Main()
4557 * eventually. This function then waits for all managed threads to
4559 * It is not necesseray anymore to execute managed code in a subthread,
4560 * so this function should not be used anymore by default: just
4561 * execute the code and then call mono_thread_manage ().
4564 mono_runtime_exec_managed_code (MonoDomain *domain,
4565 MonoMainThreadFunc main_func,
4569 mono_thread_create_checked (domain, main_func, main_args, &error);
4570 mono_error_assert_ok (&error);
4572 mono_thread_manage ();
4576 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4578 MonoInternalThread* thread = mono_thread_internal_current ();
4579 MonoCustomAttrInfo* cinfo;
4580 gboolean has_stathread_attribute;
4582 if (!domain->entry_assembly) {
4584 MonoAssembly *assembly;
4586 assembly = method->klass->image->assembly;
4587 domain->entry_assembly = assembly;
4588 /* Domains created from another domain already have application_base and configuration_file set */
4589 if (domain->setup->application_base == NULL) {
4590 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4593 if (domain->setup->configuration_file == NULL) {
4594 str = g_strconcat (assembly->image->name, ".config", NULL);
4595 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4597 mono_domain_set_options_from_config (domain);
4601 MonoError cattr_error;
4602 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4603 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4605 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4607 mono_custom_attrs_free (cinfo);
4609 has_stathread_attribute = FALSE;
4611 if (has_stathread_attribute) {
4612 thread->apartment_state = ThreadApartmentState_STA;
4614 thread->apartment_state = ThreadApartmentState_MTA;
4616 mono_thread_init_apartment_state ();
4621 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4623 MONO_REQ_GC_UNSAFE_MODE;
4628 mono_error_init (error);
4633 /* FIXME: check signature of method */
4634 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4636 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4638 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4641 mono_environment_exitcode_set (rval);
4643 mono_runtime_invoke_checked (method, NULL, pa, error);
4655 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4657 MONO_REQ_GC_UNSAFE_MODE;
4667 /* FIXME: check signature of method */
4668 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4669 MonoError inner_error;
4671 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4672 if (*exc == NULL && !mono_error_ok (&inner_error))
4673 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4675 mono_error_cleanup (&inner_error);
4678 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4682 mono_environment_exitcode_set (rval);
4684 MonoError inner_error;
4685 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4686 if (*exc == NULL && !mono_error_ok (&inner_error))
4687 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4689 mono_error_cleanup (&inner_error);
4694 /* If the return type of Main is void, only
4695 * set the exitcode if an exception was thrown
4696 * (we don't want to blow away an
4697 * explicitly-set exit code)
4700 mono_environment_exitcode_set (rval);
4708 * Execute a standard Main() method (args doesn't contain the
4712 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4715 prepare_thread_to_exec_main (mono_object_domain (args), method);
4717 int rval = do_try_exec_main (method, args, exc);
4720 int rval = do_exec_main_checked (method, args, &error);
4721 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4727 * Execute a standard Main() method (args doesn't contain the
4730 * On failure sets @error
4733 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4735 mono_error_init (error);
4736 prepare_thread_to_exec_main (mono_object_domain (args), method);
4737 return do_exec_main_checked (method, args, error);
4741 * Execute a standard Main() method (args doesn't contain the
4744 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4747 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4749 prepare_thread_to_exec_main (mono_object_domain (args), method);
4750 return do_try_exec_main (method, args, exc);
4755 /** invoke_array_extract_argument:
4756 * @params: array of arguments to the method.
4757 * @i: the index of the argument to extract.
4758 * @t: ith type from the method signature.
4759 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4760 * @error: set on error.
4762 * Given an array of method arguments, return the ith one using the corresponding type
4763 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4765 * On failure sets @error and returns NULL.
4768 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4770 MonoType *t_orig = t;
4771 gpointer result = NULL;
4772 mono_error_init (error);
4777 case MONO_TYPE_BOOLEAN:
4780 case MONO_TYPE_CHAR:
4789 case MONO_TYPE_VALUETYPE:
4790 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4791 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4792 result = mono_array_get (params, MonoObject*, i);
4794 *has_byref_nullables = TRUE;
4796 /* MS seems to create the objects if a null is passed in */
4797 if (!mono_array_get (params, MonoObject*, i)) {
4798 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4799 return_val_if_nok (error, NULL);
4800 mono_array_setref (params, i, o);
4805 * We can't pass the unboxed vtype byref to the callee, since
4806 * that would mean the callee would be able to modify boxed
4807 * primitive types. So we (and MS) make a copy of the boxed
4808 * object, pass that to the callee, and replace the original
4809 * boxed object in the arg array with the copy.
4811 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4812 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4813 return_val_if_nok (error, NULL);
4814 mono_array_setref (params, i, copy);
4817 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4820 case MONO_TYPE_STRING:
4821 case MONO_TYPE_OBJECT:
4822 case MONO_TYPE_CLASS:
4823 case MONO_TYPE_ARRAY:
4824 case MONO_TYPE_SZARRAY:
4826 result = mono_array_addr (params, MonoObject*, i);
4827 // FIXME: I need to check this code path
4829 result = mono_array_get (params, MonoObject*, i);
4831 case MONO_TYPE_GENERICINST:
4833 t = &t->data.generic_class->container_class->this_arg;
4835 t = &t->data.generic_class->container_class->byval_arg;
4837 case MONO_TYPE_PTR: {
4840 /* The argument should be an IntPtr */
4841 arg = mono_array_get (params, MonoObject*, i);
4845 g_assert (arg->vtable->klass == mono_defaults.int_class);
4846 result = ((MonoIntPtr*)arg)->m_value;
4851 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4856 * mono_runtime_invoke_array:
4857 * @method: method to invoke
4858 * @obJ: object instance
4859 * @params: arguments to the method
4860 * @exc: exception information.
4862 * Invokes the method represented by @method on the object @obj.
4864 * obj is the 'this' pointer, it should be NULL for static
4865 * methods, a MonoObject* for object instances and a pointer to
4866 * the value type for value types.
4868 * The params array contains the arguments to the method with the
4869 * same convention: MonoObject* pointers for object instances and
4870 * pointers to the value type otherwise. The _invoke_array
4871 * variant takes a C# object[] as the params argument (MonoArray
4872 * *params): in this case the value types are boxed inside the
4873 * respective reference representation.
4875 * From unmanaged code you'll usually use the
4876 * mono_runtime_invoke_checked() variant.
4878 * Note that this function doesn't handle virtual methods for
4879 * you, it will exec the exact method you pass: we still need to
4880 * expose a function to lookup the derived class implementation
4881 * of a virtual method (there are examples of this in the code,
4884 * You can pass NULL as the exc argument if you don't want to
4885 * catch exceptions, otherwise, *exc will be set to the exception
4886 * thrown, if any. if an exception is thrown, you can't use the
4887 * MonoObject* result from the function.
4889 * If the method returns a value type, it is boxed in an object
4893 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4898 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4900 mono_error_cleanup (&error);
4903 if (!is_ok (&error))
4904 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4908 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4909 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4915 * mono_runtime_invoke_array_checked:
4916 * @method: method to invoke
4917 * @obJ: object instance
4918 * @params: arguments to the method
4919 * @error: set on failure.
4921 * Invokes the method represented by @method on the object @obj.
4923 * obj is the 'this' pointer, it should be NULL for static
4924 * methods, a MonoObject* for object instances and a pointer to
4925 * the value type for value types.
4927 * The params array contains the arguments to the method with the
4928 * same convention: MonoObject* pointers for object instances and
4929 * pointers to the value type otherwise. The _invoke_array
4930 * variant takes a C# object[] as the params argument (MonoArray
4931 * *params): in this case the value types are boxed inside the
4932 * respective reference representation.
4934 * From unmanaged code you'll usually use the
4935 * mono_runtime_invoke_checked() variant.
4937 * Note that this function doesn't handle virtual methods for
4938 * you, it will exec the exact method you pass: we still need to
4939 * expose a function to lookup the derived class implementation
4940 * of a virtual method (there are examples of this in the code,
4943 * On failure or exception, @error will be set. In that case, you
4944 * can't use the MonoObject* result from the function.
4946 * If the method returns a value type, it is boxed in an object
4950 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4953 mono_error_init (error);
4954 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4958 * mono_runtime_try_invoke_array:
4959 * @method: method to invoke
4960 * @obJ: object instance
4961 * @params: arguments to the method
4962 * @exc: exception information.
4963 * @error: set on failure.
4965 * Invokes the method represented by @method on the object @obj.
4967 * obj is the 'this' pointer, it should be NULL for static
4968 * methods, a MonoObject* for object instances and a pointer to
4969 * the value type for value types.
4971 * The params array contains the arguments to the method with the
4972 * same convention: MonoObject* pointers for object instances and
4973 * pointers to the value type otherwise. The _invoke_array
4974 * variant takes a C# object[] as the params argument (MonoArray
4975 * *params): in this case the value types are boxed inside the
4976 * respective reference representation.
4978 * From unmanaged code you'll usually use the
4979 * mono_runtime_invoke_checked() variant.
4981 * Note that this function doesn't handle virtual methods for
4982 * you, it will exec the exact method you pass: we still need to
4983 * expose a function to lookup the derived class implementation
4984 * of a virtual method (there are examples of this in the code,
4987 * You can pass NULL as the exc argument if you don't want to catch
4988 * exceptions, otherwise, *exc will be set to the exception thrown, if
4989 * any. On other failures, @error will be set. If an exception is
4990 * thrown or there's an error, you can't use the MonoObject* result
4991 * from the function.
4993 * If the method returns a value type, it is boxed in an object
4997 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4998 MonoObject **exc, MonoError *error)
5000 MONO_REQ_GC_UNSAFE_MODE;
5002 mono_error_init (error);
5004 MonoMethodSignature *sig = mono_method_signature (method);
5005 gpointer *pa = NULL;
5008 gboolean has_byref_nullables = FALSE;
5010 if (NULL != params) {
5011 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5012 for (i = 0; i < mono_array_length (params); i++) {
5013 MonoType *t = sig->params [i];
5014 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5015 return_val_if_nok (error, NULL);
5019 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5022 if (mono_class_is_nullable (method->klass)) {
5023 /* Need to create a boxed vtype instead */
5029 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5034 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5035 mono_error_assert_ok (error);
5036 g_assert (obj); /*maybe we should raise a TLE instead?*/
5037 #ifndef DISABLE_REMOTING
5038 if (mono_object_is_transparent_proxy (obj)) {
5039 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5042 if (method->klass->valuetype)
5043 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5046 } else if (method->klass->valuetype) {
5047 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5048 return_val_if_nok (error, NULL);
5052 mono_runtime_try_invoke (method, o, pa, exc, error);
5054 mono_runtime_invoke_checked (method, o, pa, error);
5057 return (MonoObject *)obj;
5059 if (mono_class_is_nullable (method->klass)) {
5060 MonoObject *nullable;
5062 /* Convert the unboxed vtype into a Nullable structure */
5063 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5064 return_val_if_nok (error, NULL);
5066 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5067 return_val_if_nok (error, NULL);
5068 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5069 obj = mono_object_unbox (nullable);
5072 /* obj must be already unboxed if needed */
5074 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5076 res = mono_runtime_invoke_checked (method, obj, pa, error);
5078 return_val_if_nok (error, NULL);
5080 if (sig->ret->type == MONO_TYPE_PTR) {
5081 MonoClass *pointer_class;
5082 static MonoMethod *box_method;
5084 MonoObject *box_exc;
5087 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5088 * convert it to a Pointer object.
5090 pointer_class = mono_class_get_pointer_class ();
5092 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5094 g_assert (res->vtable->klass == mono_defaults.int_class);
5095 box_args [0] = ((MonoIntPtr*)res)->m_value;
5096 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5097 return_val_if_nok (error, NULL);
5099 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5100 g_assert (box_exc == NULL);
5101 mono_error_assert_ok (error);
5104 if (has_byref_nullables) {
5106 * The runtime invoke wrapper already converted byref nullables back,
5107 * and stored them in pa, we just need to copy them back to the
5110 for (i = 0; i < mono_array_length (params); i++) {
5111 MonoType *t = sig->params [i];
5113 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5114 mono_array_setref (params, i, pa [i]);
5124 * @klass: the class of the object that we want to create
5126 * Returns: a newly created object whose definition is
5127 * looked up using @klass. This will not invoke any constructors,
5128 * so the consumer of this routine has to invoke any constructors on
5129 * its own to initialize the object.
5131 * It returns NULL on failure.
5134 mono_object_new (MonoDomain *domain, MonoClass *klass)
5136 MONO_REQ_GC_UNSAFE_MODE;
5140 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5142 mono_error_cleanup (&error);
5147 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5149 MONO_REQ_GC_UNSAFE_MODE;
5153 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5155 mono_error_set_pending_exception (&error);
5160 * mono_object_new_checked:
5161 * @klass: the class of the object that we want to create
5162 * @error: set on error
5164 * Returns: a newly created object whose definition is
5165 * looked up using @klass. This will not invoke any constructors,
5166 * so the consumer of this routine has to invoke any constructors on
5167 * its own to initialize the object.
5169 * It returns NULL on failure and sets @error.
5172 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5174 MONO_REQ_GC_UNSAFE_MODE;
5178 vtable = mono_class_vtable (domain, klass);
5179 g_assert (vtable); /* FIXME don't swallow the error */
5181 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5186 * mono_object_new_pinned:
5188 * Same as mono_object_new, but the returned object will be pinned.
5189 * For SGEN, these objects will only be freed at appdomain unload.
5192 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5194 MONO_REQ_GC_UNSAFE_MODE;
5198 mono_error_init (error);
5200 vtable = mono_class_vtable (domain, klass);
5201 g_assert (vtable); /* FIXME don't swallow the error */
5203 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5205 if (G_UNLIKELY (!o))
5206 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5207 else if (G_UNLIKELY (vtable->klass->has_finalize))
5208 mono_object_register_finalizer (o);
5214 * mono_object_new_specific:
5215 * @vtable: the vtable of the object that we want to create
5217 * Returns: A newly created object with class and domain specified
5221 mono_object_new_specific (MonoVTable *vtable)
5224 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5225 mono_error_cleanup (&error);
5231 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5233 MONO_REQ_GC_UNSAFE_MODE;
5237 mono_error_init (error);
5239 /* check for is_com_object for COM Interop */
5240 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5243 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5246 MonoClass *klass = mono_class_get_activation_services_class ();
5249 mono_class_init (klass);
5251 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5253 mono_error_set_not_supported (error, "Linked away.");
5256 vtable->domain->create_proxy_for_type_method = im;
5259 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5260 if (!mono_error_ok (error))
5263 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5264 if (!mono_error_ok (error))
5271 return mono_object_new_alloc_specific_checked (vtable, error);
5275 ves_icall_object_new_specific (MonoVTable *vtable)
5278 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5279 mono_error_set_pending_exception (&error);
5285 * mono_object_new_alloc_specific:
5286 * @vtable: virtual table for the object.
5288 * This function allocates a new `MonoObject` with the type derived
5289 * from the @vtable information. If the class of this object has a
5290 * finalizer, then the object will be tracked for finalization.
5292 * This method might raise an exception on errors. Use the
5293 * `mono_object_new_fast_checked` method if you want to manually raise
5296 * Returns: the allocated object.
5299 mono_object_new_alloc_specific (MonoVTable *vtable)
5302 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5303 mono_error_cleanup (&error);
5309 * mono_object_new_alloc_specific_checked:
5310 * @vtable: virtual table for the object.
5311 * @error: holds the error return value.
5313 * This function allocates a new `MonoObject` with the type derived
5314 * from the @vtable information. If the class of this object has a
5315 * finalizer, then the object will be tracked for finalization.
5317 * If there is not enough memory, the @error parameter will be set
5318 * and will contain a user-visible message with the amount of bytes
5319 * that were requested.
5321 * Returns: the allocated object, or NULL if there is not enough memory
5325 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5327 MONO_REQ_GC_UNSAFE_MODE;
5331 mono_error_init (error);
5333 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5335 if (G_UNLIKELY (!o))
5336 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5337 else if (G_UNLIKELY (vtable->klass->has_finalize))
5338 mono_object_register_finalizer (o);
5344 * mono_object_new_fast:
5345 * @vtable: virtual table for the object.
5347 * This function allocates a new `MonoObject` with the type derived
5348 * from the @vtable information. The returned object is not tracked
5349 * for finalization. If your object implements a finalizer, you should
5350 * use `mono_object_new_alloc_specific` instead.
5352 * This method might raise an exception on errors. Use the
5353 * `mono_object_new_fast_checked` method if you want to manually raise
5356 * Returns: the allocated object.
5359 mono_object_new_fast (MonoVTable *vtable)
5362 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5363 mono_error_cleanup (&error);
5369 * mono_object_new_fast_checked:
5370 * @vtable: virtual table for the object.
5371 * @error: holds the error return value.
5373 * This function allocates a new `MonoObject` with the type derived
5374 * from the @vtable information. The returned object is not tracked
5375 * for finalization. If your object implements a finalizer, you should
5376 * use `mono_object_new_alloc_specific_checked` instead.
5378 * If there is not enough memory, the @error parameter will be set
5379 * and will contain a user-visible message with the amount of bytes
5380 * that were requested.
5382 * Returns: the allocated object, or NULL if there is not enough memory
5386 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5388 MONO_REQ_GC_UNSAFE_MODE;
5392 mono_error_init (error);
5394 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5396 if (G_UNLIKELY (!o))
5397 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5403 ves_icall_object_new_fast (MonoVTable *vtable)
5406 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5407 mono_error_set_pending_exception (&error);
5413 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5415 MONO_REQ_GC_UNSAFE_MODE;
5419 mono_error_init (error);
5421 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5423 if (G_UNLIKELY (!o))
5424 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5425 else if (G_UNLIKELY (vtable->klass->has_finalize))
5426 mono_object_register_finalizer (o);
5432 * mono_class_get_allocation_ftn:
5434 * @for_box: the object will be used for boxing
5435 * @pass_size_in_words:
5437 * Return the allocation function appropriate for the given class.
5441 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5443 MONO_REQ_GC_NEUTRAL_MODE;
5445 *pass_size_in_words = FALSE;
5447 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5448 return ves_icall_object_new_specific;
5450 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5452 return ves_icall_object_new_fast;
5455 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5456 * of the overhead of parameter passing.
5459 *pass_size_in_words = TRUE;
5460 #ifdef GC_REDIRECT_TO_LOCAL
5461 return GC_local_gcj_fast_malloc;
5463 return GC_gcj_fast_malloc;
5468 return ves_icall_object_new_specific;
5472 * mono_object_new_from_token:
5473 * @image: Context where the type_token is hosted
5474 * @token: a token of the type that we want to create
5476 * Returns: A newly created object whose definition is
5477 * looked up using @token in the @image image
5480 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5482 MONO_REQ_GC_UNSAFE_MODE;
5488 klass = mono_class_get_checked (image, token, &error);
5489 mono_error_assert_ok (&error);
5491 result = mono_object_new_checked (domain, klass, &error);
5493 mono_error_cleanup (&error);
5500 * mono_object_clone:
5501 * @obj: the object to clone
5503 * Returns: A newly created object who is a shallow copy of @obj
5506 mono_object_clone (MonoObject *obj)
5509 MonoObject *o = mono_object_clone_checked (obj, &error);
5510 mono_error_cleanup (&error);
5516 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5518 MONO_REQ_GC_UNSAFE_MODE;
5523 mono_error_init (error);
5525 size = obj->vtable->klass->instance_size;
5527 if (obj->vtable->klass->rank)
5528 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5530 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5532 if (G_UNLIKELY (!o)) {
5533 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5537 /* If the object doesn't contain references this will do a simple memmove. */
5538 mono_gc_wbarrier_object_copy (o, obj);
5540 if (obj->vtable->klass->has_finalize)
5541 mono_object_register_finalizer (o);
5546 * mono_array_full_copy:
5547 * @src: source array to copy
5548 * @dest: destination array
5550 * Copies the content of one array to another with exactly the same type and size.
5553 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5555 MONO_REQ_GC_UNSAFE_MODE;
5558 MonoClass *klass = src->obj.vtable->klass;
5560 g_assert (klass == dest->obj.vtable->klass);
5562 size = mono_array_length (src);
5563 g_assert (size == mono_array_length (dest));
5564 size *= mono_array_element_size (klass);
5566 if (klass->element_class->valuetype) {
5567 if (klass->element_class->has_references)
5568 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5570 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5572 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5575 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5580 * mono_array_clone_in_domain:
5581 * @domain: the domain in which the array will be cloned into
5582 * @array: the array to clone
5583 * @error: set on error
5585 * This routine returns a copy of the array that is hosted on the
5586 * specified MonoDomain. On failure returns NULL and sets @error.
5589 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5591 MONO_REQ_GC_UNSAFE_MODE;
5596 MonoClass *klass = array->obj.vtable->klass;
5598 mono_error_init (error);
5600 if (array->bounds == NULL) {
5601 size = mono_array_length (array);
5602 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5603 return_val_if_nok (error, NULL);
5605 size *= mono_array_element_size (klass);
5607 if (klass->element_class->valuetype) {
5608 if (klass->element_class->has_references)
5609 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5611 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5613 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5616 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5621 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5622 size = mono_array_element_size (klass);
5623 for (i = 0; i < klass->rank; ++i) {
5624 sizes [i] = array->bounds [i].length;
5625 size *= array->bounds [i].length;
5626 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5628 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5629 return_val_if_nok (error, NULL);
5631 if (klass->element_class->valuetype) {
5632 if (klass->element_class->has_references)
5633 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5635 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5637 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5640 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5648 * @array: the array to clone
5650 * Returns: A newly created array who is a shallow copy of @array
5653 mono_array_clone (MonoArray *array)
5655 MONO_REQ_GC_UNSAFE_MODE;
5658 MonoArray *result = mono_array_clone_checked (array, &error);
5659 mono_error_cleanup (&error);
5664 * mono_array_clone_checked:
5665 * @array: the array to clone
5666 * @error: set on error
5668 * Returns: A newly created array who is a shallow copy of @array. On
5669 * failure returns NULL and sets @error.
5672 mono_array_clone_checked (MonoArray *array, MonoError *error)
5675 MONO_REQ_GC_UNSAFE_MODE;
5676 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5679 /* helper macros to check for overflow when calculating the size of arrays */
5680 #ifdef MONO_BIG_ARRAYS
5681 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5682 #define MYGUINT_MAX MYGUINT64_MAX
5683 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5684 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5685 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5686 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5687 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5689 #define MYGUINT32_MAX 4294967295U
5690 #define MYGUINT_MAX MYGUINT32_MAX
5691 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5692 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5693 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5694 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5695 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5699 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5701 MONO_REQ_GC_NEUTRAL_MODE;
5705 byte_len = mono_array_element_size (klass);
5706 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5709 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5711 byte_len += MONO_SIZEOF_MONO_ARRAY;
5719 * mono_array_new_full:
5720 * @domain: domain where the object is created
5721 * @array_class: array class
5722 * @lengths: lengths for each dimension in the array
5723 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5725 * This routine creates a new array objects with the given dimensions,
5726 * lower bounds and type.
5729 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5732 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5733 mono_error_cleanup (&error);
5739 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5741 MONO_REQ_GC_UNSAFE_MODE;
5743 uintptr_t byte_len = 0, len, bounds_size;
5746 MonoArrayBounds *bounds;
5750 mono_error_init (error);
5752 if (!array_class->inited)
5753 mono_class_init (array_class);
5757 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5758 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5760 if (len > MONO_ARRAY_MAX_INDEX) {
5761 mono_error_set_generic_error (error, "System", "OverflowException", "");
5766 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5768 for (i = 0; i < array_class->rank; ++i) {
5769 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5770 mono_error_set_generic_error (error, "System", "OverflowException", "");
5773 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5774 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5781 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5782 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5788 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5789 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5792 byte_len = (byte_len + 3) & ~3;
5793 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5794 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5797 byte_len += bounds_size;
5800 * Following three lines almost taken from mono_object_new ():
5801 * they need to be kept in sync.
5803 vtable = mono_class_vtable_full (domain, array_class, error);
5804 return_val_if_nok (error, NULL);
5807 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5809 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5811 if (G_UNLIKELY (!o)) {
5812 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5816 array = (MonoArray*)o;
5818 bounds = array->bounds;
5821 for (i = 0; i < array_class->rank; ++i) {
5822 bounds [i].length = lengths [i];
5824 bounds [i].lower_bound = lower_bounds [i];
5833 * @domain: domain where the object is created
5834 * @eclass: element class
5835 * @n: number of array elements
5837 * This routine creates a new szarray with @n elements of type @eclass.
5840 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5842 MONO_REQ_GC_UNSAFE_MODE;
5845 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5846 mono_error_cleanup (&error);
5851 * mono_array_new_checked:
5852 * @domain: domain where the object is created
5853 * @eclass: element class
5854 * @n: number of array elements
5855 * @error: set on error
5857 * This routine creates a new szarray with @n elements of type @eclass.
5858 * On failure returns NULL and sets @error.
5861 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5865 mono_error_init (error);
5867 ac = mono_array_class_get (eclass, 1);
5870 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5871 return_val_if_nok (error, NULL);
5873 return mono_array_new_specific_checked (vtable, n, error);
5877 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5880 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5881 mono_error_set_pending_exception (&error);
5887 * mono_array_new_specific:
5888 * @vtable: a vtable in the appropriate domain for an initialized class
5889 * @n: number of array elements
5891 * This routine is a fast alternative to mono_array_new() for code which
5892 * can be sure about the domain it operates in.
5895 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5898 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5899 mono_error_cleanup (&error);
5905 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5907 MONO_REQ_GC_UNSAFE_MODE;
5912 mono_error_init (error);
5914 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5915 mono_error_set_generic_error (error, "System", "OverflowException", "");
5919 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5920 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5923 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5925 if (G_UNLIKELY (!o)) {
5926 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5930 return (MonoArray*)o;
5934 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5937 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5938 mono_error_set_pending_exception (&error);
5944 * mono_string_empty_wrapper:
5946 * Returns: The same empty string instance as the managed string.Empty
5949 mono_string_empty_wrapper (void)
5951 MonoDomain *domain = mono_domain_get ();
5952 return mono_string_empty (domain);
5956 * mono_string_empty:
5958 * Returns: The same empty string instance as the managed string.Empty
5961 mono_string_empty (MonoDomain *domain)
5964 g_assert (domain->empty_string);
5965 return domain->empty_string;
5969 * mono_string_new_utf16:
5970 * @text: a pointer to an utf16 string
5971 * @len: the length of the string
5973 * Returns: A newly created string object which contains @text.
5976 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5978 MONO_REQ_GC_UNSAFE_MODE;
5981 MonoString *res = NULL;
5982 res = mono_string_new_utf16_checked (domain, text, len, &error);
5983 mono_error_cleanup (&error);
5989 * mono_string_new_utf16_checked:
5990 * @text: a pointer to an utf16 string
5991 * @len: the length of the string
5992 * @error: written on error.
5994 * Returns: A newly created string object which contains @text.
5995 * On error, returns NULL and sets @error.
5998 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6000 MONO_REQ_GC_UNSAFE_MODE;
6004 mono_error_init (error);
6006 s = mono_string_new_size_checked (domain, len, error);
6008 memcpy (mono_string_chars (s), text, len * 2);
6014 * mono_string_new_utf32:
6015 * @text: a pointer to an utf32 string
6016 * @len: the length of the string
6017 * @error: set on failure.
6019 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6022 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6024 MONO_REQ_GC_UNSAFE_MODE;
6027 mono_unichar2 *utf16_output = NULL;
6028 gint32 utf16_len = 0;
6029 GError *gerror = NULL;
6030 glong items_written;
6032 mono_error_init (error);
6033 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6036 g_error_free (gerror);
6038 while (utf16_output [utf16_len]) utf16_len++;
6040 s = mono_string_new_size_checked (domain, utf16_len, error);
6041 return_val_if_nok (error, NULL);
6043 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6045 g_free (utf16_output);
6051 * mono_string_new_utf32:
6052 * @text: a pointer to an utf32 string
6053 * @len: the length of the string
6055 * Returns: A newly created string object which contains @text.
6058 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6061 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6062 mono_error_cleanup (&error);
6067 * mono_string_new_size:
6068 * @text: a pointer to an utf16 string
6069 * @len: the length of the string
6071 * Returns: A newly created string object of @len
6074 mono_string_new_size (MonoDomain *domain, gint32 len)
6077 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6078 mono_error_cleanup (&error);
6084 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6086 MONO_REQ_GC_UNSAFE_MODE;
6092 mono_error_init (error);
6094 /* check for overflow */
6095 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6096 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6100 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6101 g_assert (size > 0);
6103 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6106 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6108 if (G_UNLIKELY (!s)) {
6109 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6117 * mono_string_new_len:
6118 * @text: a pointer to an utf8 string
6119 * @length: number of bytes in @text to consider
6121 * Returns: A newly created string object which contains @text.
6124 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6126 MONO_REQ_GC_UNSAFE_MODE;
6129 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6130 mono_error_cleanup (&error);
6135 * mono_string_new_len_checked:
6136 * @text: a pointer to an utf8 string
6137 * @length: number of bytes in @text to consider
6138 * @error: set on error
6140 * Returns: A newly created string object which contains @text. On
6141 * failure returns NULL and sets @error.
6144 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6146 MONO_REQ_GC_UNSAFE_MODE;
6148 mono_error_init (error);
6150 GError *eg_error = NULL;
6151 MonoString *o = NULL;
6153 glong items_written;
6155 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6158 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6160 g_error_free (eg_error);
6169 * @text: a pointer to an utf8 string
6171 * Returns: A newly created string object which contains @text.
6173 * This function asserts if it cannot allocate a new string.
6175 * @deprecated Use mono_string_new_checked in new code.
6178 mono_string_new (MonoDomain *domain, const char *text)
6181 MonoString *res = NULL;
6182 res = mono_string_new_checked (domain, text, &error);
6183 mono_error_assert_ok (&error);
6188 * mono_string_new_checked:
6189 * @text: a pointer to an utf8 string
6190 * @merror: set on error
6192 * Returns: A newly created string object which contains @text.
6193 * On error returns NULL and sets @merror.
6196 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6198 MONO_REQ_GC_UNSAFE_MODE;
6200 GError *eg_error = NULL;
6201 MonoString *o = NULL;
6203 glong items_written;
6206 mono_error_init (error);
6210 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6213 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6215 g_error_free (eg_error);
6219 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6224 MonoString *o = NULL;
6226 if (!g_utf8_validate (text, -1, &end)) {
6227 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6231 len = g_utf8_strlen (text, -1);
6232 o = mono_string_new_size_checked (domain, len, error);
6235 str = mono_string_chars (o);
6237 while (text < end) {
6238 *str++ = g_utf8_get_char (text);
6239 text = g_utf8_next_char (text);
6248 * mono_string_new_wrapper:
6249 * @text: pointer to utf8 characters.
6251 * Helper function to create a string object from @text in the current domain.
6254 mono_string_new_wrapper (const char *text)
6256 MONO_REQ_GC_UNSAFE_MODE;
6258 MonoDomain *domain = mono_domain_get ();
6261 return mono_string_new (domain, text);
6268 * @class: the class of the value
6269 * @value: a pointer to the unboxed data
6271 * Returns: A newly created object which contains @value.
6274 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6277 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6278 mono_error_cleanup (&error);
6283 * mono_value_box_checked:
6284 * @domain: the domain of the new object
6285 * @class: the class of the value
6286 * @value: a pointer to the unboxed data
6287 * @error: set on error
6289 * Returns: A newly created object which contains @value. On failure
6290 * returns NULL and sets @error.
6293 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6295 MONO_REQ_GC_UNSAFE_MODE;
6300 mono_error_init (error);
6302 g_assert (klass->valuetype);
6303 if (mono_class_is_nullable (klass))
6304 return mono_nullable_box ((guint8 *)value, klass, error);
6306 vtable = mono_class_vtable (domain, klass);
6309 size = mono_class_instance_size (klass);
6310 res = mono_object_new_alloc_specific_checked (vtable, error);
6311 return_val_if_nok (error, NULL);
6313 size = size - sizeof (MonoObject);
6316 g_assert (size == mono_class_value_size (klass, NULL));
6317 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6319 #if NO_UNALIGNED_ACCESS
6320 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6324 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6327 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6330 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6333 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6336 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6340 if (klass->has_finalize) {
6341 mono_object_register_finalizer (res);
6342 return_val_if_nok (error, NULL);
6349 * @dest: destination pointer
6350 * @src: source pointer
6351 * @klass: a valuetype class
6353 * Copy a valuetype from @src to @dest. This function must be used
6354 * when @klass contains references fields.
6357 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6359 MONO_REQ_GC_UNSAFE_MODE;
6361 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6365 * mono_value_copy_array:
6366 * @dest: destination array
6367 * @dest_idx: index in the @dest array
6368 * @src: source pointer
6369 * @count: number of items
6371 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6372 * This function must be used when @klass contains references fields.
6373 * Overlap is handled.
6376 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6378 MONO_REQ_GC_UNSAFE_MODE;
6380 int size = mono_array_element_size (dest->obj.vtable->klass);
6381 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6382 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6383 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6387 * mono_object_get_domain:
6388 * @obj: object to query
6390 * Returns: the MonoDomain where the object is hosted
6393 mono_object_get_domain (MonoObject *obj)
6395 MONO_REQ_GC_UNSAFE_MODE;
6397 return mono_object_domain (obj);
6401 * mono_object_get_class:
6402 * @obj: object to query
6404 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6406 * Returns: the MonoClass of the object.
6409 mono_object_get_class (MonoObject *obj)
6411 MONO_REQ_GC_UNSAFE_MODE;
6413 return mono_object_class (obj);
6416 * mono_object_get_size:
6417 * @o: object to query
6419 * Returns: the size, in bytes, of @o
6422 mono_object_get_size (MonoObject* o)
6424 MONO_REQ_GC_UNSAFE_MODE;
6426 MonoClass* klass = mono_object_class (o);
6427 if (klass == mono_defaults.string_class) {
6428 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6429 } else if (o->vtable->rank) {
6430 MonoArray *array = (MonoArray*)o;
6431 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6432 if (array->bounds) {
6435 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6439 return mono_class_instance_size (klass);
6444 * mono_object_unbox:
6445 * @obj: object to unbox
6447 * Returns: a pointer to the start of the valuetype boxed in this
6450 * This method will assert if the object passed is not a valuetype.
6453 mono_object_unbox (MonoObject *obj)
6455 MONO_REQ_GC_UNSAFE_MODE;
6457 /* add assert for valuetypes? */
6458 g_assert (obj->vtable->klass->valuetype);
6459 return ((char*)obj) + sizeof (MonoObject);
6463 * mono_object_isinst:
6465 * @klass: a pointer to a class
6467 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6470 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6472 MONO_REQ_GC_UNSAFE_MODE;
6474 HANDLE_FUNCTION_ENTER ();
6475 MONO_HANDLE_DCL (MonoObject, obj);
6477 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6478 mono_error_cleanup (&error);
6479 HANDLE_FUNCTION_RETURN_OBJ (result);
6484 * mono_object_isinst_checked:
6486 * @klass: a pointer to a class
6487 * @error: set on error
6489 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6490 * On failure returns NULL and sets @error.
6493 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6495 MONO_REQ_GC_UNSAFE_MODE;
6497 HANDLE_FUNCTION_ENTER ();
6498 mono_error_init (error);
6499 MONO_HANDLE_DCL (MonoObject, obj);
6500 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6501 HANDLE_FUNCTION_RETURN_OBJ (result);
6505 * mono_object_handle_isinst:
6507 * @klass: a pointer to a class
6508 * @error: set on error
6510 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6511 * On failure returns NULL and sets @error.
6514 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6516 mono_error_init (error);
6519 mono_class_init (klass);
6521 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6522 return mono_object_handle_isinst_mbyref (obj, klass, error);
6525 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6527 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6528 MONO_HANDLE_ASSIGN (result, obj);
6533 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6535 MONO_REQ_GC_UNSAFE_MODE;
6537 HANDLE_FUNCTION_ENTER ();
6539 MONO_HANDLE_DCL (MonoObject, obj);
6540 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6541 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6542 HANDLE_FUNCTION_RETURN_OBJ (result);
6546 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6548 mono_error_init (error);
6550 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6552 if (MONO_HANDLE_IS_NULL (obj))
6555 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6557 if (mono_class_is_interface (klass)) {
6558 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6559 MONO_HANDLE_ASSIGN (result, obj);
6563 /* casting an array one of the invariant interfaces that must act as such */
6564 if (klass->is_array_special_interface) {
6565 if (mono_class_is_assignable_from (klass, vt->klass)) {
6566 MONO_HANDLE_ASSIGN (result, obj);
6571 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6572 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6573 MONO_HANDLE_ASSIGN (result, obj);
6577 MonoClass *oklass = vt->klass;
6578 if (mono_class_is_transparent_proxy (oklass)){
6579 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6580 oklass = remote_class->proxy_class;
6583 mono_class_setup_supertypes (klass);
6584 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6585 MONO_HANDLE_ASSIGN (result, obj);
6589 #ifndef DISABLE_REMOTING
6590 if (mono_class_is_transparent_proxy (vt->klass))
6592 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6593 if (!custom_type_info)
6595 MonoDomain *domain = mono_domain_get ();
6596 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6597 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6598 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6599 MonoMethod *im = NULL;
6602 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6604 mono_error_set_not_supported (error, "Linked away.");
6607 im = mono_object_handle_get_virtual_method (rp, im, error);
6612 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6616 pa [0] = MONO_HANDLE_RAW (reftype);
6617 pa [1] = MONO_HANDLE_RAW (obj);
6618 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6622 if (*(MonoBoolean *) mono_object_unbox(res)) {
6623 /* Update the vtable of the remote type, so it can safely cast to this new type */
6624 mono_upgrade_remote_class (domain, obj, klass, error);
6627 MONO_HANDLE_ASSIGN (result, obj);
6630 #endif /* DISABLE_REMOTING */
6636 * mono_object_castclass_mbyref:
6638 * @klass: a pointer to a class
6640 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6643 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6645 MONO_REQ_GC_UNSAFE_MODE;
6646 HANDLE_FUNCTION_ENTER ();
6648 MONO_HANDLE_DCL (MonoObject, obj);
6649 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6650 if (MONO_HANDLE_IS_NULL (obj))
6652 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6653 mono_error_cleanup (&error);
6655 HANDLE_FUNCTION_RETURN_OBJ (result);
6659 MonoDomain *orig_domain;
6665 str_lookup (MonoDomain *domain, gpointer user_data)
6667 MONO_REQ_GC_UNSAFE_MODE;
6669 LDStrInfo *info = (LDStrInfo *)user_data;
6670 if (info->res || domain == info->orig_domain)
6672 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6676 mono_string_get_pinned (MonoString *str, MonoError *error)
6678 MONO_REQ_GC_UNSAFE_MODE;
6680 mono_error_init (error);
6682 /* We only need to make a pinned version of a string if this is a moving GC */
6683 if (!mono_gc_is_moving ())
6687 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6688 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6690 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6691 news->length = mono_string_length (str);
6693 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6699 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6701 MONO_REQ_GC_UNSAFE_MODE;
6703 MonoGHashTable *ldstr_table;
6704 MonoString *s, *res;
6707 mono_error_init (error);
6709 domain = ((MonoObject *)str)->vtable->domain;
6710 ldstr_table = domain->ldstr_table;
6712 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6718 /* Allocate outside the lock */
6720 s = mono_string_get_pinned (str, error);
6721 return_val_if_nok (error, NULL);
6724 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6729 mono_g_hash_table_insert (ldstr_table, s, s);
6734 LDStrInfo ldstr_info;
6735 ldstr_info.orig_domain = domain;
6736 ldstr_info.ins = str;
6737 ldstr_info.res = NULL;
6739 mono_domain_foreach (str_lookup, &ldstr_info);
6740 if (ldstr_info.res) {
6742 * the string was already interned in some other domain:
6743 * intern it in the current one as well.
6745 mono_g_hash_table_insert (ldstr_table, str, str);
6755 * mono_string_is_interned:
6756 * @o: String to probe
6758 * Returns whether the string has been interned.
6761 mono_string_is_interned (MonoString *o)
6764 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6765 /* This function does not fail. */
6766 mono_error_assert_ok (&error);
6771 * mono_string_intern:
6772 * @o: String to intern
6774 * Interns the string passed.
6775 * Returns: The interned string.
6778 mono_string_intern (MonoString *str)
6781 MonoString *result = mono_string_intern_checked (str, &error);
6782 mono_error_assert_ok (&error);
6787 * mono_string_intern_checked:
6788 * @o: String to intern
6789 * @error: set on error.
6791 * Interns the string passed.
6792 * Returns: The interned string. On failure returns NULL and sets @error
6795 mono_string_intern_checked (MonoString *str, MonoError *error)
6797 MONO_REQ_GC_UNSAFE_MODE;
6799 mono_error_init (error);
6801 return mono_string_is_interned_lookup (str, TRUE, error);
6806 * @domain: the domain where the string will be used.
6807 * @image: a metadata context
6808 * @idx: index into the user string table.
6810 * Implementation for the ldstr opcode.
6811 * Returns: a loaded string from the @image/@idx combination.
6814 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6817 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6818 mono_error_cleanup (&error);
6823 * mono_ldstr_checked:
6824 * @domain: the domain where the string will be used.
6825 * @image: a metadata context
6826 * @idx: index into the user string table.
6827 * @error: set on error.
6829 * Implementation for the ldstr opcode.
6830 * Returns: a loaded string from the @image/@idx combination.
6831 * On failure returns NULL and sets @error.
6834 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6836 MONO_REQ_GC_UNSAFE_MODE;
6837 mono_error_init (error);
6839 if (image->dynamic) {
6840 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6843 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6844 return NULL; /*FIXME we should probably be raising an exception here*/
6845 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6851 * mono_ldstr_metadata_sig
6852 * @domain: the domain for the string
6853 * @sig: the signature of a metadata string
6854 * @error: set on error
6856 * Returns: a MonoString for a string stored in the metadata. On
6857 * failure returns NULL and sets @error.
6860 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6862 MONO_REQ_GC_UNSAFE_MODE;
6864 mono_error_init (error);
6865 const char *str = sig;
6866 MonoString *o, *interned;
6869 len2 = mono_metadata_decode_blob_size (str, &str);
6872 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6873 return_val_if_nok (error, NULL);
6874 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6877 guint16 *p2 = (guint16*)mono_string_chars (o);
6878 for (i = 0; i < len2; ++i) {
6879 *p2 = GUINT16_FROM_LE (*p2);
6885 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6888 return interned; /* o will get garbage collected */
6890 o = mono_string_get_pinned (o, error);
6893 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6895 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6907 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6911 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6917 GError *gerror = NULL;
6919 mono_error_init (error);
6921 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6922 return NULL; /*FIXME we should probably be raising an exception here*/
6923 str = mono_metadata_user_string (image, idx);
6925 len2 = mono_metadata_decode_blob_size (str, &str);
6928 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6930 mono_error_set_argument (error, "string", "%s", gerror->message);
6931 g_error_free (gerror);
6934 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6935 if (len2 > written) {
6936 /* allocate the total length and copy the part of the string that has been converted */
6937 char *as2 = (char *)g_malloc0 (len2);
6938 memcpy (as2, as, written);
6947 * mono_string_to_utf8:
6948 * @s: a System.String
6950 * Returns the UTF8 representation for @s.
6951 * The resulting buffer needs to be freed with mono_free().
6953 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6956 mono_string_to_utf8 (MonoString *s)
6958 MONO_REQ_GC_UNSAFE_MODE;
6961 char *result = mono_string_to_utf8_checked (s, &error);
6963 if (!is_ok (&error)) {
6964 mono_error_cleanup (&error);
6971 * mono_string_to_utf8_checked:
6972 * @s: a System.String
6973 * @error: a MonoError.
6975 * Converts a MonoString to its UTF8 representation. May fail; check
6976 * @error to determine whether the conversion was successful.
6977 * The resulting buffer should be freed with mono_free().
6980 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6982 MONO_REQ_GC_UNSAFE_MODE;
6986 GError *gerror = NULL;
6988 mono_error_init (error);
6994 return g_strdup ("");
6996 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6998 mono_error_set_argument (error, "string", "%s", gerror->message);
6999 g_error_free (gerror);
7002 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7003 if (s->length > written) {
7004 /* allocate the total length and copy the part of the string that has been converted */
7005 char *as2 = (char *)g_malloc0 (s->length);
7006 memcpy (as2, as, written);
7015 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7017 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7021 * mono_string_to_utf8_ignore:
7024 * Converts a MonoString to its UTF8 representation. Will ignore
7025 * invalid surrogate pairs.
7026 * The resulting buffer should be freed with mono_free().
7030 mono_string_to_utf8_ignore (MonoString *s)
7032 MONO_REQ_GC_UNSAFE_MODE;
7041 return g_strdup ("");
7043 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7045 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7046 if (s->length > written) {
7047 /* allocate the total length and copy the part of the string that has been converted */
7048 char *as2 = (char *)g_malloc0 (s->length);
7049 memcpy (as2, as, written);
7058 * mono_string_to_utf8_image_ignore:
7059 * @s: a System.String
7061 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7064 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7066 MONO_REQ_GC_UNSAFE_MODE;
7068 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7072 * mono_string_to_utf8_mp_ignore:
7073 * @s: a System.String
7075 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7078 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7080 MONO_REQ_GC_UNSAFE_MODE;
7082 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7087 * mono_string_to_utf16:
7090 * Return an null-terminated array of the utf-16 chars
7091 * contained in @s. The result must be freed with g_free().
7092 * This is a temporary helper until our string implementation
7093 * is reworked to always include the null terminating char.
7096 mono_string_to_utf16 (MonoString *s)
7098 MONO_REQ_GC_UNSAFE_MODE;
7105 as = (char *)g_malloc ((s->length * 2) + 2);
7106 as [(s->length * 2)] = '\0';
7107 as [(s->length * 2) + 1] = '\0';
7110 return (gunichar2 *)(as);
7113 memcpy (as, mono_string_chars(s), s->length * 2);
7114 return (gunichar2 *)(as);
7118 * mono_string_to_utf32:
7121 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7122 * contained in @s. The result must be freed with g_free().
7125 mono_string_to_utf32 (MonoString *s)
7127 MONO_REQ_GC_UNSAFE_MODE;
7129 mono_unichar4 *utf32_output = NULL;
7130 GError *error = NULL;
7131 glong items_written;
7136 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7139 g_error_free (error);
7141 return utf32_output;
7145 * mono_string_from_utf16:
7146 * @data: the UTF16 string (LPWSTR) to convert
7148 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7150 * Returns: a MonoString.
7153 mono_string_from_utf16 (gunichar2 *data)
7156 MonoString *result = mono_string_from_utf16_checked (data, &error);
7157 mono_error_cleanup (&error);
7162 * mono_string_from_utf16_checked:
7163 * @data: the UTF16 string (LPWSTR) to convert
7164 * @error: set on error
7166 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7168 * Returns: a MonoString. On failure sets @error and returns NULL.
7171 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7174 MONO_REQ_GC_UNSAFE_MODE;
7176 mono_error_init (error);
7177 MonoDomain *domain = mono_domain_get ();
7183 while (data [len]) len++;
7185 return mono_string_new_utf16_checked (domain, data, len, error);
7189 * mono_string_from_utf32:
7190 * @data: the UTF32 string (LPWSTR) to convert
7192 * Converts a UTF32 (UCS-4)to a MonoString.
7194 * Returns: a MonoString.
7197 mono_string_from_utf32 (mono_unichar4 *data)
7200 MonoString *result = mono_string_from_utf32_checked (data, &error);
7201 mono_error_cleanup (&error);
7206 * mono_string_from_utf32_checked:
7207 * @data: the UTF32 string (LPWSTR) to convert
7208 * @error: set on error
7210 * Converts a UTF32 (UCS-4)to a MonoString.
7212 * Returns: a MonoString. On failure returns NULL and sets @error.
7215 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7217 MONO_REQ_GC_UNSAFE_MODE;
7219 mono_error_init (error);
7220 MonoString* result = NULL;
7221 mono_unichar2 *utf16_output = NULL;
7222 GError *gerror = NULL;
7223 glong items_written;
7229 while (data [len]) len++;
7231 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7234 g_error_free (gerror);
7236 result = mono_string_from_utf16_checked (utf16_output, error);
7237 g_free (utf16_output);
7242 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7244 MONO_REQ_GC_UNSAFE_MODE;
7251 r = mono_string_to_utf8_ignore (s);
7253 r = mono_string_to_utf8_checked (s, error);
7254 if (!mono_error_ok (error))
7261 len = strlen (r) + 1;
7263 mp_s = (char *)mono_mempool_alloc (mp, len);
7265 mp_s = (char *)mono_image_alloc (image, len);
7267 memcpy (mp_s, r, len);
7275 * mono_string_to_utf8_image:
7276 * @s: a System.String
7278 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7281 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7283 MONO_REQ_GC_UNSAFE_MODE;
7285 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7289 * mono_string_to_utf8_mp:
7290 * @s: a System.String
7292 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7295 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7297 MONO_REQ_GC_UNSAFE_MODE;
7299 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7303 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7306 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7308 eh_callbacks = *cbs;
7311 MonoRuntimeExceptionHandlingCallbacks *
7312 mono_get_eh_callbacks (void)
7314 return &eh_callbacks;
7318 * mono_raise_exception:
7319 * @ex: exception object
7321 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7324 mono_raise_exception (MonoException *ex)
7326 MONO_REQ_GC_UNSAFE_MODE;
7329 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7330 * that will cause gcc to omit the function epilog, causing problems when
7331 * the JIT tries to walk the stack, since the return address on the stack
7332 * will point into the next function in the executable, not this one.
7334 eh_callbacks.mono_raise_exception (ex);
7338 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7340 MONO_REQ_GC_UNSAFE_MODE;
7342 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7346 * mono_wait_handle_new:
7347 * @domain: Domain where the object will be created
7348 * @handle: Handle for the wait handle
7349 * @error: set on error.
7351 * Returns: A new MonoWaitHandle created in the given domain for the
7352 * given handle. On failure returns NULL and sets @rror.
7355 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7357 MONO_REQ_GC_UNSAFE_MODE;
7359 MonoWaitHandle *res;
7360 gpointer params [1];
7361 static MonoMethod *handle_set;
7363 mono_error_init (error);
7364 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7365 return_val_if_nok (error, NULL);
7367 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7369 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7371 params [0] = &handle;
7373 mono_runtime_invoke_checked (handle_set, res, params, error);
7378 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7380 MONO_REQ_GC_UNSAFE_MODE;
7382 static MonoClassField *f_safe_handle = NULL;
7385 if (!f_safe_handle) {
7386 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7387 g_assert (f_safe_handle);
7390 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7396 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7398 MONO_REQ_GC_UNSAFE_MODE;
7400 RuntimeInvokeFunction runtime_invoke;
7402 mono_error_init (error);
7404 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7405 MonoMethod *method = mono_get_context_capture_method ();
7406 MonoMethod *wrapper;
7409 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7410 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7411 return_val_if_nok (error, NULL);
7412 domain->capture_context_method = mono_compile_method_checked (method, error);
7413 return_val_if_nok (error, NULL);
7416 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7418 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7421 * mono_async_result_new:
7422 * @domain:domain where the object will be created.
7423 * @handle: wait handle.
7424 * @state: state to pass to AsyncResult
7425 * @data: C closure data.
7426 * @error: set on error.
7428 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7429 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7430 * On failure returns NULL and sets @error.
7434 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7436 MONO_REQ_GC_UNSAFE_MODE;
7438 mono_error_init (error);
7439 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7440 return_val_if_nok (error, NULL);
7441 MonoObject *context = mono_runtime_capture_context (domain, error);
7442 return_val_if_nok (error, NULL);
7443 /* we must capture the execution context from the original thread */
7445 MONO_OBJECT_SETREF (res, execution_context, context);
7446 /* note: result may be null if the flow is suppressed */
7449 res->data = (void **)data;
7450 MONO_OBJECT_SETREF (res, object_data, object_data);
7451 MONO_OBJECT_SETREF (res, async_state, state);
7452 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7453 return_val_if_nok (error, NULL);
7455 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7457 res->sync_completed = FALSE;
7458 res->completed = FALSE;
7464 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7466 MONO_REQ_GC_UNSAFE_MODE;
7473 g_assert (ares->async_delegate);
7475 ac = (MonoAsyncCall*) ares->object_data;
7477 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7478 if (mono_error_set_pending_exception (&error))
7481 gpointer wait_event = NULL;
7483 ac->msg->exc = NULL;
7485 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7487 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7488 mono_threads_begin_abort_protected_block ();
7490 if (!ac->msg->exc) {
7491 MonoException *ex = mono_error_convert_to_exception (&error);
7492 ac->msg->exc = (MonoObject *)ex;
7494 mono_error_cleanup (&error);
7497 MONO_OBJECT_SETREF (ac, res, res);
7499 mono_monitor_enter ((MonoObject*) ares);
7500 ares->completed = 1;
7502 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7503 mono_monitor_exit ((MonoObject*) ares);
7505 if (wait_event != NULL)
7506 mono_w32event_set (wait_event);
7508 mono_error_init (&error); //the else branch would leave it in an undefined state
7510 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7512 mono_threads_end_abort_protected_block ();
7514 if (mono_error_set_pending_exception (&error))
7522 mono_message_init (MonoDomain *domain,
7523 MonoMethodMessage *this_obj,
7524 MonoReflectionMethod *method,
7525 MonoArray *out_args,
7528 MONO_REQ_GC_UNSAFE_MODE;
7530 static MonoMethod *init_message_method = NULL;
7532 if (!init_message_method) {
7533 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7534 g_assert (init_message_method != NULL);
7537 mono_error_init (error);
7538 /* FIXME set domain instead? */
7539 g_assert (domain == mono_domain_get ());
7546 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7547 return is_ok (error);
7550 #ifndef DISABLE_REMOTING
7552 * mono_remoting_invoke:
7553 * @real_proxy: pointer to a RealProxy object
7554 * @msg: The MonoMethodMessage to execute
7555 * @exc: used to store exceptions
7556 * @out_args: used to store output arguments
7558 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7559 * IMessage interface and it is not trivial to extract results from there. So
7560 * we call an helper method PrivateInvoke instead of calling
7561 * RealProxy::Invoke() directly.
7563 * Returns: the result object.
7566 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7568 MONO_REQ_GC_UNSAFE_MODE;
7571 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7576 mono_error_init (error);
7578 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7581 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7583 mono_error_set_not_supported (error, "Linked away.");
7586 real_proxy->vtable->domain->private_invoke_method = im;
7589 pa [0] = real_proxy;
7594 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7595 return_val_if_nok (error, NULL);
7602 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7603 MonoObject **exc, MonoArray **out_args, MonoError *error)
7605 MONO_REQ_GC_UNSAFE_MODE;
7607 static MonoClass *object_array_klass;
7608 mono_error_init (error);
7612 MonoMethodSignature *sig;
7614 int i, j, outarg_count = 0;
7616 #ifndef DISABLE_REMOTING
7617 if (target && mono_object_is_transparent_proxy (target)) {
7618 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7619 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7620 target = tp->rp->unwrapped_server;
7622 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7627 domain = mono_domain_get ();
7628 method = msg->method->method;
7629 sig = mono_method_signature (method);
7631 for (i = 0; i < sig->param_count; i++) {
7632 if (sig->params [i]->byref)
7636 if (!object_array_klass) {
7639 klass = mono_array_class_get (mono_defaults.object_class, 1);
7642 mono_memory_barrier ();
7643 object_array_klass = klass;
7646 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7647 return_val_if_nok (error, NULL);
7649 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7652 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7653 return_val_if_nok (error, NULL);
7655 for (i = 0, j = 0; i < sig->param_count; i++) {
7656 if (sig->params [i]->byref) {
7658 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7659 mono_array_setref (*out_args, j, arg);
7668 * prepare_to_string_method:
7670 * @target: Set to @obj or unboxed value if a valuetype
7672 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7675 prepare_to_string_method (MonoObject *obj, void **target)
7677 MONO_REQ_GC_UNSAFE_MODE;
7679 static MonoMethod *to_string = NULL;
7687 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7689 method = mono_object_get_virtual_method (obj, to_string);
7691 // Unbox value type if needed
7692 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7693 *target = mono_object_unbox (obj);
7699 * mono_object_to_string:
7701 * @exc: Any exception thrown by ToString (). May be NULL.
7703 * Returns: the result of calling ToString () on an object.
7706 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7709 MonoString *s = NULL;
7711 MonoMethod *method = prepare_to_string_method (obj, &target);
7713 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7714 if (*exc == NULL && !mono_error_ok (&error))
7715 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7717 mono_error_cleanup (&error);
7719 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7720 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7727 * mono_object_to_string_checked:
7729 * @error: Set on error.
7731 * Returns: the result of calling ToString () on an object. If the
7732 * method cannot be invoked or if it raises an exception, sets @error
7736 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7738 mono_error_init (error);
7740 MonoMethod *method = prepare_to_string_method (obj, &target);
7741 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7745 * mono_object_try_to_string:
7747 * @exc: Any exception thrown by ToString (). Must not be NULL.
7748 * @error: Set if method cannot be invoked.
7750 * Returns: the result of calling ToString () on an object. If the
7751 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7755 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7758 mono_error_init (error);
7760 MonoMethod *method = prepare_to_string_method (obj, &target);
7761 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7767 get_native_backtrace (MonoException *exc_raw)
7769 HANDLE_FUNCTION_ENTER ();
7770 MONO_HANDLE_DCL(MonoException, exc);
7771 char * trace = mono_exception_handle_get_native_backtrace (exc);
7772 HANDLE_FUNCTION_RETURN_VAL (trace);
7776 * mono_print_unhandled_exception:
7777 * @exc: The exception
7779 * Prints the unhandled exception.
7782 mono_print_unhandled_exception (MonoObject *exc)
7784 MONO_REQ_GC_UNSAFE_MODE;
7787 char *message = (char*)"";
7788 gboolean free_message = FALSE;
7791 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7792 message = g_strdup ("OutOfMemoryException");
7793 free_message = TRUE;
7794 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7795 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7796 free_message = TRUE;
7799 if (((MonoException*)exc)->native_trace_ips) {
7800 message = get_native_backtrace ((MonoException*)exc);
7801 free_message = TRUE;
7803 MonoObject *other_exc = NULL;
7804 str = mono_object_try_to_string (exc, &other_exc, &error);
7805 if (other_exc == NULL && !is_ok (&error))
7806 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7808 mono_error_cleanup (&error);
7810 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7811 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7813 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7814 original_backtrace, nested_backtrace);
7816 g_free (original_backtrace);
7817 g_free (nested_backtrace);
7818 free_message = TRUE;
7820 message = mono_string_to_utf8_checked (str, &error);
7821 if (!mono_error_ok (&error)) {
7822 mono_error_cleanup (&error);
7823 message = (char *) "";
7825 free_message = TRUE;
7832 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7833 * exc->vtable->klass->name, message);
7835 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7842 * mono_delegate_ctor_with_method:
7843 * @this: pointer to an uninitialized delegate object
7844 * @target: target object
7845 * @addr: pointer to native code
7847 * @error: set on error.
7849 * Initialize a delegate and sets a specific method, not the one
7850 * associated with addr. This is useful when sharing generic code.
7851 * In that case addr will most probably not be associated with the
7852 * correct instantiation of the method.
7853 * On failure returns FALSE and sets @error.
7856 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7858 MONO_REQ_GC_UNSAFE_MODE;
7860 mono_error_init (error);
7861 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7863 g_assert (this_obj);
7866 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7869 delegate->method = method;
7871 mono_stats.delegate_creations++;
7873 #ifndef DISABLE_REMOTING
7874 if (target && mono_object_is_transparent_proxy (target)) {
7876 method = mono_marshal_get_remoting_invoke (method);
7877 delegate->method_ptr = mono_compile_method_checked (method, error);
7878 return_val_if_nok (error, FALSE);
7879 MONO_OBJECT_SETREF (delegate, target, target);
7883 delegate->method_ptr = addr;
7884 MONO_OBJECT_SETREF (delegate, target, target);
7887 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7888 if (callbacks.init_delegate)
7889 callbacks.init_delegate (delegate);
7894 * mono_delegate_ctor:
7895 * @this: pointer to an uninitialized delegate object
7896 * @target: target object
7897 * @addr: pointer to native code
7898 * @error: set on error.
7900 * This is used to initialize a delegate.
7901 * On failure returns FALSE and sets @error.
7904 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7906 MONO_REQ_GC_UNSAFE_MODE;
7908 mono_error_init (error);
7909 MonoDomain *domain = mono_domain_get ();
7911 MonoMethod *method = NULL;
7915 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7917 if (!ji && domain != mono_get_root_domain ())
7918 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7920 method = mono_jit_info_get_method (ji);
7921 g_assert (!mono_class_is_gtd (method->klass));
7924 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7928 * mono_method_call_message_new:
7929 * @method: method to encapsulate
7930 * @params: parameters to the method
7931 * @invoke: optional, delegate invoke.
7932 * @cb: async callback delegate.
7933 * @state: state passed to the async callback.
7934 * @error: set on error.
7936 * Translates arguments pointers into a MonoMethodMessage.
7937 * On failure returns NULL and sets @error.
7940 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7941 MonoDelegate **cb, MonoObject **state, MonoError *error)
7943 MONO_REQ_GC_UNSAFE_MODE;
7945 mono_error_init (error);
7947 MonoDomain *domain = mono_domain_get ();
7948 MonoMethodSignature *sig = mono_method_signature (method);
7949 MonoMethodMessage *msg;
7952 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7953 return_val_if_nok (error, NULL);
7956 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7957 return_val_if_nok (error, NULL);
7958 mono_message_init (domain, msg, rm, NULL, error);
7959 return_val_if_nok (error, NULL);
7960 count = sig->param_count - 2;
7962 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7963 return_val_if_nok (error, NULL);
7964 mono_message_init (domain, msg, rm, NULL, error);
7965 return_val_if_nok (error, NULL);
7966 count = sig->param_count;
7969 for (i = 0; i < count; i++) {
7974 if (sig->params [i]->byref)
7975 vpos = *((gpointer *)params [i]);
7979 klass = mono_class_from_mono_type (sig->params [i]);
7981 if (klass->valuetype) {
7982 arg = mono_value_box_checked (domain, klass, vpos, error);
7983 return_val_if_nok (error, NULL);
7985 arg = *((MonoObject **)vpos);
7987 mono_array_setref (msg->args, i, arg);
7990 if (cb != NULL && state != NULL) {
7991 *cb = *((MonoDelegate **)params [i]);
7993 *state = *((MonoObject **)params [i]);
8000 * mono_method_return_message_restore:
8002 * Restore results from message based processing back to arguments pointers
8005 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8007 MONO_REQ_GC_UNSAFE_MODE;
8009 mono_error_init (error);
8011 MonoMethodSignature *sig = mono_method_signature (method);
8012 int i, j, type, size, out_len;
8014 if (out_args == NULL)
8016 out_len = mono_array_length (out_args);
8020 for (i = 0, j = 0; i < sig->param_count; i++) {
8021 MonoType *pt = sig->params [i];
8026 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8030 arg = (char *)mono_array_get (out_args, gpointer, j);
8033 g_assert (type != MONO_TYPE_VOID);
8035 if (MONO_TYPE_IS_REFERENCE (pt)) {
8036 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8039 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8040 size = mono_class_value_size (klass, NULL);
8041 if (klass->has_references)
8042 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8044 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8046 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8047 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8056 #ifndef DISABLE_REMOTING
8059 * mono_load_remote_field:
8060 * @this: pointer to an object
8061 * @klass: klass of the object containing @field
8062 * @field: the field to load
8063 * @res: a storage to store the result
8065 * This method is called by the runtime on attempts to load fields of
8066 * transparent proxy objects. @this points to such TP, @klass is the class of
8067 * the object containing @field. @res is a storage location which can be
8068 * used to store the result.
8070 * Returns: an address pointing to the value of field.
8073 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8076 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8077 mono_error_cleanup (&error);
8082 * mono_load_remote_field_checked:
8083 * @this: pointer to an object
8084 * @klass: klass of the object containing @field
8085 * @field: the field to load
8086 * @res: a storage to store the result
8087 * @error: set on error
8089 * This method is called by the runtime on attempts to load fields of
8090 * transparent proxy objects. @this points to such TP, @klass is the class of
8091 * the object containing @field. @res is a storage location which can be
8092 * used to store the result.
8094 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8097 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8099 MONO_REQ_GC_UNSAFE_MODE;
8101 static MonoMethod *getter = NULL;
8103 mono_error_init (error);
8105 MonoDomain *domain = mono_domain_get ();
8106 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8107 MonoClass *field_class;
8108 MonoMethodMessage *msg;
8109 MonoArray *out_args;
8113 g_assert (mono_object_is_transparent_proxy (this_obj));
8114 g_assert (res != NULL);
8116 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8117 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8122 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8124 mono_error_set_not_supported (error, "Linked away.");
8129 field_class = mono_class_from_mono_type (field->type);
8131 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8132 return_val_if_nok (error, NULL);
8133 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8134 return_val_if_nok (error, NULL);
8135 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8136 return_val_if_nok (error, NULL);
8137 mono_message_init (domain, msg, rm, out_args, error);
8138 return_val_if_nok (error, NULL);
8140 full_name = mono_type_get_full_name (klass);
8141 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8142 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8145 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8146 return_val_if_nok (error, NULL);
8149 mono_error_set_exception_instance (error, (MonoException *)exc);
8153 if (mono_array_length (out_args) == 0)
8156 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8158 if (field_class->valuetype) {
8159 return ((char *)*res) + sizeof (MonoObject);
8165 * mono_load_remote_field_new:
8170 * Missing documentation.
8173 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8177 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8178 mono_error_cleanup (&error);
8183 * mono_load_remote_field_new_checked:
8184 * @this: pointer to an object
8185 * @klass: klass of the object containing @field
8186 * @field: the field to load
8187 * @error: set on error.
8189 * This method is called by the runtime on attempts to load fields of
8190 * transparent proxy objects. @this points to such TP, @klass is the class of
8191 * the object containing @field.
8193 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8196 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8198 MONO_REQ_GC_UNSAFE_MODE;
8200 mono_error_init (error);
8202 static MonoMethod *tp_load = NULL;
8204 g_assert (mono_object_is_transparent_proxy (this_obj));
8207 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8209 mono_error_set_not_supported (error, "Linked away.");
8214 /* MonoType *type = mono_class_get_type (klass); */
8220 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8224 * mono_store_remote_field:
8225 * @this_obj: pointer to an object
8226 * @klass: klass of the object containing @field
8227 * @field: the field to load
8228 * @val: the value/object to store
8230 * This method is called by the runtime on attempts to store fields of
8231 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8232 * the object containing @field. @val is the new value to store in @field.
8235 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8238 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8239 mono_error_cleanup (&error);
8243 * mono_store_remote_field_checked:
8244 * @this_obj: pointer to an object
8245 * @klass: klass of the object containing @field
8246 * @field: the field to load
8247 * @val: the value/object to store
8248 * @error: set on error
8250 * This method is called by the runtime on attempts to store fields of
8251 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8252 * the object containing @field. @val is the new value to store in @field.
8254 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8257 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8260 MONO_REQ_GC_UNSAFE_MODE;
8262 mono_error_init (error);
8264 MonoDomain *domain = mono_domain_get ();
8265 MonoClass *field_class;
8268 g_assert (mono_object_is_transparent_proxy (this_obj));
8270 field_class = mono_class_from_mono_type (field->type);
8272 if (field_class->valuetype) {
8273 arg = mono_value_box_checked (domain, field_class, val, error);
8274 return_val_if_nok (error, FALSE);
8276 arg = *((MonoObject**)val);
8279 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8283 * mono_store_remote_field_new:
8289 * Missing documentation
8292 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8295 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8296 mono_error_cleanup (&error);
8300 * mono_store_remote_field_new_checked:
8307 * Missing documentation
8310 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8312 MONO_REQ_GC_UNSAFE_MODE;
8314 static MonoMethod *tp_store = NULL;
8316 mono_error_init (error);
8318 g_assert (mono_object_is_transparent_proxy (this_obj));
8321 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8323 mono_error_set_not_supported (error, "Linked away.");
8333 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8334 return is_ok (error);
8339 * mono_create_ftnptr:
8341 * Given a function address, create a function descriptor for it.
8342 * This is only needed on some platforms.
8345 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8347 return callbacks.create_ftnptr (domain, addr);
8351 * mono_get_addr_from_ftnptr:
8353 * Given a pointer to a function descriptor, return the function address.
8354 * This is only needed on some platforms.
8357 mono_get_addr_from_ftnptr (gpointer descr)
8359 return callbacks.get_addr_from_ftnptr (descr);
8363 * mono_string_chars:
8366 * Returns a pointer to the UCS16 characters stored in the MonoString
8369 mono_string_chars (MonoString *s)
8371 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8377 * mono_string_length:
8380 * Returns the lenght in characters of the string
8383 mono_string_length (MonoString *s)
8385 MONO_REQ_GC_UNSAFE_MODE;
8391 * mono_array_length:
8392 * @array: a MonoArray*
8394 * Returns the total number of elements in the array. This works for
8395 * both vectors and multidimensional arrays.
8398 mono_array_length (MonoArray *array)
8400 MONO_REQ_GC_UNSAFE_MODE;
8402 return array->max_length;
8406 * mono_array_addr_with_size:
8407 * @array: a MonoArray*
8408 * @size: size of the array elements
8409 * @idx: index into the array
8411 * Use this function to obtain the address for the @idx item on the
8412 * @array containing elements of size @size.
8414 * This method performs no bounds checking or type checking.
8416 * Returns the address of the @idx element in the array.
8419 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8421 MONO_REQ_GC_UNSAFE_MODE;
8423 return ((char*)(array)->vector) + size * idx;
8428 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8430 MonoDomain *domain = mono_domain_get ();
8434 mono_error_init (error);
8438 len = g_list_length (list);
8439 res = mono_array_new_checked (domain, eclass, len, error);
8440 return_val_if_nok (error, NULL);
8442 for (i = 0; list; list = list->next, i++)
8443 mono_array_set (res, gpointer, i, list->data);
8450 * The following section is purely to declare prototypes and
8451 * document the API, as these C files are processed by our
8457 * @array: array to alter
8458 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8459 * @index: index into the array
8460 * @value: value to set
8462 * Value Type version: This sets the @index's element of the @array
8463 * with elements of size sizeof(type) to the provided @value.
8465 * This macro does not attempt to perform type checking or bounds checking.
8467 * Use this to set value types in a `MonoArray`.
8469 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8474 * mono_array_setref:
8475 * @array: array to alter
8476 * @index: index into the array
8477 * @value: value to set
8479 * Reference Type version: This sets the @index's element of the
8480 * @array with elements of size sizeof(type) to the provided @value.
8482 * This macro does not attempt to perform type checking or bounds checking.
8484 * Use this to reference types in a `MonoArray`.
8486 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8492 * @array: array on which to operate on
8493 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8494 * @index: index into the array
8496 * Use this macro to retrieve the @index element of an @array and
8497 * extract the value assuming that the elements of the array match
8498 * the provided type value.
8500 * This method can be used with both arrays holding value types and
8501 * reference types. For reference types, the @type parameter should
8502 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8504 * This macro does not attempt to perform type checking or bounds checking.
8506 * Returns: The element at the @index position in the @array.
8508 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)