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) {
753 case MONO_TYPE_FNPTR:
755 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
760 if (klass->image != mono_defaults.corlib)
763 case MONO_TYPE_STRING:
764 case MONO_TYPE_SZARRAY:
765 case MONO_TYPE_CLASS:
766 case MONO_TYPE_OBJECT:
767 case MONO_TYPE_ARRAY:
768 g_assert ((field->offset % sizeof(gpointer)) == 0);
770 g_assert (pos < size || pos <= max_size);
771 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
772 *max_set = MAX (*max_set, pos);
774 case MONO_TYPE_GENERICINST:
775 if (!mono_type_generic_inst_is_valuetype (type)) {
776 g_assert ((field->offset % sizeof(gpointer)) == 0);
778 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
779 *max_set = MAX (*max_set, pos);
784 case MONO_TYPE_VALUETYPE: {
785 MonoClass *fclass = mono_class_from_mono_type (field->type);
786 if (fclass->has_references) {
787 /* remove the object header */
788 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
802 case MONO_TYPE_BOOLEAN:
806 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
817 * mono_class_compute_bitmap:
819 * Mono internal function to compute a bitmap of reference fields in a class.
822 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
824 MONO_REQ_GC_NEUTRAL_MODE;
826 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
831 * similar to the above, but sets the bits in the bitmap for any non-ref field
832 * and ignores static fields
835 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
837 MonoClassField *field;
842 max_size = class->instance_size / sizeof (gpointer);
843 if (max_size >= size) {
844 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
847 for (p = class; p != NULL; p = p->parent) {
848 gpointer iter = NULL;
849 while ((field = mono_class_get_fields (p, &iter))) {
852 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
854 /* FIXME: should not happen, flag as type load error */
855 if (field->type->byref)
858 pos = field->offset / sizeof (gpointer);
861 type = mono_type_get_underlying_type (field->type);
862 switch (type->type) {
863 #if SIZEOF_VOID_P == 8
867 case MONO_TYPE_FNPTR:
872 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
873 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
874 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
877 #if SIZEOF_VOID_P == 4
881 case MONO_TYPE_FNPTR:
886 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
887 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
888 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
894 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
895 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
896 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
899 case MONO_TYPE_BOOLEAN:
902 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
904 case MONO_TYPE_STRING:
905 case MONO_TYPE_SZARRAY:
906 case MONO_TYPE_CLASS:
907 case MONO_TYPE_OBJECT:
908 case MONO_TYPE_ARRAY:
910 case MONO_TYPE_GENERICINST:
911 if (!mono_type_generic_inst_is_valuetype (type)) {
916 case MONO_TYPE_VALUETYPE: {
917 MonoClass *fclass = mono_class_from_mono_type (field->type);
918 /* remove the object header */
919 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
923 g_assert_not_reached ();
932 * mono_class_insecure_overlapping:
933 * check if a class with explicit layout has references and non-references
934 * fields overlapping.
936 * Returns: TRUE if it is insecure to load the type.
939 mono_class_insecure_overlapping (MonoClass *klass)
943 gsize default_bitmap [4] = {0};
945 gsize default_nrbitmap [4] = {0};
946 int i, insecure = FALSE;
949 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
950 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
952 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
953 int idx = i % (sizeof (bitmap [0]) * 8);
954 if (bitmap [idx] & nrbitmap [idx]) {
959 if (bitmap != default_bitmap)
961 if (nrbitmap != default_nrbitmap)
964 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
972 ves_icall_string_alloc (int length)
975 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
976 mono_error_set_pending_exception (&error);
981 /* LOCKING: Acquires the loader lock */
983 mono_class_compute_gc_descriptor (MonoClass *klass)
985 MONO_REQ_GC_NEUTRAL_MODE;
989 gsize default_bitmap [4] = {0};
990 static gboolean gcj_inited = FALSE;
991 MonoGCDescriptor gc_descr;
996 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
997 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1000 mono_loader_unlock ();
1004 mono_class_init (klass);
1006 if (klass->gc_descr_inited)
1009 bitmap = default_bitmap;
1010 if (klass == mono_defaults.string_class) {
1011 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1012 } else if (klass->rank) {
1013 mono_class_compute_gc_descriptor (klass->element_class);
1014 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1016 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1017 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1018 class->name_space, class->name);*/
1020 /* remove the object header */
1021 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1022 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));
1023 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1024 class->name_space, class->name);*/
1025 if (bitmap != default_bitmap)
1029 /*static int count = 0;
1032 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1033 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1035 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1036 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1038 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1039 if (bitmap != default_bitmap)
1043 /* Publish the data */
1044 mono_loader_lock ();
1045 klass->gc_descr = gc_descr;
1046 mono_memory_barrier ();
1047 klass->gc_descr_inited = TRUE;
1048 mono_loader_unlock ();
1052 * field_is_special_static:
1053 * @fklass: The MonoClass to look up.
1054 * @field: The MonoClassField describing the field.
1056 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1057 * SPECIAL_STATIC_NONE otherwise.
1060 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1062 MONO_REQ_GC_NEUTRAL_MODE;
1065 MonoCustomAttrInfo *ainfo;
1067 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1068 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1071 for (i = 0; i < ainfo->num_attrs; ++i) {
1072 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1073 if (klass->image == mono_defaults.corlib) {
1074 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1075 mono_custom_attrs_free (ainfo);
1076 return SPECIAL_STATIC_THREAD;
1078 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1079 mono_custom_attrs_free (ainfo);
1080 return SPECIAL_STATIC_CONTEXT;
1084 mono_custom_attrs_free (ainfo);
1085 return SPECIAL_STATIC_NONE;
1088 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1089 #define mix(a,b,c) { \
1090 a -= c; a ^= rot(c, 4); c += b; \
1091 b -= a; b ^= rot(a, 6); a += c; \
1092 c -= b; c ^= rot(b, 8); b += a; \
1093 a -= c; a ^= rot(c,16); c += b; \
1094 b -= a; b ^= rot(a,19); a += c; \
1095 c -= b; c ^= rot(b, 4); b += a; \
1097 #define final(a,b,c) { \
1098 c ^= b; c -= rot(b,14); \
1099 a ^= c; a -= rot(c,11); \
1100 b ^= a; b -= rot(a,25); \
1101 c ^= b; c -= rot(b,16); \
1102 a ^= c; a -= rot(c,4); \
1103 b ^= a; b -= rot(a,14); \
1104 c ^= b; c -= rot(b,24); \
1108 * mono_method_get_imt_slot:
1110 * The IMT slot is embedded into AOTed code, so this must return the same value
1111 * for the same method across all executions. This means:
1112 * - pointers shouldn't be used as hash values.
1113 * - mono_metadata_str_hash () should be used for hashing strings.
1116 mono_method_get_imt_slot (MonoMethod *method)
1118 MONO_REQ_GC_NEUTRAL_MODE;
1120 MonoMethodSignature *sig;
1122 guint32 *hashes_start, *hashes;
1126 /* This can be used to stress tests the collision code */
1130 * We do this to simplify generic sharing. It will hurt
1131 * performance in cases where a class implements two different
1132 * instantiations of the same generic interface.
1133 * The code in build_imt_slots () depends on this.
1135 if (method->is_inflated)
1136 method = ((MonoMethodInflated*)method)->declaring;
1138 sig = mono_method_signature (method);
1139 hashes_count = sig->param_count + 4;
1140 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1141 hashes = hashes_start;
1143 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1144 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1145 method->klass->name_space, method->klass->name, method->name);
1148 /* Initialize hashes */
1149 hashes [0] = mono_metadata_str_hash (method->klass->name);
1150 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1151 hashes [2] = mono_metadata_str_hash (method->name);
1152 hashes [3] = mono_metadata_type_hash (sig->ret);
1153 for (i = 0; i < sig->param_count; i++) {
1154 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1157 /* Setup internal state */
1158 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1160 /* Handle most of the hashes */
1161 while (hashes_count > 3) {
1170 /* Handle the last 3 hashes (all the case statements fall through) */
1171 switch (hashes_count) {
1172 case 3 : c += hashes [2];
1173 case 2 : b += hashes [1];
1174 case 1 : a += hashes [0];
1176 case 0: /* nothing left to add */
1180 g_free (hashes_start);
1181 /* Report the result */
1182 return c % MONO_IMT_SIZE;
1191 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1192 MONO_REQ_GC_NEUTRAL_MODE;
1194 guint32 imt_slot = mono_method_get_imt_slot (method);
1195 MonoImtBuilderEntry *entry;
1197 if (slot_num >= 0 && imt_slot != slot_num) {
1198 /* we build just a single imt slot and this is not it */
1202 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1203 entry->key = method;
1204 entry->value.vtable_slot = vtable_slot;
1205 entry->next = imt_builder [imt_slot];
1206 if (imt_builder [imt_slot] != NULL) {
1207 entry->children = imt_builder [imt_slot]->children + 1;
1208 if (entry->children == 1) {
1209 mono_stats.imt_slots_with_collisions++;
1210 *imt_collisions_bitmap |= (1 << imt_slot);
1213 entry->children = 0;
1214 mono_stats.imt_used_slots++;
1216 imt_builder [imt_slot] = entry;
1219 char *method_name = mono_method_full_name (method, TRUE);
1220 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1221 method, method_name, imt_slot, vtable_slot, entry->children);
1222 g_free (method_name);
1229 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1231 MonoMethod *method = e->key;
1232 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1236 method->klass->name_space,
1237 method->klass->name,
1240 printf (" * %s: NULL\n", message);
1246 compare_imt_builder_entries (const void *p1, const void *p2) {
1247 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1248 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1250 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1254 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1256 MONO_REQ_GC_NEUTRAL_MODE;
1258 int count = end - start;
1259 int chunk_start = out_array->len;
1262 for (i = start; i < end; ++i) {
1263 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1264 item->key = sorted_array [i]->key;
1265 item->value = sorted_array [i]->value;
1266 item->has_target_code = sorted_array [i]->has_target_code;
1267 item->is_equals = TRUE;
1269 item->check_target_idx = out_array->len + 1;
1271 item->check_target_idx = 0;
1272 g_ptr_array_add (out_array, item);
1275 int middle = start + count / 2;
1276 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1278 item->key = sorted_array [middle]->key;
1279 item->is_equals = FALSE;
1280 g_ptr_array_add (out_array, item);
1281 imt_emit_ir (sorted_array, start, middle, out_array);
1282 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1288 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1289 MONO_REQ_GC_NEUTRAL_MODE;
1291 int number_of_entries = entries->children + 1;
1292 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1293 GPtrArray *result = g_ptr_array_new ();
1294 MonoImtBuilderEntry *current_entry;
1297 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1298 sorted_array [i] = current_entry;
1300 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1302 /*for (i = 0; i < number_of_entries; i++) {
1303 print_imt_entry (" sorted array:", sorted_array [i], i);
1306 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1308 g_free (sorted_array);
1313 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1315 MONO_REQ_GC_NEUTRAL_MODE;
1317 if (imt_builder_entry != NULL) {
1318 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1319 /* No collision, return the vtable slot contents */
1320 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1322 /* Collision, build the trampoline */
1323 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1326 result = imt_trampoline_builder (vtable, domain,
1327 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1328 for (i = 0; i < imt_ir->len; ++i)
1329 g_free (g_ptr_array_index (imt_ir, i));
1330 g_ptr_array_free (imt_ir, TRUE);
1342 static MonoImtBuilderEntry*
1343 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1346 * LOCKING: requires the loader and domain locks.
1350 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1352 MONO_REQ_GC_NEUTRAL_MODE;
1356 guint32 imt_collisions_bitmap = 0;
1357 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1358 int method_count = 0;
1359 gboolean record_method_count_for_max_collisions = FALSE;
1360 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1363 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1365 for (i = 0; i < klass->interface_offsets_count; ++i) {
1366 MonoClass *iface = klass->interfaces_packed [i];
1367 int interface_offset = klass->interface_offsets_packed [i];
1368 int method_slot_in_interface, vt_slot;
1370 if (mono_class_has_variant_generic_params (iface))
1371 has_variant_iface = TRUE;
1373 mono_class_setup_methods (iface);
1374 vt_slot = interface_offset;
1375 int mcount = mono_class_get_method_count (iface);
1376 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1379 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1381 * The imt slot of the method is the same as for its declaring method,
1382 * see the comment in mono_method_get_imt_slot (), so we can
1383 * avoid inflating methods which will be discarded by
1384 * add_imt_builder_entry anyway.
1386 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1387 if (mono_method_get_imt_slot (method) != slot_num) {
1392 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1393 if (method->is_generic) {
1394 has_generic_virtual = TRUE;
1399 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1400 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1405 if (extra_interfaces) {
1406 int interface_offset = klass->vtable_size;
1408 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1409 MonoClass* iface = (MonoClass *)list_item->data;
1410 int method_slot_in_interface;
1411 int mcount = mono_class_get_method_count (iface);
1412 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1413 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1415 if (method->is_generic)
1416 has_generic_virtual = TRUE;
1417 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1419 interface_offset += mcount;
1422 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1423 /* overwrite the imt slot only if we're building all the entries or if
1424 * we're building this specific one
1426 if (slot_num < 0 || i == slot_num) {
1427 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1430 if (imt_builder [i]) {
1431 MonoImtBuilderEntry *entry;
1433 /* Link entries with imt_builder [i] */
1434 for (entry = entries; entry->next; entry = entry->next) {
1436 MonoMethod *method = (MonoMethod*)entry->key;
1437 char *method_name = mono_method_full_name (method, TRUE);
1438 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1439 g_free (method_name);
1442 entry->next = imt_builder [i];
1443 entries->children += imt_builder [i]->children + 1;
1445 imt_builder [i] = entries;
1448 if (has_generic_virtual || has_variant_iface) {
1450 * There might be collisions later when the the trampoline is expanded.
1452 imt_collisions_bitmap |= (1 << i);
1455 * The IMT trampoline might be called with an instance of one of the
1456 * generic virtual methods, so has to fallback to the IMT trampoline.
1458 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1460 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1463 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1467 if (imt_builder [i] != NULL) {
1468 int methods_in_slot = imt_builder [i]->children + 1;
1469 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1470 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1471 record_method_count_for_max_collisions = TRUE;
1473 method_count += methods_in_slot;
1477 mono_stats.imt_number_of_methods += method_count;
1478 if (record_method_count_for_max_collisions) {
1479 mono_stats.imt_method_count_when_max_collisions = method_count;
1482 for (i = 0; i < MONO_IMT_SIZE; i++) {
1483 MonoImtBuilderEntry* entry = imt_builder [i];
1484 while (entry != NULL) {
1485 MonoImtBuilderEntry* next = entry->next;
1490 g_free (imt_builder);
1491 /* we OR the bitmap since we may build just a single imt slot at a time */
1492 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1496 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1497 MONO_REQ_GC_NEUTRAL_MODE;
1499 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1503 * mono_vtable_build_imt_slot:
1504 * @vtable: virtual object table struct
1505 * @imt_slot: slot in the IMT table
1507 * Fill the given @imt_slot in the IMT table of @vtable with
1508 * a trampoline or a trampoline for the case of collisions.
1509 * This is part of the internal mono API.
1511 * LOCKING: Take the domain lock.
1514 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1516 MONO_REQ_GC_NEUTRAL_MODE;
1518 gpointer *imt = (gpointer*)vtable;
1519 imt -= MONO_IMT_SIZE;
1520 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1522 /* no support for extra interfaces: the proxy objects will need
1523 * to build the complete IMT
1524 * Update and heck needs to ahppen inside the proper domain lock, as all
1525 * the changes made to a MonoVTable.
1527 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1528 mono_domain_lock (vtable->domain);
1529 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1530 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1531 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1532 mono_domain_unlock (vtable->domain);
1533 mono_loader_unlock ();
1536 #define THUNK_THRESHOLD 10
1539 * mono_method_alloc_generic_virtual_trampoline:
1541 * @size: size in bytes
1543 * Allocs size bytes to be used for the code of a generic virtual
1544 * trampoline. It's either allocated from the domain's code manager or
1545 * reused from a previously invalidated piece.
1547 * LOCKING: The domain lock must be held.
1550 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1552 MONO_REQ_GC_NEUTRAL_MODE;
1554 static gboolean inited = FALSE;
1555 static int generic_virtual_trampolines_size = 0;
1558 mono_counters_register ("Generic virtual trampoline bytes",
1559 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1562 generic_virtual_trampolines_size += size;
1564 return mono_domain_code_reserve (domain, size);
1567 typedef struct _GenericVirtualCase {
1571 struct _GenericVirtualCase *next;
1572 } GenericVirtualCase;
1575 * get_generic_virtual_entries:
1577 * Return IMT entries for the generic virtual method instances and
1578 * variant interface methods for vtable slot
1581 static MonoImtBuilderEntry*
1582 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1584 MONO_REQ_GC_NEUTRAL_MODE;
1586 GenericVirtualCase *list;
1587 MonoImtBuilderEntry *entries;
1589 mono_domain_lock (domain);
1590 if (!domain->generic_virtual_cases)
1591 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1593 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1596 for (; list; list = list->next) {
1597 MonoImtBuilderEntry *entry;
1599 if (list->count < THUNK_THRESHOLD)
1602 entry = g_new0 (MonoImtBuilderEntry, 1);
1603 entry->key = list->method;
1604 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1605 entry->has_target_code = 1;
1607 entry->children = entries->children + 1;
1608 entry->next = entries;
1612 mono_domain_unlock (domain);
1614 /* FIXME: Leaking memory ? */
1619 * mono_method_add_generic_virtual_invocation:
1621 * @vtable_slot: pointer to the vtable slot
1622 * @method: the inflated generic virtual method
1623 * @code: the method's code
1625 * Registers a call via unmanaged code to a generic virtual method
1626 * instantiation or variant interface method. If the number of calls reaches a threshold
1627 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1628 * virtual method trampoline.
1631 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1632 gpointer *vtable_slot,
1633 MonoMethod *method, gpointer code)
1635 MONO_REQ_GC_NEUTRAL_MODE;
1637 static gboolean inited = FALSE;
1638 static int num_added = 0;
1639 static int num_freed = 0;
1641 GenericVirtualCase *gvc, *list;
1642 MonoImtBuilderEntry *entries;
1646 mono_domain_lock (domain);
1647 if (!domain->generic_virtual_cases)
1648 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1651 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1652 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1656 /* Check whether the case was already added */
1657 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1660 if (gvc->method == method)
1665 /* If not found, make a new one */
1667 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1668 gvc->method = method;
1671 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1673 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1678 if (++gvc->count == THUNK_THRESHOLD) {
1679 gpointer *old_thunk = (void **)*vtable_slot;
1680 gpointer vtable_trampoline = NULL;
1681 gpointer imt_trampoline = NULL;
1683 if ((gpointer)vtable_slot < (gpointer)vtable) {
1684 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1685 int imt_slot = MONO_IMT_SIZE + displacement;
1687 /* Force the rebuild of the trampoline at the next call */
1688 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1689 *vtable_slot = imt_trampoline;
1691 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1693 entries = get_generic_virtual_entries (domain, vtable_slot);
1695 sorted = imt_sort_slot_entries (entries);
1697 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1701 MonoImtBuilderEntry *next = entries->next;
1706 for (i = 0; i < sorted->len; ++i)
1707 g_free (g_ptr_array_index (sorted, i));
1708 g_ptr_array_free (sorted, TRUE);
1710 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1715 mono_domain_unlock (domain);
1718 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1721 * mono_class_vtable:
1722 * @domain: the application domain
1723 * @class: the class to initialize
1725 * VTables are domain specific because we create domain specific code, and
1726 * they contain the domain specific static class data.
1727 * On failure, NULL is returned, and class->exception_type is set.
1730 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1733 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1734 mono_error_cleanup (&error);
1739 * mono_class_vtable_full:
1740 * @domain: the application domain
1741 * @class: the class to initialize
1742 * @error set on failure.
1744 * VTables are domain specific because we create domain specific code, and
1745 * they contain the domain specific static class data.
1748 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1750 MONO_REQ_GC_UNSAFE_MODE;
1752 MonoClassRuntimeInfo *runtime_info;
1754 mono_error_init (error);
1758 if (mono_class_has_failure (klass)) {
1759 mono_error_set_for_class_failure (error, klass);
1763 /* this check can be inlined in jitted code, too */
1764 runtime_info = klass->runtime_info;
1765 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1766 return runtime_info->domain_vtables [domain->domain_id];
1767 return mono_class_create_runtime_vtable (domain, klass, error);
1771 * mono_class_try_get_vtable:
1772 * @domain: the application domain
1773 * @class: the class to initialize
1775 * This function tries to get the associated vtable from @class if
1776 * it was already created.
1779 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1781 MONO_REQ_GC_NEUTRAL_MODE;
1783 MonoClassRuntimeInfo *runtime_info;
1787 runtime_info = klass->runtime_info;
1788 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1789 return runtime_info->domain_vtables [domain->domain_id];
1794 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1796 MONO_REQ_GC_NEUTRAL_MODE;
1798 size_t alloc_offset;
1801 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1802 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1803 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1805 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1806 g_assert ((imt_table_bytes & 7) == 4);
1813 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1817 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1819 MONO_REQ_GC_UNSAFE_MODE;
1822 MonoClassRuntimeInfo *runtime_info, *old_info;
1823 MonoClassField *field;
1825 int i, vtable_slots;
1826 size_t imt_table_bytes;
1828 guint32 vtable_size, class_size;
1830 gpointer *interface_offsets;
1832 mono_error_init (error);
1834 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1835 mono_domain_lock (domain);
1836 runtime_info = klass->runtime_info;
1837 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1838 mono_domain_unlock (domain);
1839 mono_loader_unlock ();
1840 return runtime_info->domain_vtables [domain->domain_id];
1842 if (!klass->inited || mono_class_has_failure (klass)) {
1843 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1844 mono_domain_unlock (domain);
1845 mono_loader_unlock ();
1846 mono_error_set_for_class_failure (error, klass);
1851 /* Array types require that their element type be valid*/
1852 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1853 MonoClass *element_class = klass->element_class;
1854 if (!element_class->inited)
1855 mono_class_init (element_class);
1857 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1858 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1859 mono_class_setup_vtable (element_class);
1861 if (mono_class_has_failure (element_class)) {
1862 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1863 if (!mono_class_has_failure (klass))
1864 mono_class_set_type_load_failure (klass, "");
1865 mono_domain_unlock (domain);
1866 mono_loader_unlock ();
1867 mono_error_set_for_class_failure (error, klass);
1873 * For some classes, mono_class_init () already computed klass->vtable_size, and
1874 * that is all that is needed because of the vtable trampolines.
1876 if (!klass->vtable_size)
1877 mono_class_setup_vtable (klass);
1879 if (mono_class_is_ginst (klass) && !klass->vtable)
1880 mono_class_check_vtable_constraints (klass, NULL);
1882 /* Initialize klass->has_finalize */
1883 mono_class_has_finalizer (klass);
1885 if (mono_class_has_failure (klass)) {
1886 mono_domain_unlock (domain);
1887 mono_loader_unlock ();
1888 mono_error_set_for_class_failure (error, klass);
1892 vtable_slots = klass->vtable_size;
1893 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1894 class_size = mono_class_data_size (klass);
1898 if (klass->interface_offsets_count) {
1899 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1900 mono_stats.imt_number_of_tables++;
1901 mono_stats.imt_tables_size += imt_table_bytes;
1903 imt_table_bytes = 0;
1906 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1908 mono_stats.used_class_count++;
1909 mono_stats.class_vtable_size += vtable_size;
1911 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1912 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1913 g_assert (!((gsize)vt & 7));
1916 vt->rank = klass->rank;
1917 vt->domain = domain;
1919 mono_class_compute_gc_descriptor (klass);
1921 * We can't use typed allocation in the non-root domains, since the
1922 * collector needs the GC descriptor stored in the vtable even after
1923 * the mempool containing the vtable is destroyed when the domain is
1924 * unloaded. An alternative might be to allocate vtables in the GC
1925 * heap, but this does not seem to work (it leads to crashes inside
1926 * libgc). If that approach is tried, two gc descriptors need to be
1927 * allocated for each class: one for the root domain, and one for all
1928 * other domains. The second descriptor should contain a bit for the
1929 * vtable field in MonoObject, since we can no longer assume the
1930 * vtable is reachable by other roots after the appdomain is unloaded.
1932 #ifdef HAVE_BOEHM_GC
1933 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1934 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1937 vt->gc_descr = klass->gc_descr;
1939 gc_bits = mono_gc_get_vtable_bits (klass);
1940 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1942 vt->gc_bits = gc_bits;
1945 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1946 if (klass->has_static_refs) {
1947 MonoGCDescriptor statics_gc_descr;
1949 gsize default_bitmap [4] = {0};
1952 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1953 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1954 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1955 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1956 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1957 if (bitmap != default_bitmap)
1960 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1962 vt->has_static_fields = TRUE;
1963 mono_stats.class_static_data_size += class_size;
1967 while ((field = mono_class_get_fields (klass, &iter))) {
1968 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1970 if (mono_field_is_deleted (field))
1972 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1973 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1974 if (special_static != SPECIAL_STATIC_NONE) {
1975 guint32 size, offset;
1977 gsize default_bitmap [4] = {0};
1982 if (mono_type_is_reference (field->type)) {
1983 default_bitmap [0] = 1;
1985 bitmap = default_bitmap;
1986 } else if (mono_type_is_struct (field->type)) {
1987 fclass = mono_class_from_mono_type (field->type);
1988 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1989 numbits = max_set + 1;
1991 default_bitmap [0] = 0;
1993 bitmap = default_bitmap;
1995 size = mono_type_size (field->type, &align);
1996 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
1997 if (!domain->special_static_fields)
1998 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1999 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2000 if (bitmap != default_bitmap)
2003 * This marks the field as special static to speed up the
2004 * checks in mono_field_static_get/set_value ().
2010 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2011 MonoClass *fklass = mono_class_from_mono_type (field->type);
2012 const char *data = mono_field_get_data (field);
2014 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2015 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2016 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2019 if (fklass->valuetype) {
2020 memcpy (t, data, mono_class_value_size (fklass, NULL));
2022 /* it's a pointer type: add check */
2023 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2030 vt->max_interface_id = klass->max_interface_id;
2031 vt->interface_bitmap = klass->interface_bitmap;
2033 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2034 // class->name, klass->interface_offsets_count);
2036 /* Initialize vtable */
2037 if (callbacks.get_vtable_trampoline) {
2038 // This also covers the AOT case
2039 for (i = 0; i < klass->vtable_size; ++i) {
2040 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2043 mono_class_setup_vtable (klass);
2045 for (i = 0; i < klass->vtable_size; ++i) {
2048 cm = klass->vtable [i];
2050 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2051 if (!is_ok (error)) {
2052 mono_domain_unlock (domain);
2053 mono_loader_unlock ();
2060 if (imt_table_bytes) {
2061 /* Now that the vtable is full, we can actually fill up the IMT */
2062 for (i = 0; i < MONO_IMT_SIZE; ++i)
2063 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2067 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2068 * re-acquire them and check if another thread has created the vtable in the meantime.
2070 /* Special case System.MonoType to avoid infinite recursion */
2071 if (klass != mono_defaults.runtimetype_class) {
2072 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2073 if (!is_ok (error)) {
2074 mono_domain_unlock (domain);
2075 mono_loader_unlock ();
2079 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2080 /* This is unregistered in
2081 unregister_vtable_reflection_type() in
2083 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2086 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2088 /* class_vtable_array keeps an array of created vtables
2090 g_ptr_array_add (domain->class_vtable_array, vt);
2091 /* klass->runtime_info is protected by the loader lock, both when
2092 * it it enlarged and when it is stored info.
2096 * Store the vtable in klass->runtime_info.
2097 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2099 mono_memory_barrier ();
2101 old_info = klass->runtime_info;
2102 if (old_info && old_info->max_domain >= domain->domain_id) {
2103 /* someone already created a large enough runtime info */
2104 old_info->domain_vtables [domain->domain_id] = vt;
2106 int new_size = domain->domain_id;
2108 new_size = MAX (new_size, old_info->max_domain);
2110 /* make the new size a power of two */
2112 while (new_size > i)
2115 /* this is a bounded memory retention issue: may want to
2116 * handle it differently when we'll have a rcu-like system.
2118 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2119 runtime_info->max_domain = new_size - 1;
2120 /* copy the stuff from the older info */
2122 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2124 runtime_info->domain_vtables [domain->domain_id] = vt;
2126 mono_memory_barrier ();
2127 klass->runtime_info = runtime_info;
2130 if (klass == mono_defaults.runtimetype_class) {
2131 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2132 if (!is_ok (error)) {
2133 mono_domain_unlock (domain);
2134 mono_loader_unlock ();
2138 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2139 /* This is unregistered in
2140 unregister_vtable_reflection_type() in
2142 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2145 mono_domain_unlock (domain);
2146 mono_loader_unlock ();
2148 /* make sure the parent is initialized */
2149 /*FIXME shouldn't this fail the current type?*/
2151 mono_class_vtable_full (domain, klass->parent, error);
2156 #ifndef DISABLE_REMOTING
2158 * mono_class_proxy_vtable:
2159 * @domain: the application domain
2160 * @remove_class: the remote class
2161 * @error: set on error
2163 * Creates a vtable for transparent proxies. It is basically
2164 * a copy of the real vtable of the class wrapped in @remote_class,
2165 * but all function pointers invoke the remoting functions, and
2166 * vtable->klass points to the transparent proxy class, and not to @class.
2168 * On failure returns NULL and sets @error
2171 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2173 MONO_REQ_GC_UNSAFE_MODE;
2175 MonoVTable *vt, *pvt;
2176 int i, j, vtsize, extra_interface_vtsize = 0;
2177 guint32 max_interface_id;
2179 GSList *extra_interfaces = NULL;
2180 MonoClass *klass = remote_class->proxy_class;
2181 gpointer *interface_offsets;
2182 uint8_t *bitmap = NULL;
2184 size_t imt_table_bytes;
2186 #ifdef COMPRESSED_INTERFACE_BITMAP
2190 mono_error_init (error);
2192 vt = mono_class_vtable (domain, klass);
2193 g_assert (vt); /*FIXME property handle failure*/
2194 max_interface_id = vt->max_interface_id;
2196 /* Calculate vtable space for extra interfaces */
2197 for (j = 0; j < remote_class->interface_count; j++) {
2198 MonoClass* iclass = remote_class->interfaces[j];
2202 /*FIXME test for interfaces with variant generic arguments*/
2203 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2204 continue; /* interface implemented by the class */
2205 if (g_slist_find (extra_interfaces, iclass))
2208 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2210 method_count = mono_class_num_methods (iclass);
2212 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2216 for (i = 0; i < ifaces->len; ++i) {
2217 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2218 /*FIXME test for interfaces with variant generic arguments*/
2219 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2220 continue; /* interface implemented by the class */
2221 if (g_slist_find (extra_interfaces, ic))
2223 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2224 method_count += mono_class_num_methods (ic);
2226 g_ptr_array_free (ifaces, TRUE);
2230 extra_interface_vtsize += method_count * sizeof (gpointer);
2231 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2234 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2235 mono_stats.imt_number_of_tables++;
2236 mono_stats.imt_tables_size += imt_table_bytes;
2238 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2240 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2242 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2243 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2244 g_assert (!((gsize)pvt & 7));
2246 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2248 pvt->klass = mono_defaults.transparent_proxy_class;
2249 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2250 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2252 /* initialize vtable */
2253 mono_class_setup_vtable (klass);
2254 for (i = 0; i < klass->vtable_size; ++i) {
2257 if ((cm = klass->vtable [i])) {
2258 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2262 pvt->vtable [i] = NULL;
2265 if (mono_class_is_abstract (klass)) {
2266 /* create trampolines for abstract methods */
2267 for (k = klass; k; k = k->parent) {
2269 gpointer iter = NULL;
2270 while ((m = mono_class_get_methods (k, &iter)))
2271 if (!pvt->vtable [m->slot]) {
2272 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2279 pvt->max_interface_id = max_interface_id;
2280 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2281 #ifdef COMPRESSED_INTERFACE_BITMAP
2282 bitmap = (uint8_t *)g_malloc0 (bsize);
2284 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2287 for (i = 0; i < klass->interface_offsets_count; ++i) {
2288 int interface_id = klass->interfaces_packed [i]->interface_id;
2289 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2292 if (extra_interfaces) {
2293 int slot = klass->vtable_size;
2299 /* Create trampolines for the methods of the interfaces */
2300 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2301 interf = (MonoClass *)list_item->data;
2303 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2307 while ((cm = mono_class_get_methods (interf, &iter))) {
2308 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2313 slot += mono_class_num_methods (interf);
2317 /* Now that the vtable is full, we can actually fill up the IMT */
2318 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2319 if (extra_interfaces) {
2320 g_slist_free (extra_interfaces);
2323 #ifdef COMPRESSED_INTERFACE_BITMAP
2324 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2325 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2326 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2329 pvt->interface_bitmap = bitmap;
2333 if (extra_interfaces)
2334 g_slist_free (extra_interfaces);
2335 #ifdef COMPRESSED_INTERFACE_BITMAP
2341 #endif /* DISABLE_REMOTING */
2344 * mono_class_field_is_special_static:
2346 * Returns whether @field is a thread/context static field.
2349 mono_class_field_is_special_static (MonoClassField *field)
2351 MONO_REQ_GC_NEUTRAL_MODE
2353 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2355 if (mono_field_is_deleted (field))
2357 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2358 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2365 * mono_class_field_get_special_static_type:
2366 * @field: The MonoClassField describing the field.
2368 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2369 * SPECIAL_STATIC_NONE otherwise.
2372 mono_class_field_get_special_static_type (MonoClassField *field)
2374 MONO_REQ_GC_NEUTRAL_MODE
2376 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2377 return SPECIAL_STATIC_NONE;
2378 if (mono_field_is_deleted (field))
2379 return SPECIAL_STATIC_NONE;
2380 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2381 return field_is_special_static (field->parent, field);
2382 return SPECIAL_STATIC_NONE;
2386 * mono_class_has_special_static_fields:
2388 * Returns whenever @klass has any thread/context static fields.
2391 mono_class_has_special_static_fields (MonoClass *klass)
2393 MONO_REQ_GC_NEUTRAL_MODE
2395 MonoClassField *field;
2399 while ((field = mono_class_get_fields (klass, &iter))) {
2400 g_assert (field->parent == klass);
2401 if (mono_class_field_is_special_static (field))
2408 #ifndef DISABLE_REMOTING
2410 * create_remote_class_key:
2411 * Creates an array of pointers that can be used as a hash key for a remote class.
2412 * The first element of the array is the number of pointers.
2415 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2417 MONO_REQ_GC_NEUTRAL_MODE;
2422 if (remote_class == NULL) {
2423 if (mono_class_is_interface (extra_class)) {
2424 key = (void **)g_malloc (sizeof(gpointer) * 3);
2425 key [0] = GINT_TO_POINTER (2);
2426 key [1] = mono_defaults.marshalbyrefobject_class;
2427 key [2] = extra_class;
2429 key = (void **)g_malloc (sizeof(gpointer) * 2);
2430 key [0] = GINT_TO_POINTER (1);
2431 key [1] = extra_class;
2434 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2435 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2436 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2437 key [1] = remote_class->proxy_class;
2439 // Keep the list of interfaces sorted
2440 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2441 if (extra_class && remote_class->interfaces [i] > extra_class) {
2442 key [j++] = extra_class;
2445 key [j] = remote_class->interfaces [i];
2448 key [j] = extra_class;
2450 // Replace the old class. The interface list is the same
2451 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2452 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2453 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2454 for (i = 0; i < remote_class->interface_count; i++)
2455 key [2 + i] = remote_class->interfaces [i];
2463 * copy_remote_class_key:
2465 * Make a copy of KEY in the domain and return the copy.
2468 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2470 MONO_REQ_GC_NEUTRAL_MODE
2472 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2473 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2475 memcpy (mp_key, key, key_size);
2481 * mono_remote_class:
2482 * @domain: the application domain
2483 * @class_name: name of the remote class
2484 * @error: set on error
2486 * Creates and initializes a MonoRemoteClass object for a remote type.
2488 * On failure returns NULL and sets @error
2491 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2493 MONO_REQ_GC_UNSAFE_MODE;
2495 MonoRemoteClass *rc;
2496 gpointer* key, *mp_key;
2499 mono_error_init (error);
2501 key = create_remote_class_key (NULL, proxy_class);
2503 mono_domain_lock (domain);
2504 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2508 mono_domain_unlock (domain);
2512 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2513 if (!is_ok (error)) {
2515 mono_domain_unlock (domain);
2519 mp_key = copy_remote_class_key (domain, key);
2523 if (mono_class_is_interface (proxy_class)) {
2524 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2525 rc->interface_count = 1;
2526 rc->interfaces [0] = proxy_class;
2527 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2529 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2530 rc->interface_count = 0;
2531 rc->proxy_class = proxy_class;
2534 rc->default_vtable = NULL;
2535 rc->xdomain_vtable = NULL;
2536 rc->proxy_class_name = name;
2537 #ifndef DISABLE_PERFCOUNTERS
2538 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2541 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2543 mono_domain_unlock (domain);
2548 * clone_remote_class:
2549 * Creates a copy of the remote_class, adding the provided class or interface
2551 static MonoRemoteClass*
2552 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2554 MONO_REQ_GC_NEUTRAL_MODE;
2556 MonoRemoteClass *rc;
2557 gpointer* key, *mp_key;
2559 key = create_remote_class_key (remote_class, extra_class);
2560 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2566 mp_key = copy_remote_class_key (domain, key);
2570 if (mono_class_is_interface (extra_class)) {
2572 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2573 rc->proxy_class = remote_class->proxy_class;
2574 rc->interface_count = remote_class->interface_count + 1;
2576 // Keep the list of interfaces sorted, since the hash key of
2577 // the remote class depends on this
2578 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2579 if (remote_class->interfaces [i] > extra_class && i == j)
2580 rc->interfaces [j++] = extra_class;
2581 rc->interfaces [j] = remote_class->interfaces [i];
2584 rc->interfaces [j] = extra_class;
2586 // Replace the old class. The interface array is the same
2587 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2588 rc->proxy_class = extra_class;
2589 rc->interface_count = remote_class->interface_count;
2590 if (rc->interface_count > 0)
2591 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2594 rc->default_vtable = NULL;
2595 rc->xdomain_vtable = NULL;
2596 rc->proxy_class_name = remote_class->proxy_class_name;
2598 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2604 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2606 MONO_REQ_GC_UNSAFE_MODE;
2608 mono_error_init (error);
2610 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2611 mono_domain_lock (domain);
2612 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2613 if (target_domain_id != -1) {
2614 if (remote_class->xdomain_vtable == NULL)
2615 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2616 mono_domain_unlock (domain);
2617 mono_loader_unlock ();
2618 return_val_if_nok (error, NULL);
2619 return remote_class->xdomain_vtable;
2621 if (remote_class->default_vtable == NULL) {
2622 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2623 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2625 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2626 MonoClass *klass = mono_class_from_mono_type (type);
2628 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)))
2629 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2632 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2633 /* N.B. both branches of the if modify error */
2634 if (!is_ok (error)) {
2635 mono_domain_unlock (domain);
2636 mono_loader_unlock ();
2641 mono_domain_unlock (domain);
2642 mono_loader_unlock ();
2643 return remote_class->default_vtable;
2647 * mono_upgrade_remote_class:
2648 * @domain: the application domain
2649 * @tproxy: the proxy whose remote class has to be upgraded.
2650 * @klass: class to which the remote class can be casted.
2651 * @error: set on error
2653 * Updates the vtable of the remote class by adding the necessary method slots
2654 * and interface offsets so it can be safely casted to klass. klass can be a
2655 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2658 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2660 MONO_REQ_GC_UNSAFE_MODE;
2662 mono_error_init (error);
2664 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2665 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2667 gboolean redo_vtable;
2668 if (mono_class_is_interface (klass)) {
2671 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2672 if (remote_class->interfaces [i] == klass)
2673 redo_vtable = FALSE;
2676 redo_vtable = (remote_class->proxy_class != klass);
2679 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2680 mono_domain_lock (domain);
2682 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2683 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2684 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2685 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2686 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2692 mono_domain_unlock (domain);
2693 mono_loader_unlock ();
2694 return is_ok (error);
2696 #endif /* DISABLE_REMOTING */
2700 * mono_object_get_virtual_method:
2701 * @obj: object to operate on.
2704 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2705 * the instance of a callvirt of method.
2708 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2710 MONO_REQ_GC_UNSAFE_MODE;
2711 HANDLE_FUNCTION_ENTER ();
2713 MONO_HANDLE_DCL (MonoObject, obj);
2714 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2715 mono_error_assert_ok (&error);
2716 HANDLE_FUNCTION_RETURN_VAL (result);
2720 * mono_object_get_virtual_method:
2721 * @obj: object to operate on.
2724 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2725 * the instance of a callvirt of method.
2728 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2730 mono_error_init (error);
2732 gboolean is_proxy = FALSE;
2733 MonoClass *klass = mono_handle_class (obj);
2734 if (mono_class_is_transparent_proxy (klass)) {
2735 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2736 klass = remote_class->proxy_class;
2739 return class_get_virtual_method (klass, method, is_proxy, error);
2743 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2745 mono_error_init (error);
2748 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2751 mono_class_setup_vtable (klass);
2752 MonoMethod **vtable = klass->vtable;
2754 if (method->slot == -1) {
2755 /* method->slot might not be set for instances of generic methods */
2756 if (method->is_inflated) {
2757 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2758 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2761 g_assert_not_reached ();
2765 MonoMethod *res = NULL;
2766 /* check method->slot is a valid index: perform isinstance? */
2767 if (method->slot != -1) {
2768 if (mono_class_is_interface (method->klass)) {
2770 gboolean variance_used = FALSE;
2771 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2772 g_assert (iface_offset > 0);
2773 res = vtable [iface_offset + method->slot];
2776 res = vtable [method->slot];
2780 #ifndef DISABLE_REMOTING
2782 /* It may be an interface, abstract class method or generic method */
2783 if (!res || mono_method_signature (res)->generic_param_count)
2786 /* generic methods demand invoke_with_check */
2787 if (mono_method_signature (res)->generic_param_count)
2788 res = mono_marshal_get_remoting_invoke_with_check (res);
2791 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2792 res = mono_cominterop_get_invoke (res);
2795 res = mono_marshal_get_remoting_invoke (res);
2800 if (method->is_inflated) {
2801 /* Have to inflate the result */
2802 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2810 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2812 MONO_REQ_GC_UNSAFE_MODE;
2814 MonoObject *result = NULL;
2816 g_assert (callbacks.runtime_invoke);
2818 mono_error_init (error);
2820 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2821 mono_profiler_method_start_invoke (method);
2823 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2825 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2826 mono_profiler_method_end_invoke (method);
2828 if (!mono_error_ok (error))
2835 * mono_runtime_invoke:
2836 * @method: method to invoke
2837 * @obJ: object instance
2838 * @params: arguments to the method
2839 * @exc: exception information.
2841 * Invokes the method represented by @method on the object @obj.
2843 * obj is the 'this' pointer, it should be NULL for static
2844 * methods, a MonoObject* for object instances and a pointer to
2845 * the value type for value types.
2847 * The params array contains the arguments to the method with the
2848 * same convention: MonoObject* pointers for object instances and
2849 * pointers to the value type otherwise.
2851 * From unmanaged code you'll usually use the
2852 * mono_runtime_invoke() variant.
2854 * Note that this function doesn't handle virtual methods for
2855 * you, it will exec the exact method you pass: we still need to
2856 * expose a function to lookup the derived class implementation
2857 * of a virtual method (there are examples of this in the code,
2860 * You can pass NULL as the exc argument if you don't want to
2861 * catch exceptions, otherwise, *exc will be set to the exception
2862 * thrown, if any. if an exception is thrown, you can't use the
2863 * MonoObject* result from the function.
2865 * If the method returns a value type, it is boxed in an object
2869 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2874 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2875 if (*exc == NULL && !mono_error_ok(&error)) {
2876 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2878 mono_error_cleanup (&error);
2880 res = mono_runtime_invoke_checked (method, obj, params, &error);
2881 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2887 * mono_runtime_try_invoke:
2888 * @method: method to invoke
2889 * @obJ: object instance
2890 * @params: arguments to the method
2891 * @exc: exception information.
2892 * @error: set on error
2894 * Invokes the method represented by @method on the object @obj.
2896 * obj is the 'this' pointer, it should be NULL for static
2897 * methods, a MonoObject* for object instances and a pointer to
2898 * the value type for value types.
2900 * The params array contains the arguments to the method with the
2901 * same convention: MonoObject* pointers for object instances and
2902 * pointers to the value type otherwise.
2904 * From unmanaged code you'll usually use the
2905 * mono_runtime_invoke() variant.
2907 * Note that this function doesn't handle virtual methods for
2908 * you, it will exec the exact method you pass: we still need to
2909 * expose a function to lookup the derived class implementation
2910 * of a virtual method (there are examples of this in the code,
2913 * For this function, you must not pass NULL as the exc argument if
2914 * you don't want to catch exceptions, use
2915 * mono_runtime_invoke_checked(). If an exception is thrown, you
2916 * can't use the MonoObject* result from the function.
2918 * If this method cannot be invoked, @error will be set and @exc and
2919 * the return value must not be used.
2921 * If the method returns a value type, it is boxed in an object
2925 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2927 MONO_REQ_GC_UNSAFE_MODE;
2929 g_assert (exc != NULL);
2931 if (mono_runtime_get_no_exec ())
2932 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2934 return do_runtime_invoke (method, obj, params, exc, error);
2938 * mono_runtime_invoke_checked:
2939 * @method: method to invoke
2940 * @obJ: object instance
2941 * @params: arguments to the method
2942 * @error: set on error
2944 * Invokes the method represented by @method on the object @obj.
2946 * obj is the 'this' pointer, it should be NULL for static
2947 * methods, a MonoObject* for object instances and a pointer to
2948 * the value type for value types.
2950 * The params array contains the arguments to the method with the
2951 * same convention: MonoObject* pointers for object instances and
2952 * pointers to the value type otherwise.
2954 * From unmanaged code you'll usually use the
2955 * mono_runtime_invoke() variant.
2957 * Note that this function doesn't handle virtual methods for
2958 * you, it will exec the exact method you pass: we still need to
2959 * expose a function to lookup the derived class implementation
2960 * of a virtual method (there are examples of this in the code,
2963 * If an exception is thrown, you can't use the MonoObject* result
2964 * from the function.
2966 * If this method cannot be invoked, @error will be set. If the
2967 * method throws an exception (and we're in coop mode) the exception
2968 * will be set in @error.
2970 * If the method returns a value type, it is boxed in an object
2974 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2976 MONO_REQ_GC_UNSAFE_MODE;
2978 if (mono_runtime_get_no_exec ())
2979 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2981 return do_runtime_invoke (method, obj, params, NULL, error);
2985 * mono_method_get_unmanaged_thunk:
2986 * @method: method to generate a thunk for.
2988 * Returns an unmanaged->managed thunk that can be used to call
2989 * a managed method directly from C.
2991 * The thunk's C signature closely matches the managed signature:
2993 * C#: public bool Equals (object obj);
2994 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2995 * MonoObject*, MonoException**);
2997 * The 1st ("this") parameter must not be used with static methods:
2999 * C#: public static bool ReferenceEquals (object a, object b);
3000 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3003 * The last argument must be a non-null pointer of a MonoException* pointer.
3004 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3005 * exception has been thrown in managed code. Otherwise it will point
3006 * to the MonoException* caught by the thunk. In this case, the result of
3007 * the thunk is undefined:
3009 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3010 * MonoException *ex = NULL;
3011 * Equals func = mono_method_get_unmanaged_thunk (method);
3012 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3014 * // handle exception
3017 * The calling convention of the thunk matches the platform's default
3018 * convention. This means that under Windows, C declarations must
3019 * contain the __stdcall attribute:
3021 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3022 * MonoObject*, MonoException**);
3026 * Value type arguments and return values are treated as they were objects:
3028 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3029 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3031 * Arguments must be properly boxed upon trunk's invocation, while return
3032 * values must be unboxed.
3035 mono_method_get_unmanaged_thunk (MonoMethod *method)
3037 MONO_REQ_GC_NEUTRAL_MODE;
3038 MONO_REQ_API_ENTRYPOINT;
3043 g_assert (!mono_threads_is_coop_enabled ());
3045 MONO_ENTER_GC_UNSAFE;
3046 method = mono_marshal_get_thunk_invoke_wrapper (method);
3047 res = mono_compile_method_checked (method, &error);
3048 mono_error_cleanup (&error);
3049 MONO_EXIT_GC_UNSAFE;
3055 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3057 MONO_REQ_GC_UNSAFE_MODE;
3061 /* object fields cannot be byref, so we don't need a
3063 gpointer *p = (gpointer*)dest;
3070 case MONO_TYPE_BOOLEAN:
3072 case MONO_TYPE_U1: {
3073 guint8 *p = (guint8*)dest;
3074 *p = value ? *(guint8*)value : 0;
3079 case MONO_TYPE_CHAR: {
3080 guint16 *p = (guint16*)dest;
3081 *p = value ? *(guint16*)value : 0;
3084 #if SIZEOF_VOID_P == 4
3089 case MONO_TYPE_U4: {
3090 gint32 *p = (gint32*)dest;
3091 *p = value ? *(gint32*)value : 0;
3094 #if SIZEOF_VOID_P == 8
3099 case MONO_TYPE_U8: {
3100 gint64 *p = (gint64*)dest;
3101 *p = value ? *(gint64*)value : 0;
3104 case MONO_TYPE_R4: {
3105 float *p = (float*)dest;
3106 *p = value ? *(float*)value : 0;
3109 case MONO_TYPE_R8: {
3110 double *p = (double*)dest;
3111 *p = value ? *(double*)value : 0;
3114 case MONO_TYPE_STRING:
3115 case MONO_TYPE_SZARRAY:
3116 case MONO_TYPE_CLASS:
3117 case MONO_TYPE_OBJECT:
3118 case MONO_TYPE_ARRAY:
3119 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3121 case MONO_TYPE_FNPTR:
3122 case MONO_TYPE_PTR: {
3123 gpointer *p = (gpointer*)dest;
3124 *p = deref_pointer? *(gpointer*)value: value;
3127 case MONO_TYPE_VALUETYPE:
3128 /* note that 't' and 'type->type' can be different */
3129 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3130 t = mono_class_enum_basetype (type->data.klass)->type;
3133 MonoClass *klass = mono_class_from_mono_type (type);
3134 int size = mono_class_value_size (klass, NULL);
3136 mono_gc_bzero_atomic (dest, size);
3138 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3141 case MONO_TYPE_GENERICINST:
3142 t = type->data.generic_class->container_class->byval_arg.type;
3145 g_error ("got type %x", type->type);
3150 * mono_field_set_value:
3151 * @obj: Instance object
3152 * @field: MonoClassField describing the field to set
3153 * @value: The value to be set
3155 * Sets the value of the field described by @field in the object instance @obj
3156 * to the value passed in @value. This method should only be used for instance
3157 * fields. For static fields, use mono_field_static_set_value.
3159 * The value must be on the native format of the field type.
3162 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3164 MONO_REQ_GC_UNSAFE_MODE;
3168 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3170 dest = (char*)obj + field->offset;
3171 mono_copy_value (field->type, dest, value, FALSE);
3175 * mono_field_static_set_value:
3176 * @field: MonoClassField describing the field to set
3177 * @value: The value to be set
3179 * Sets the value of the static field described by @field
3180 * to the value passed in @value.
3182 * The value must be on the native format of the field type.
3185 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3187 MONO_REQ_GC_UNSAFE_MODE;
3191 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3192 /* you cant set a constant! */
3193 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3195 if (field->offset == -1) {
3196 /* Special static */
3199 mono_domain_lock (vt->domain);
3200 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3201 mono_domain_unlock (vt->domain);
3202 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3204 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3206 mono_copy_value (field->type, dest, value, FALSE);
3210 * mono_vtable_get_static_field_data:
3212 * Internal use function: return a pointer to the memory holding the static fields
3213 * for a class or NULL if there are no static fields.
3214 * This is exported only for use by the debugger.
3217 mono_vtable_get_static_field_data (MonoVTable *vt)
3219 MONO_REQ_GC_NEUTRAL_MODE
3221 if (!vt->has_static_fields)
3223 return vt->vtable [vt->klass->vtable_size];
3227 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3229 MONO_REQ_GC_UNSAFE_MODE;
3233 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3234 if (field->offset == -1) {
3235 /* Special static */
3238 mono_domain_lock (vt->domain);
3239 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3240 mono_domain_unlock (vt->domain);
3241 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3243 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3246 src = (guint8*)obj + field->offset;
3253 * mono_field_get_value:
3254 * @obj: Object instance
3255 * @field: MonoClassField describing the field to fetch information from
3256 * @value: pointer to the location where the value will be stored
3258 * Use this routine to get the value of the field @field in the object
3261 * The pointer provided by value must be of the field type, for reference
3262 * types this is a MonoObject*, for value types its the actual pointer to
3267 * mono_field_get_value (obj, int_field, &i);
3270 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3272 MONO_REQ_GC_UNSAFE_MODE;
3278 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3280 src = (char*)obj + field->offset;
3281 mono_copy_value (field->type, value, src, TRUE);
3285 * mono_field_get_value_object:
3286 * @domain: domain where the object will be created (if boxing)
3287 * @field: MonoClassField describing the field to fetch information from
3288 * @obj: The object instance for the field.
3290 * Returns: a new MonoObject with the value from the given field. If the
3291 * field represents a value type, the value is boxed.
3295 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3298 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3299 mono_error_assert_ok (&error);
3304 * mono_field_get_value_object_checked:
3305 * @domain: domain where the object will be created (if boxing)
3306 * @field: MonoClassField describing the field to fetch information from
3307 * @obj: The object instance for the field.
3308 * @error: Set on error.
3310 * Returns: a new MonoObject with the value from the given field. If the
3311 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3315 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3317 MONO_REQ_GC_UNSAFE_MODE;
3319 mono_error_init (error);
3323 MonoVTable *vtable = NULL;
3325 gboolean is_static = FALSE;
3326 gboolean is_ref = FALSE;
3327 gboolean is_literal = FALSE;
3328 gboolean is_ptr = FALSE;
3329 MonoType *type = mono_field_get_type_checked (field, error);
3331 return_val_if_nok (error, NULL);
3333 switch (type->type) {
3334 case MONO_TYPE_STRING:
3335 case MONO_TYPE_OBJECT:
3336 case MONO_TYPE_CLASS:
3337 case MONO_TYPE_ARRAY:
3338 case MONO_TYPE_SZARRAY:
3343 case MONO_TYPE_BOOLEAN:
3346 case MONO_TYPE_CHAR:
3355 case MONO_TYPE_VALUETYPE:
3356 is_ref = type->byref;
3358 case MONO_TYPE_GENERICINST:
3359 is_ref = !mono_type_generic_inst_is_valuetype (type);
3365 g_error ("type 0x%x not handled in "
3366 "mono_field_get_value_object", type->type);
3370 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3373 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3377 vtable = mono_class_vtable_full (domain, field->parent, error);
3378 return_val_if_nok (error, NULL);
3380 if (!vtable->initialized) {
3381 mono_runtime_class_init_full (vtable, error);
3382 return_val_if_nok (error, NULL);
3391 get_default_field_value (domain, field, &o, error);
3392 return_val_if_nok (error, NULL);
3393 } else if (is_static) {
3394 mono_field_static_get_value_checked (vtable, field, &o, error);
3395 return_val_if_nok (error, NULL);
3397 mono_field_get_value (obj, field, &o);
3403 static MonoMethod *m;
3409 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3410 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3416 get_default_field_value (domain, field, v, error);
3417 return_val_if_nok (error, NULL);
3418 } else if (is_static) {
3419 mono_field_static_get_value_checked (vtable, field, v, error);
3420 return_val_if_nok (error, NULL);
3422 mono_field_get_value (obj, field, v);
3425 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3426 args [0] = ptr ? *ptr : NULL;
3427 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3428 return_val_if_nok (error, NULL);
3430 o = mono_runtime_invoke_checked (m, NULL, args, error);
3431 return_val_if_nok (error, NULL);
3436 /* boxed value type */
3437 klass = mono_class_from_mono_type (type);
3439 if (mono_class_is_nullable (klass))
3440 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3442 o = mono_object_new_checked (domain, klass, error);
3443 return_val_if_nok (error, NULL);
3444 v = ((gchar *) o) + sizeof (MonoObject);
3447 get_default_field_value (domain, field, v, error);
3448 return_val_if_nok (error, NULL);
3449 } else if (is_static) {
3450 mono_field_static_get_value_checked (vtable, field, v, error);
3451 return_val_if_nok (error, NULL);
3453 mono_field_get_value (obj, field, v);
3460 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3462 MONO_REQ_GC_UNSAFE_MODE;
3464 mono_error_init (error);
3466 const char *p = blob;
3467 mono_metadata_decode_blob_size (p, &p);
3470 case MONO_TYPE_BOOLEAN:
3473 *(guint8 *) value = *p;
3475 case MONO_TYPE_CHAR:
3478 *(guint16*) value = read16 (p);
3482 *(guint32*) value = read32 (p);
3486 *(guint64*) value = read64 (p);
3489 readr4 (p, (float*) value);
3492 readr8 (p, (double*) value);
3494 case MONO_TYPE_STRING:
3495 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3497 case MONO_TYPE_CLASS:
3498 *(gpointer*) value = NULL;
3502 g_warning ("type 0x%02x should not be in constant table", type);
3508 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3510 MONO_REQ_GC_NEUTRAL_MODE;
3512 MonoTypeEnum def_type;
3515 mono_error_init (error);
3517 data = mono_class_get_field_default_value (field, &def_type);
3518 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3522 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3524 MONO_REQ_GC_UNSAFE_MODE;
3528 mono_error_init (error);
3530 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3532 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3533 get_default_field_value (vt->domain, field, value, error);
3537 if (field->offset == -1) {
3538 /* Special static */
3539 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3540 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3542 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3544 mono_copy_value (field->type, value, src, TRUE);
3548 * mono_field_static_get_value:
3549 * @vt: vtable to the object
3550 * @field: MonoClassField describing the field to fetch information from
3551 * @value: where the value is returned
3553 * Use this routine to get the value of the static field @field value.
3555 * The pointer provided by value must be of the field type, for reference
3556 * types this is a MonoObject*, for value types its the actual pointer to
3561 * mono_field_static_get_value (vt, int_field, &i);
3564 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3566 MONO_REQ_GC_NEUTRAL_MODE;
3569 mono_field_static_get_value_checked (vt, field, value, &error);
3570 mono_error_cleanup (&error);
3574 * mono_field_static_get_value_checked:
3575 * @vt: vtable to the object
3576 * @field: MonoClassField describing the field to fetch information from
3577 * @value: where the value is returned
3578 * @error: set on error
3580 * Use this routine to get the value of the static field @field value.
3582 * The pointer provided by value must be of the field type, for reference
3583 * types this is a MonoObject*, for value types its the actual pointer to
3588 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3589 * if (!is_ok (error)) { ... }
3591 * On failure sets @error.
3594 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3596 MONO_REQ_GC_NEUTRAL_MODE;
3598 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3602 * mono_property_set_value:
3603 * @prop: MonoProperty to set
3604 * @obj: instance object on which to act
3605 * @params: parameters to pass to the propery
3606 * @exc: optional exception
3608 * Invokes the property's set method with the given arguments on the
3609 * object instance obj (or NULL for static properties).
3611 * You can pass NULL as the exc argument if you don't want to
3612 * catch exceptions, otherwise, *exc will be set to the exception
3613 * thrown, if any. if an exception is thrown, you can't use the
3614 * MonoObject* result from the function.
3617 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3619 MONO_REQ_GC_UNSAFE_MODE;
3622 do_runtime_invoke (prop->set, obj, params, exc, &error);
3623 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3624 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3626 mono_error_cleanup (&error);
3631 * mono_property_set_value_checked:
3632 * @prop: MonoProperty to set
3633 * @obj: instance object on which to act
3634 * @params: parameters to pass to the propery
3635 * @error: set on error
3637 * Invokes the property's set method with the given arguments on the
3638 * object instance obj (or NULL for static properties).
3640 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3641 * If an exception is thrown, it will be caught and returned via @error.
3644 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3646 MONO_REQ_GC_UNSAFE_MODE;
3650 mono_error_init (error);
3651 do_runtime_invoke (prop->set, obj, params, &exc, error);
3652 if (exc != NULL && is_ok (error))
3653 mono_error_set_exception_instance (error, (MonoException*)exc);
3654 return is_ok (error);
3658 * mono_property_get_value:
3659 * @prop: MonoProperty to fetch
3660 * @obj: instance object on which to act
3661 * @params: parameters to pass to the propery
3662 * @exc: optional exception
3664 * Invokes the property's get method with the given arguments on the
3665 * object instance obj (or NULL for static properties).
3667 * You can pass NULL as the exc argument if you don't want to
3668 * catch exceptions, otherwise, *exc will be set to the exception
3669 * thrown, if any. if an exception is thrown, you can't use the
3670 * MonoObject* result from the function.
3672 * Returns: the value from invoking the get method on the property.
3675 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3677 MONO_REQ_GC_UNSAFE_MODE;
3680 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3681 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3682 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3684 mono_error_cleanup (&error); /* FIXME don't raise here */
3691 * mono_property_get_value_checked:
3692 * @prop: MonoProperty to fetch
3693 * @obj: instance object on which to act
3694 * @params: parameters to pass to the propery
3695 * @error: set on error
3697 * Invokes the property's get method with the given arguments on the
3698 * object instance obj (or NULL for static properties).
3700 * If an exception is thrown, you can't use the
3701 * MonoObject* result from the function. The exception will be propagated via @error.
3703 * Returns: the value from invoking the get method on the property. On
3704 * failure returns NULL and sets @error.
3707 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3709 MONO_REQ_GC_UNSAFE_MODE;
3712 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3713 if (exc != NULL && !is_ok (error))
3714 mono_error_set_exception_instance (error, (MonoException*) exc);
3722 * mono_nullable_init:
3723 * @buf: The nullable structure to initialize.
3724 * @value: the value to initialize from
3725 * @klass: the type for the object
3727 * Initialize the nullable structure pointed to by @buf from @value which
3728 * should be a boxed value type. The size of @buf should be able to hold
3729 * as much data as the @klass->instance_size (which is the number of bytes
3730 * that will be copies).
3732 * Since Nullables have variable structure, we can not define a C
3733 * structure for them.
3736 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3738 MONO_REQ_GC_UNSAFE_MODE;
3740 MonoClass *param_class = klass->cast_class;
3742 mono_class_setup_fields (klass);
3743 g_assert (klass->fields_inited);
3745 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3746 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3748 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3750 if (param_class->has_references)
3751 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3753 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3755 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3760 * mono_nullable_box:
3761 * @buf: The buffer representing the data to be boxed
3762 * @klass: the type to box it as.
3763 * @error: set on oerr
3765 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3766 * @buf. On failure returns NULL and sets @error
3769 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3771 MONO_REQ_GC_UNSAFE_MODE;
3773 mono_error_init (error);
3774 MonoClass *param_class = klass->cast_class;
3776 mono_class_setup_fields (klass);
3777 g_assert (klass->fields_inited);
3779 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3780 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3782 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3783 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3784 return_val_if_nok (error, NULL);
3785 if (param_class->has_references)
3786 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3788 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3796 * mono_get_delegate_invoke:
3797 * @klass: The delegate class
3799 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3802 mono_get_delegate_invoke (MonoClass *klass)
3804 MONO_REQ_GC_NEUTRAL_MODE;
3808 /* This is called at runtime, so avoid the slower search in metadata */
3809 mono_class_setup_methods (klass);
3810 if (mono_class_has_failure (klass))
3812 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3817 * mono_get_delegate_begin_invoke:
3818 * @klass: The delegate class
3820 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3823 mono_get_delegate_begin_invoke (MonoClass *klass)
3825 MONO_REQ_GC_NEUTRAL_MODE;
3829 /* This is called at runtime, so avoid the slower search in metadata */
3830 mono_class_setup_methods (klass);
3831 if (mono_class_has_failure (klass))
3833 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3838 * mono_get_delegate_end_invoke:
3839 * @klass: The delegate class
3841 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3844 mono_get_delegate_end_invoke (MonoClass *klass)
3846 MONO_REQ_GC_NEUTRAL_MODE;
3850 /* This is called at runtime, so avoid the slower search in metadata */
3851 mono_class_setup_methods (klass);
3852 if (mono_class_has_failure (klass))
3854 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3859 * mono_runtime_delegate_invoke:
3860 * @delegate: pointer to a delegate object.
3861 * @params: parameters for the delegate.
3862 * @exc: Pointer to the exception result.
3864 * Invokes the delegate method @delegate with the parameters provided.
3866 * You can pass NULL as the exc argument if you don't want to
3867 * catch exceptions, otherwise, *exc will be set to the exception
3868 * thrown, if any. if an exception is thrown, you can't use the
3869 * MonoObject* result from the function.
3872 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3874 MONO_REQ_GC_UNSAFE_MODE;
3878 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3880 mono_error_cleanup (&error);
3883 if (!is_ok (&error))
3884 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3888 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3889 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3895 * mono_runtime_delegate_try_invoke:
3896 * @delegate: pointer to a delegate object.
3897 * @params: parameters for the delegate.
3898 * @exc: Pointer to the exception result.
3899 * @error: set on error
3901 * Invokes the delegate method @delegate with the parameters provided.
3903 * You can pass NULL as the exc argument if you don't want to
3904 * catch exceptions, otherwise, *exc will be set to the exception
3905 * thrown, if any. On failure to execute, @error will be set.
3906 * if an exception is thrown, you can't use the
3907 * MonoObject* result from the function.
3910 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3912 MONO_REQ_GC_UNSAFE_MODE;
3914 mono_error_init (error);
3916 MonoClass *klass = delegate->vtable->klass;
3919 im = mono_get_delegate_invoke (klass);
3921 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3924 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3926 o = mono_runtime_invoke_checked (im, delegate, params, error);
3933 * mono_runtime_delegate_invoke_checked:
3934 * @delegate: pointer to a delegate object.
3935 * @params: parameters for the delegate.
3936 * @error: set on error
3938 * Invokes the delegate method @delegate with the parameters provided.
3940 * On failure @error will be set and you can't use the MonoObject*
3941 * result from the function.
3944 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3946 mono_error_init (error);
3947 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3950 static char **main_args = NULL;
3951 static int num_main_args = 0;
3954 * mono_runtime_get_main_args:
3956 * Returns: a MonoArray with the arguments passed to the main program
3959 mono_runtime_get_main_args (void)
3961 MONO_REQ_GC_UNSAFE_MODE;
3963 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3964 mono_error_assert_ok (&error);
3969 * mono_runtime_get_main_args:
3970 * @error: set on error
3972 * Returns: a MonoArray with the arguments passed to the main
3973 * program. On failure returns NULL and sets @error.
3976 mono_runtime_get_main_args_checked (MonoError *error)
3980 MonoDomain *domain = mono_domain_get ();
3982 mono_error_init (error);
3984 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3985 return_val_if_nok (error, NULL);
3987 for (i = 0; i < num_main_args; ++i)
3988 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3994 free_main_args (void)
3996 MONO_REQ_GC_NEUTRAL_MODE;
4000 for (i = 0; i < num_main_args; ++i)
4001 g_free (main_args [i]);
4008 * mono_runtime_set_main_args:
4009 * @argc: number of arguments from the command line
4010 * @argv: array of strings from the command line
4012 * Set the command line arguments from an embedding application that doesn't otherwise call
4013 * mono_runtime_run_main ().
4016 mono_runtime_set_main_args (int argc, char* argv[])
4018 MONO_REQ_GC_NEUTRAL_MODE;
4023 main_args = g_new0 (char*, argc);
4024 num_main_args = argc;
4026 for (i = 0; i < argc; ++i) {
4029 utf8_arg = mono_utf8_from_external (argv[i]);
4030 if (utf8_arg == NULL) {
4031 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4032 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4036 main_args [i] = utf8_arg;
4043 * Prepare an array of arguments in order to execute a standard Main()
4044 * method (argc/argv contains the executable name). This method also
4045 * sets the command line argument value needed by System.Environment.
4049 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4051 MONO_REQ_GC_UNSAFE_MODE;
4055 MonoArray *args = NULL;
4056 MonoDomain *domain = mono_domain_get ();
4057 gchar *utf8_fullpath;
4058 MonoMethodSignature *sig;
4060 g_assert (method != NULL);
4062 mono_thread_set_main (mono_thread_current ());
4064 main_args = g_new0 (char*, argc);
4065 num_main_args = argc;
4067 if (!g_path_is_absolute (argv [0])) {
4068 gchar *basename = g_path_get_basename (argv [0]);
4069 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4073 utf8_fullpath = mono_utf8_from_external (fullpath);
4074 if(utf8_fullpath == NULL) {
4075 /* Printing the arg text will cause glib to
4076 * whinge about "Invalid UTF-8", but at least
4077 * its relevant, and shows the problem text
4080 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4081 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4088 utf8_fullpath = mono_utf8_from_external (argv[0]);
4089 if(utf8_fullpath == NULL) {
4090 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4091 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4096 main_args [0] = utf8_fullpath;
4098 for (i = 1; i < argc; ++i) {
4101 utf8_arg=mono_utf8_from_external (argv[i]);
4102 if(utf8_arg==NULL) {
4103 /* Ditto the comment about Invalid UTF-8 here */
4104 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4105 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4109 main_args [i] = utf8_arg;
4114 sig = mono_method_signature (method);
4116 g_print ("Unable to load Main method.\n");
4120 if (sig->param_count) {
4121 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4122 mono_error_assert_ok (&error);
4123 for (i = 0; i < argc; ++i) {
4124 /* The encodings should all work, given that
4125 * we've checked all these args for the
4128 gchar *str = mono_utf8_from_external (argv [i]);
4129 MonoString *arg = mono_string_new (domain, str);
4130 mono_array_setref (args, i, arg);
4134 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4135 mono_error_assert_ok (&error);
4138 mono_assembly_set_main (method->klass->image->assembly);
4144 * mono_runtime_run_main:
4145 * @method: the method to start the application with (usually Main)
4146 * @argc: number of arguments from the command line
4147 * @argv: array of strings from the command line
4148 * @exc: excetption results
4150 * Execute a standard Main() method (argc/argv contains the
4151 * executable name). This method also sets the command line argument value
4152 * needed by System.Environment.
4157 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4160 MONO_REQ_GC_UNSAFE_MODE;
4163 MonoArray *args = prepare_run_main (method, argc, argv);
4166 res = mono_runtime_try_exec_main (method, args, exc);
4168 res = mono_runtime_exec_main_checked (method, args, &error);
4169 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4175 * mono_runtime_run_main_checked:
4176 * @method: the method to start the application with (usually Main)
4177 * @argc: number of arguments from the command line
4178 * @argv: array of strings from the command line
4179 * @error: set on error
4181 * Execute a standard Main() method (argc/argv contains the
4182 * executable name). This method also sets the command line argument value
4183 * needed by System.Environment. On failure sets @error.
4188 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4191 mono_error_init (error);
4192 MonoArray *args = prepare_run_main (method, argc, argv);
4193 return mono_runtime_exec_main_checked (method, args, error);
4197 * mono_runtime_try_run_main:
4198 * @method: the method to start the application with (usually Main)
4199 * @argc: number of arguments from the command line
4200 * @argv: array of strings from the command line
4201 * @exc: set if Main throws an exception
4202 * @error: set if Main can't be executed
4204 * Execute a standard Main() method (argc/argv contains the executable
4205 * name). This method also sets the command line argument value needed
4206 * by System.Environment. On failure sets @error if Main can't be
4207 * executed or @exc if it threw and exception.
4212 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4216 MonoArray *args = prepare_run_main (method, argc, argv);
4217 return mono_runtime_try_exec_main (method, args, exc);
4222 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4224 static MonoMethod *serialize_method;
4230 if (!serialize_method) {
4231 MonoClass *klass = mono_class_get_remoting_services_class ();
4232 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4235 if (!serialize_method) {
4240 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4245 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4246 if (*exc == NULL && !mono_error_ok (&error))
4247 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4249 mono_error_cleanup (&error);
4258 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4260 MONO_REQ_GC_UNSAFE_MODE;
4262 static MonoMethod *deserialize_method;
4268 if (!deserialize_method) {
4269 MonoClass *klass = mono_class_get_remoting_services_class ();
4270 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4272 if (!deserialize_method) {
4280 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4281 if (*exc == NULL && !mono_error_ok (&error))
4282 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4284 mono_error_cleanup (&error);
4292 #ifndef DISABLE_REMOTING
4294 make_transparent_proxy (MonoObject *obj, MonoError *error)
4296 MONO_REQ_GC_UNSAFE_MODE;
4298 static MonoMethod *get_proxy_method;
4300 MonoDomain *domain = mono_domain_get ();
4301 MonoRealProxy *real_proxy;
4302 MonoReflectionType *reflection_type;
4303 MonoTransparentProxy *transparent_proxy;
4305 mono_error_init (error);
4307 if (!get_proxy_method)
4308 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4310 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4312 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4313 return_val_if_nok (error, NULL);
4314 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4315 return_val_if_nok (error, NULL);
4317 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4318 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4320 MonoObject *exc = NULL;
4322 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4323 if (exc != NULL && is_ok (error))
4324 mono_error_set_exception_instance (error, (MonoException*)exc);
4326 return (MonoObject*) transparent_proxy;
4328 #endif /* DISABLE_REMOTING */
4331 * mono_object_xdomain_representation
4333 * @target_domain: a domain
4334 * @error: set on error.
4336 * Creates a representation of obj in the domain target_domain. This
4337 * is either a copy of obj arrived through via serialization and
4338 * deserialization or a proxy, depending on whether the object is
4339 * serializable or marshal by ref. obj must not be in target_domain.
4341 * If the object cannot be represented in target_domain, NULL is
4342 * returned and @error is set appropriately.
4345 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4347 MONO_REQ_GC_UNSAFE_MODE;
4349 mono_error_init (error);
4350 MonoObject *deserialized = NULL;
4352 #ifndef DISABLE_REMOTING
4353 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4354 deserialized = make_transparent_proxy (obj, error);
4359 gboolean failure = FALSE;
4360 MonoDomain *domain = mono_domain_get ();
4361 MonoObject *serialized;
4362 MonoObject *exc = NULL;
4364 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4365 serialized = serialize_object (obj, &failure, &exc);
4366 mono_domain_set_internal_with_options (target_domain, FALSE);
4368 deserialized = deserialize_object (serialized, &failure, &exc);
4369 if (domain != target_domain)
4370 mono_domain_set_internal_with_options (domain, FALSE);
4372 mono_error_set_exception_instance (error, (MonoException*)exc);
4375 return deserialized;
4378 /* Used in call_unhandled_exception_delegate */
4380 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4382 MONO_REQ_GC_UNSAFE_MODE;
4384 mono_error_init (error);
4387 MonoMethod *method = NULL;
4388 MonoBoolean is_terminating = TRUE;
4391 klass = mono_class_get_unhandled_exception_event_args_class ();
4392 mono_class_init (klass);
4394 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4395 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4399 args [1] = &is_terminating;
4401 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4402 return_val_if_nok (error, NULL);
4404 mono_runtime_invoke_checked (method, obj, args, error);
4405 return_val_if_nok (error, NULL);
4410 /* Used in mono_unhandled_exception */
4412 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4413 MONO_REQ_GC_UNSAFE_MODE;
4416 MonoObject *e = NULL;
4418 MonoDomain *current_domain = mono_domain_get ();
4420 if (domain != current_domain)
4421 mono_domain_set_internal_with_options (domain, FALSE);
4423 g_assert (domain == mono_object_domain (domain->domain));
4425 if (mono_object_domain (exc) != domain) {
4427 exc = mono_object_xdomain_representation (exc, domain, &error);
4429 if (!is_ok (&error)) {
4430 MonoError inner_error;
4431 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4432 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4433 mono_error_assert_ok (&inner_error);
4435 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4436 "System.Runtime.Serialization", "SerializationException",
4437 "Could not serialize unhandled exception.");
4441 g_assert (mono_object_domain (exc) == domain);
4443 pa [0] = domain->domain;
4444 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4445 mono_error_assert_ok (&error);
4446 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4447 if (!is_ok (&error)) {
4449 e = (MonoObject*)mono_error_convert_to_exception (&error);
4451 mono_error_cleanup (&error);
4454 if (domain != current_domain)
4455 mono_domain_set_internal_with_options (current_domain, FALSE);
4458 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4459 if (!mono_error_ok (&error)) {
4460 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4461 mono_error_cleanup (&error);
4463 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4469 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4472 * mono_runtime_unhandled_exception_policy_set:
4473 * @policy: the new policy
4475 * This is a VM internal routine.
4477 * Sets the runtime policy for handling unhandled exceptions.
4480 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4481 runtime_unhandled_exception_policy = policy;
4485 * mono_runtime_unhandled_exception_policy_get:
4487 * This is a VM internal routine.
4489 * Gets the runtime policy for handling unhandled exceptions.
4491 MonoRuntimeUnhandledExceptionPolicy
4492 mono_runtime_unhandled_exception_policy_get (void) {
4493 return runtime_unhandled_exception_policy;
4497 * mono_unhandled_exception:
4498 * @exc: exception thrown
4500 * This is a VM internal routine.
4502 * We call this function when we detect an unhandled exception
4503 * in the default domain.
4505 * It invokes the * UnhandledException event in AppDomain or prints
4506 * a warning to the console
4509 mono_unhandled_exception (MonoObject *exc)
4511 MONO_REQ_GC_UNSAFE_MODE;
4514 MonoClassField *field;
4515 MonoDomain *current_domain, *root_domain;
4516 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4518 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4521 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4524 current_domain = mono_domain_get ();
4525 root_domain = mono_get_root_domain ();
4527 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4528 mono_error_assert_ok (&error);
4529 if (current_domain != root_domain) {
4530 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4531 mono_error_assert_ok (&error);
4534 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4535 mono_print_unhandled_exception (exc);
4537 /* unhandled exception callbacks must not be aborted */
4538 mono_threads_begin_abort_protected_block ();
4539 if (root_appdomain_delegate)
4540 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4541 if (current_appdomain_delegate)
4542 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4543 mono_threads_end_abort_protected_block ();
4546 /* set exitcode only if we will abort the process */
4547 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4548 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4550 mono_environment_exitcode_set (1);
4555 * mono_runtime_exec_managed_code:
4556 * @domain: Application domain
4557 * @main_func: function to invoke from the execution thread
4558 * @main_args: parameter to the main_func
4560 * Launch a new thread to execute a function
4562 * main_func is called back from the thread with main_args as the
4563 * parameter. The callback function is expected to start Main()
4564 * eventually. This function then waits for all managed threads to
4566 * It is not necesseray anymore to execute managed code in a subthread,
4567 * so this function should not be used anymore by default: just
4568 * execute the code and then call mono_thread_manage ().
4571 mono_runtime_exec_managed_code (MonoDomain *domain,
4572 MonoMainThreadFunc main_func,
4576 mono_thread_create_checked (domain, main_func, main_args, &error);
4577 mono_error_assert_ok (&error);
4579 mono_thread_manage ();
4583 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4585 MonoInternalThread* thread = mono_thread_internal_current ();
4586 MonoCustomAttrInfo* cinfo;
4587 gboolean has_stathread_attribute;
4589 if (!domain->entry_assembly) {
4591 MonoAssembly *assembly;
4593 assembly = method->klass->image->assembly;
4594 domain->entry_assembly = assembly;
4595 /* Domains created from another domain already have application_base and configuration_file set */
4596 if (domain->setup->application_base == NULL) {
4597 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4600 if (domain->setup->configuration_file == NULL) {
4601 str = g_strconcat (assembly->image->name, ".config", NULL);
4602 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4604 mono_domain_set_options_from_config (domain);
4608 MonoError cattr_error;
4609 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4610 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4612 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4614 mono_custom_attrs_free (cinfo);
4616 has_stathread_attribute = FALSE;
4618 if (has_stathread_attribute) {
4619 thread->apartment_state = ThreadApartmentState_STA;
4621 thread->apartment_state = ThreadApartmentState_MTA;
4623 mono_thread_init_apartment_state ();
4628 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4630 MONO_REQ_GC_UNSAFE_MODE;
4635 mono_error_init (error);
4640 /* FIXME: check signature of method */
4641 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4643 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4645 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4648 mono_environment_exitcode_set (rval);
4650 mono_runtime_invoke_checked (method, NULL, pa, error);
4662 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4664 MONO_REQ_GC_UNSAFE_MODE;
4674 /* FIXME: check signature of method */
4675 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4676 MonoError inner_error;
4678 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4679 if (*exc == NULL && !mono_error_ok (&inner_error))
4680 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4682 mono_error_cleanup (&inner_error);
4685 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4689 mono_environment_exitcode_set (rval);
4691 MonoError inner_error;
4692 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4693 if (*exc == NULL && !mono_error_ok (&inner_error))
4694 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4696 mono_error_cleanup (&inner_error);
4701 /* If the return type of Main is void, only
4702 * set the exitcode if an exception was thrown
4703 * (we don't want to blow away an
4704 * explicitly-set exit code)
4707 mono_environment_exitcode_set (rval);
4715 * Execute a standard Main() method (args doesn't contain the
4719 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4722 prepare_thread_to_exec_main (mono_object_domain (args), method);
4724 int rval = do_try_exec_main (method, args, exc);
4727 int rval = do_exec_main_checked (method, args, &error);
4728 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4734 * Execute a standard Main() method (args doesn't contain the
4737 * On failure sets @error
4740 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4742 mono_error_init (error);
4743 prepare_thread_to_exec_main (mono_object_domain (args), method);
4744 return do_exec_main_checked (method, args, error);
4748 * Execute a standard Main() method (args doesn't contain the
4751 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4754 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4756 prepare_thread_to_exec_main (mono_object_domain (args), method);
4757 return do_try_exec_main (method, args, exc);
4762 /** invoke_array_extract_argument:
4763 * @params: array of arguments to the method.
4764 * @i: the index of the argument to extract.
4765 * @t: ith type from the method signature.
4766 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4767 * @error: set on error.
4769 * Given an array of method arguments, return the ith one using the corresponding type
4770 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4772 * On failure sets @error and returns NULL.
4775 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4777 MonoType *t_orig = t;
4778 gpointer result = NULL;
4779 mono_error_init (error);
4784 case MONO_TYPE_BOOLEAN:
4787 case MONO_TYPE_CHAR:
4796 case MONO_TYPE_VALUETYPE:
4797 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4798 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4799 result = mono_array_get (params, MonoObject*, i);
4801 *has_byref_nullables = TRUE;
4803 /* MS seems to create the objects if a null is passed in */
4804 if (!mono_array_get (params, MonoObject*, i)) {
4805 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4806 return_val_if_nok (error, NULL);
4807 mono_array_setref (params, i, o);
4812 * We can't pass the unboxed vtype byref to the callee, since
4813 * that would mean the callee would be able to modify boxed
4814 * primitive types. So we (and MS) make a copy of the boxed
4815 * object, pass that to the callee, and replace the original
4816 * boxed object in the arg array with the copy.
4818 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4819 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4820 return_val_if_nok (error, NULL);
4821 mono_array_setref (params, i, copy);
4824 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4827 case MONO_TYPE_STRING:
4828 case MONO_TYPE_OBJECT:
4829 case MONO_TYPE_CLASS:
4830 case MONO_TYPE_ARRAY:
4831 case MONO_TYPE_SZARRAY:
4833 result = mono_array_addr (params, MonoObject*, i);
4834 // FIXME: I need to check this code path
4836 result = mono_array_get (params, MonoObject*, i);
4838 case MONO_TYPE_GENERICINST:
4840 t = &t->data.generic_class->container_class->this_arg;
4842 t = &t->data.generic_class->container_class->byval_arg;
4844 case MONO_TYPE_PTR: {
4847 /* The argument should be an IntPtr */
4848 arg = mono_array_get (params, MonoObject*, i);
4852 g_assert (arg->vtable->klass == mono_defaults.int_class);
4853 result = ((MonoIntPtr*)arg)->m_value;
4858 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4863 * mono_runtime_invoke_array:
4864 * @method: method to invoke
4865 * @obJ: object instance
4866 * @params: arguments to the method
4867 * @exc: exception information.
4869 * Invokes the method represented by @method on the object @obj.
4871 * obj is the 'this' pointer, it should be NULL for static
4872 * methods, a MonoObject* for object instances and a pointer to
4873 * the value type for value types.
4875 * The params array contains the arguments to the method with the
4876 * same convention: MonoObject* pointers for object instances and
4877 * pointers to the value type otherwise. The _invoke_array
4878 * variant takes a C# object[] as the params argument (MonoArray
4879 * *params): in this case the value types are boxed inside the
4880 * respective reference representation.
4882 * From unmanaged code you'll usually use the
4883 * mono_runtime_invoke_checked() variant.
4885 * Note that this function doesn't handle virtual methods for
4886 * you, it will exec the exact method you pass: we still need to
4887 * expose a function to lookup the derived class implementation
4888 * of a virtual method (there are examples of this in the code,
4891 * You can pass NULL as the exc argument if you don't want to
4892 * catch exceptions, otherwise, *exc will be set to the exception
4893 * thrown, if any. if an exception is thrown, you can't use the
4894 * MonoObject* result from the function.
4896 * If the method returns a value type, it is boxed in an object
4900 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4905 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4907 mono_error_cleanup (&error);
4910 if (!is_ok (&error))
4911 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4915 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4916 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4922 * mono_runtime_invoke_array_checked:
4923 * @method: method to invoke
4924 * @obJ: object instance
4925 * @params: arguments to the method
4926 * @error: set on failure.
4928 * Invokes the method represented by @method on the object @obj.
4930 * obj is the 'this' pointer, it should be NULL for static
4931 * methods, a MonoObject* for object instances and a pointer to
4932 * the value type for value types.
4934 * The params array contains the arguments to the method with the
4935 * same convention: MonoObject* pointers for object instances and
4936 * pointers to the value type otherwise. The _invoke_array
4937 * variant takes a C# object[] as the params argument (MonoArray
4938 * *params): in this case the value types are boxed inside the
4939 * respective reference representation.
4941 * From unmanaged code you'll usually use the
4942 * mono_runtime_invoke_checked() variant.
4944 * Note that this function doesn't handle virtual methods for
4945 * you, it will exec the exact method you pass: we still need to
4946 * expose a function to lookup the derived class implementation
4947 * of a virtual method (there are examples of this in the code,
4950 * On failure or exception, @error will be set. In that case, you
4951 * can't use the MonoObject* result from the function.
4953 * If the method returns a value type, it is boxed in an object
4957 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4960 mono_error_init (error);
4961 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4965 * mono_runtime_try_invoke_array:
4966 * @method: method to invoke
4967 * @obJ: object instance
4968 * @params: arguments to the method
4969 * @exc: exception information.
4970 * @error: set on failure.
4972 * Invokes the method represented by @method on the object @obj.
4974 * obj is the 'this' pointer, it should be NULL for static
4975 * methods, a MonoObject* for object instances and a pointer to
4976 * the value type for value types.
4978 * The params array contains the arguments to the method with the
4979 * same convention: MonoObject* pointers for object instances and
4980 * pointers to the value type otherwise. The _invoke_array
4981 * variant takes a C# object[] as the params argument (MonoArray
4982 * *params): in this case the value types are boxed inside the
4983 * respective reference representation.
4985 * From unmanaged code you'll usually use the
4986 * mono_runtime_invoke_checked() variant.
4988 * Note that this function doesn't handle virtual methods for
4989 * you, it will exec the exact method you pass: we still need to
4990 * expose a function to lookup the derived class implementation
4991 * of a virtual method (there are examples of this in the code,
4994 * You can pass NULL as the exc argument if you don't want to catch
4995 * exceptions, otherwise, *exc will be set to the exception thrown, if
4996 * any. On other failures, @error will be set. If an exception is
4997 * thrown or there's an error, you can't use the MonoObject* result
4998 * from the function.
5000 * If the method returns a value type, it is boxed in an object
5004 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5005 MonoObject **exc, MonoError *error)
5007 MONO_REQ_GC_UNSAFE_MODE;
5009 mono_error_init (error);
5011 MonoMethodSignature *sig = mono_method_signature (method);
5012 gpointer *pa = NULL;
5015 gboolean has_byref_nullables = FALSE;
5017 if (NULL != params) {
5018 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5019 for (i = 0; i < mono_array_length (params); i++) {
5020 MonoType *t = sig->params [i];
5021 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5022 return_val_if_nok (error, NULL);
5026 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5029 if (mono_class_is_nullable (method->klass)) {
5030 /* Need to create a boxed vtype instead */
5036 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5041 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5042 mono_error_assert_ok (error);
5043 g_assert (obj); /*maybe we should raise a TLE instead?*/
5044 #ifndef DISABLE_REMOTING
5045 if (mono_object_is_transparent_proxy (obj)) {
5046 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5049 if (method->klass->valuetype)
5050 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5053 } else if (method->klass->valuetype) {
5054 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5055 return_val_if_nok (error, NULL);
5059 mono_runtime_try_invoke (method, o, pa, exc, error);
5061 mono_runtime_invoke_checked (method, o, pa, error);
5064 return (MonoObject *)obj;
5066 if (mono_class_is_nullable (method->klass)) {
5067 MonoObject *nullable;
5069 /* Convert the unboxed vtype into a Nullable structure */
5070 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5071 return_val_if_nok (error, NULL);
5073 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5074 return_val_if_nok (error, NULL);
5075 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5076 obj = mono_object_unbox (nullable);
5079 /* obj must be already unboxed if needed */
5081 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5083 res = mono_runtime_invoke_checked (method, obj, pa, error);
5085 return_val_if_nok (error, NULL);
5087 if (sig->ret->type == MONO_TYPE_PTR) {
5088 MonoClass *pointer_class;
5089 static MonoMethod *box_method;
5091 MonoObject *box_exc;
5094 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5095 * convert it to a Pointer object.
5097 pointer_class = mono_class_get_pointer_class ();
5099 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5101 g_assert (res->vtable->klass == mono_defaults.int_class);
5102 box_args [0] = ((MonoIntPtr*)res)->m_value;
5103 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5104 return_val_if_nok (error, NULL);
5106 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5107 g_assert (box_exc == NULL);
5108 mono_error_assert_ok (error);
5111 if (has_byref_nullables) {
5113 * The runtime invoke wrapper already converted byref nullables back,
5114 * and stored them in pa, we just need to copy them back to the
5117 for (i = 0; i < mono_array_length (params); i++) {
5118 MonoType *t = sig->params [i];
5120 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5121 mono_array_setref (params, i, pa [i]);
5131 * @klass: the class of the object that we want to create
5133 * Returns: a newly created object whose definition is
5134 * looked up using @klass. This will not invoke any constructors,
5135 * so the consumer of this routine has to invoke any constructors on
5136 * its own to initialize the object.
5138 * It returns NULL on failure.
5141 mono_object_new (MonoDomain *domain, MonoClass *klass)
5143 MONO_REQ_GC_UNSAFE_MODE;
5147 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5149 mono_error_cleanup (&error);
5154 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5156 MONO_REQ_GC_UNSAFE_MODE;
5160 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5162 mono_error_set_pending_exception (&error);
5167 * mono_object_new_checked:
5168 * @klass: the class of the object that we want to create
5169 * @error: set on error
5171 * Returns: a newly created object whose definition is
5172 * looked up using @klass. This will not invoke any constructors,
5173 * so the consumer of this routine has to invoke any constructors on
5174 * its own to initialize the object.
5176 * It returns NULL on failure and sets @error.
5179 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5181 MONO_REQ_GC_UNSAFE_MODE;
5185 vtable = mono_class_vtable (domain, klass);
5186 g_assert (vtable); /* FIXME don't swallow the error */
5188 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5193 * mono_object_new_pinned:
5195 * Same as mono_object_new, but the returned object will be pinned.
5196 * For SGEN, these objects will only be freed at appdomain unload.
5199 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5201 MONO_REQ_GC_UNSAFE_MODE;
5205 mono_error_init (error);
5207 vtable = mono_class_vtable (domain, klass);
5208 g_assert (vtable); /* FIXME don't swallow the error */
5210 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5212 if (G_UNLIKELY (!o))
5213 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5214 else if (G_UNLIKELY (vtable->klass->has_finalize))
5215 mono_object_register_finalizer (o);
5221 * mono_object_new_specific:
5222 * @vtable: the vtable of the object that we want to create
5224 * Returns: A newly created object with class and domain specified
5228 mono_object_new_specific (MonoVTable *vtable)
5231 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5232 mono_error_cleanup (&error);
5238 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5240 MONO_REQ_GC_UNSAFE_MODE;
5244 mono_error_init (error);
5246 /* check for is_com_object for COM Interop */
5247 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5250 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5253 MonoClass *klass = mono_class_get_activation_services_class ();
5256 mono_class_init (klass);
5258 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5260 mono_error_set_not_supported (error, "Linked away.");
5263 vtable->domain->create_proxy_for_type_method = im;
5266 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5267 if (!mono_error_ok (error))
5270 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5271 if (!mono_error_ok (error))
5278 return mono_object_new_alloc_specific_checked (vtable, error);
5282 ves_icall_object_new_specific (MonoVTable *vtable)
5285 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5286 mono_error_set_pending_exception (&error);
5292 * mono_object_new_alloc_specific:
5293 * @vtable: virtual table for the object.
5295 * This function allocates a new `MonoObject` with the type derived
5296 * from the @vtable information. If the class of this object has a
5297 * finalizer, then the object will be tracked for finalization.
5299 * This method might raise an exception on errors. Use the
5300 * `mono_object_new_fast_checked` method if you want to manually raise
5303 * Returns: the allocated object.
5306 mono_object_new_alloc_specific (MonoVTable *vtable)
5309 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5310 mono_error_cleanup (&error);
5316 * mono_object_new_alloc_specific_checked:
5317 * @vtable: virtual table for the object.
5318 * @error: holds the error return value.
5320 * This function allocates a new `MonoObject` with the type derived
5321 * from the @vtable information. If the class of this object has a
5322 * finalizer, then the object will be tracked for finalization.
5324 * If there is not enough memory, the @error parameter will be set
5325 * and will contain a user-visible message with the amount of bytes
5326 * that were requested.
5328 * Returns: the allocated object, or NULL if there is not enough memory
5332 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5334 MONO_REQ_GC_UNSAFE_MODE;
5338 mono_error_init (error);
5340 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5342 if (G_UNLIKELY (!o))
5343 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5344 else if (G_UNLIKELY (vtable->klass->has_finalize))
5345 mono_object_register_finalizer (o);
5351 * mono_object_new_fast:
5352 * @vtable: virtual table for the object.
5354 * This function allocates a new `MonoObject` with the type derived
5355 * from the @vtable information. The returned object is not tracked
5356 * for finalization. If your object implements a finalizer, you should
5357 * use `mono_object_new_alloc_specific` instead.
5359 * This method might raise an exception on errors. Use the
5360 * `mono_object_new_fast_checked` method if you want to manually raise
5363 * Returns: the allocated object.
5366 mono_object_new_fast (MonoVTable *vtable)
5369 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5370 mono_error_cleanup (&error);
5376 * mono_object_new_fast_checked:
5377 * @vtable: virtual table for the object.
5378 * @error: holds the error return value.
5380 * This function allocates a new `MonoObject` with the type derived
5381 * from the @vtable information. The returned object is not tracked
5382 * for finalization. If your object implements a finalizer, you should
5383 * use `mono_object_new_alloc_specific_checked` instead.
5385 * If there is not enough memory, the @error parameter will be set
5386 * and will contain a user-visible message with the amount of bytes
5387 * that were requested.
5389 * Returns: the allocated object, or NULL if there is not enough memory
5393 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5395 MONO_REQ_GC_UNSAFE_MODE;
5399 mono_error_init (error);
5401 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5403 if (G_UNLIKELY (!o))
5404 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5410 ves_icall_object_new_fast (MonoVTable *vtable)
5413 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5414 mono_error_set_pending_exception (&error);
5420 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5422 MONO_REQ_GC_UNSAFE_MODE;
5426 mono_error_init (error);
5428 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5430 if (G_UNLIKELY (!o))
5431 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5432 else if (G_UNLIKELY (vtable->klass->has_finalize))
5433 mono_object_register_finalizer (o);
5439 * mono_class_get_allocation_ftn:
5441 * @for_box: the object will be used for boxing
5442 * @pass_size_in_words:
5444 * Return the allocation function appropriate for the given class.
5448 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5450 MONO_REQ_GC_NEUTRAL_MODE;
5452 *pass_size_in_words = FALSE;
5454 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5455 return ves_icall_object_new_specific;
5457 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5459 return ves_icall_object_new_fast;
5462 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5463 * of the overhead of parameter passing.
5466 *pass_size_in_words = TRUE;
5467 #ifdef GC_REDIRECT_TO_LOCAL
5468 return GC_local_gcj_fast_malloc;
5470 return GC_gcj_fast_malloc;
5475 return ves_icall_object_new_specific;
5479 * mono_object_new_from_token:
5480 * @image: Context where the type_token is hosted
5481 * @token: a token of the type that we want to create
5483 * Returns: A newly created object whose definition is
5484 * looked up using @token in the @image image
5487 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5489 MONO_REQ_GC_UNSAFE_MODE;
5495 klass = mono_class_get_checked (image, token, &error);
5496 mono_error_assert_ok (&error);
5498 result = mono_object_new_checked (domain, klass, &error);
5500 mono_error_cleanup (&error);
5507 * mono_object_clone:
5508 * @obj: the object to clone
5510 * Returns: A newly created object who is a shallow copy of @obj
5513 mono_object_clone (MonoObject *obj)
5516 MonoObject *o = mono_object_clone_checked (obj, &error);
5517 mono_error_cleanup (&error);
5523 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5525 MONO_REQ_GC_UNSAFE_MODE;
5530 mono_error_init (error);
5532 size = obj->vtable->klass->instance_size;
5534 if (obj->vtable->klass->rank)
5535 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5537 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5539 if (G_UNLIKELY (!o)) {
5540 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5544 /* If the object doesn't contain references this will do a simple memmove. */
5545 mono_gc_wbarrier_object_copy (o, obj);
5547 if (obj->vtable->klass->has_finalize)
5548 mono_object_register_finalizer (o);
5553 * mono_array_full_copy:
5554 * @src: source array to copy
5555 * @dest: destination array
5557 * Copies the content of one array to another with exactly the same type and size.
5560 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5562 MONO_REQ_GC_UNSAFE_MODE;
5565 MonoClass *klass = src->obj.vtable->klass;
5567 g_assert (klass == dest->obj.vtable->klass);
5569 size = mono_array_length (src);
5570 g_assert (size == mono_array_length (dest));
5571 size *= mono_array_element_size (klass);
5573 if (klass->element_class->valuetype) {
5574 if (klass->element_class->has_references)
5575 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5577 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5579 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5582 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5587 * mono_array_clone_in_domain:
5588 * @domain: the domain in which the array will be cloned into
5589 * @array: the array to clone
5590 * @error: set on error
5592 * This routine returns a copy of the array that is hosted on the
5593 * specified MonoDomain. On failure returns NULL and sets @error.
5596 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5598 MONO_REQ_GC_UNSAFE_MODE;
5603 MonoClass *klass = array->obj.vtable->klass;
5605 mono_error_init (error);
5607 if (array->bounds == NULL) {
5608 size = mono_array_length (array);
5609 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5610 return_val_if_nok (error, NULL);
5612 size *= mono_array_element_size (klass);
5614 if (klass->element_class->valuetype) {
5615 if (klass->element_class->has_references)
5616 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5618 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5620 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5623 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5628 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5629 size = mono_array_element_size (klass);
5630 for (i = 0; i < klass->rank; ++i) {
5631 sizes [i] = array->bounds [i].length;
5632 size *= array->bounds [i].length;
5633 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5635 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5636 return_val_if_nok (error, NULL);
5638 if (klass->element_class->valuetype) {
5639 if (klass->element_class->has_references)
5640 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5642 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5644 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5647 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5655 * @array: the array to clone
5657 * Returns: A newly created array who is a shallow copy of @array
5660 mono_array_clone (MonoArray *array)
5662 MONO_REQ_GC_UNSAFE_MODE;
5665 MonoArray *result = mono_array_clone_checked (array, &error);
5666 mono_error_cleanup (&error);
5671 * mono_array_clone_checked:
5672 * @array: the array to clone
5673 * @error: set on error
5675 * Returns: A newly created array who is a shallow copy of @array. On
5676 * failure returns NULL and sets @error.
5679 mono_array_clone_checked (MonoArray *array, MonoError *error)
5682 MONO_REQ_GC_UNSAFE_MODE;
5683 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5686 /* helper macros to check for overflow when calculating the size of arrays */
5687 #ifdef MONO_BIG_ARRAYS
5688 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5689 #define MYGUINT_MAX MYGUINT64_MAX
5690 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5691 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5692 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5693 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5694 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5696 #define MYGUINT32_MAX 4294967295U
5697 #define MYGUINT_MAX MYGUINT32_MAX
5698 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5699 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5700 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5701 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5702 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5706 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5708 MONO_REQ_GC_NEUTRAL_MODE;
5712 byte_len = mono_array_element_size (klass);
5713 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5716 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5718 byte_len += MONO_SIZEOF_MONO_ARRAY;
5726 * mono_array_new_full:
5727 * @domain: domain where the object is created
5728 * @array_class: array class
5729 * @lengths: lengths for each dimension in the array
5730 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5732 * This routine creates a new array objects with the given dimensions,
5733 * lower bounds and type.
5736 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5739 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5740 mono_error_cleanup (&error);
5746 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5748 MONO_REQ_GC_UNSAFE_MODE;
5750 uintptr_t byte_len = 0, len, bounds_size;
5753 MonoArrayBounds *bounds;
5757 mono_error_init (error);
5759 if (!array_class->inited)
5760 mono_class_init (array_class);
5764 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5765 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5767 if (len > MONO_ARRAY_MAX_INDEX) {
5768 mono_error_set_generic_error (error, "System", "OverflowException", "");
5773 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5775 for (i = 0; i < array_class->rank; ++i) {
5776 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5777 mono_error_set_generic_error (error, "System", "OverflowException", "");
5780 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5781 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5788 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5789 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5795 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5796 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5799 byte_len = (byte_len + 3) & ~3;
5800 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5801 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5804 byte_len += bounds_size;
5807 * Following three lines almost taken from mono_object_new ():
5808 * they need to be kept in sync.
5810 vtable = mono_class_vtable_full (domain, array_class, error);
5811 return_val_if_nok (error, NULL);
5814 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5816 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5818 if (G_UNLIKELY (!o)) {
5819 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5823 array = (MonoArray*)o;
5825 bounds = array->bounds;
5828 for (i = 0; i < array_class->rank; ++i) {
5829 bounds [i].length = lengths [i];
5831 bounds [i].lower_bound = lower_bounds [i];
5840 * @domain: domain where the object is created
5841 * @eclass: element class
5842 * @n: number of array elements
5844 * This routine creates a new szarray with @n elements of type @eclass.
5847 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5849 MONO_REQ_GC_UNSAFE_MODE;
5852 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5853 mono_error_cleanup (&error);
5858 * mono_array_new_checked:
5859 * @domain: domain where the object is created
5860 * @eclass: element class
5861 * @n: number of array elements
5862 * @error: set on error
5864 * This routine creates a new szarray with @n elements of type @eclass.
5865 * On failure returns NULL and sets @error.
5868 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5872 mono_error_init (error);
5874 ac = mono_array_class_get (eclass, 1);
5877 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5878 return_val_if_nok (error, NULL);
5880 return mono_array_new_specific_checked (vtable, n, error);
5884 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5887 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5888 mono_error_set_pending_exception (&error);
5894 * mono_array_new_specific:
5895 * @vtable: a vtable in the appropriate domain for an initialized class
5896 * @n: number of array elements
5898 * This routine is a fast alternative to mono_array_new() for code which
5899 * can be sure about the domain it operates in.
5902 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5905 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5906 mono_error_cleanup (&error);
5912 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5914 MONO_REQ_GC_UNSAFE_MODE;
5919 mono_error_init (error);
5921 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5922 mono_error_set_generic_error (error, "System", "OverflowException", "");
5926 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5927 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5930 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5932 if (G_UNLIKELY (!o)) {
5933 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5937 return (MonoArray*)o;
5941 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5944 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5945 mono_error_set_pending_exception (&error);
5951 * mono_string_empty_wrapper:
5953 * Returns: The same empty string instance as the managed string.Empty
5956 mono_string_empty_wrapper (void)
5958 MonoDomain *domain = mono_domain_get ();
5959 return mono_string_empty (domain);
5963 * mono_string_empty:
5965 * Returns: The same empty string instance as the managed string.Empty
5968 mono_string_empty (MonoDomain *domain)
5971 g_assert (domain->empty_string);
5972 return domain->empty_string;
5976 * mono_string_new_utf16:
5977 * @text: a pointer to an utf16 string
5978 * @len: the length of the string
5980 * Returns: A newly created string object which contains @text.
5983 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5985 MONO_REQ_GC_UNSAFE_MODE;
5988 MonoString *res = NULL;
5989 res = mono_string_new_utf16_checked (domain, text, len, &error);
5990 mono_error_cleanup (&error);
5996 * mono_string_new_utf16_checked:
5997 * @text: a pointer to an utf16 string
5998 * @len: the length of the string
5999 * @error: written on error.
6001 * Returns: A newly created string object which contains @text.
6002 * On error, returns NULL and sets @error.
6005 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6007 MONO_REQ_GC_UNSAFE_MODE;
6011 mono_error_init (error);
6013 s = mono_string_new_size_checked (domain, len, error);
6015 memcpy (mono_string_chars (s), text, len * 2);
6021 * mono_string_new_utf32:
6022 * @text: a pointer to an utf32 string
6023 * @len: the length of the string
6024 * @error: set on failure.
6026 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6029 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6031 MONO_REQ_GC_UNSAFE_MODE;
6034 mono_unichar2 *utf16_output = NULL;
6035 gint32 utf16_len = 0;
6036 GError *gerror = NULL;
6037 glong items_written;
6039 mono_error_init (error);
6040 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6043 g_error_free (gerror);
6045 while (utf16_output [utf16_len]) utf16_len++;
6047 s = mono_string_new_size_checked (domain, utf16_len, error);
6048 return_val_if_nok (error, NULL);
6050 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6052 g_free (utf16_output);
6058 * mono_string_new_utf32:
6059 * @text: a pointer to an utf32 string
6060 * @len: the length of the string
6062 * Returns: A newly created string object which contains @text.
6065 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6068 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6069 mono_error_cleanup (&error);
6074 * mono_string_new_size:
6075 * @text: a pointer to an utf16 string
6076 * @len: the length of the string
6078 * Returns: A newly created string object of @len
6081 mono_string_new_size (MonoDomain *domain, gint32 len)
6084 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6085 mono_error_cleanup (&error);
6091 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6093 MONO_REQ_GC_UNSAFE_MODE;
6099 mono_error_init (error);
6101 /* check for overflow */
6102 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6103 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6107 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6108 g_assert (size > 0);
6110 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6113 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6115 if (G_UNLIKELY (!s)) {
6116 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6124 * mono_string_new_len:
6125 * @text: a pointer to an utf8 string
6126 * @length: number of bytes in @text to consider
6128 * Returns: A newly created string object which contains @text.
6131 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6133 MONO_REQ_GC_UNSAFE_MODE;
6136 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6137 mono_error_cleanup (&error);
6142 * mono_string_new_len_checked:
6143 * @text: a pointer to an utf8 string
6144 * @length: number of bytes in @text to consider
6145 * @error: set on error
6147 * Returns: A newly created string object which contains @text. On
6148 * failure returns NULL and sets @error.
6151 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6153 MONO_REQ_GC_UNSAFE_MODE;
6155 mono_error_init (error);
6157 GError *eg_error = NULL;
6158 MonoString *o = NULL;
6160 glong items_written;
6162 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6165 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6167 g_error_free (eg_error);
6176 * @text: a pointer to an utf8 string
6178 * Returns: A newly created string object which contains @text.
6180 * This function asserts if it cannot allocate a new string.
6182 * @deprecated Use mono_string_new_checked in new code.
6185 mono_string_new (MonoDomain *domain, const char *text)
6188 MonoString *res = NULL;
6189 res = mono_string_new_checked (domain, text, &error);
6190 mono_error_assert_ok (&error);
6195 * mono_string_new_checked:
6196 * @text: a pointer to an utf8 string
6197 * @merror: set on error
6199 * Returns: A newly created string object which contains @text.
6200 * On error returns NULL and sets @merror.
6203 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6205 MONO_REQ_GC_UNSAFE_MODE;
6207 GError *eg_error = NULL;
6208 MonoString *o = NULL;
6210 glong items_written;
6213 mono_error_init (error);
6217 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6220 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6222 g_error_free (eg_error);
6226 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6231 MonoString *o = NULL;
6233 if (!g_utf8_validate (text, -1, &end)) {
6234 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6238 len = g_utf8_strlen (text, -1);
6239 o = mono_string_new_size_checked (domain, len, error);
6242 str = mono_string_chars (o);
6244 while (text < end) {
6245 *str++ = g_utf8_get_char (text);
6246 text = g_utf8_next_char (text);
6255 * mono_string_new_wrapper:
6256 * @text: pointer to utf8 characters.
6258 * Helper function to create a string object from @text in the current domain.
6261 mono_string_new_wrapper (const char *text)
6263 MONO_REQ_GC_UNSAFE_MODE;
6265 MonoDomain *domain = mono_domain_get ();
6268 return mono_string_new (domain, text);
6275 * @class: the class of the value
6276 * @value: a pointer to the unboxed data
6278 * Returns: A newly created object which contains @value.
6281 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6284 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6285 mono_error_cleanup (&error);
6290 * mono_value_box_checked:
6291 * @domain: the domain of the new object
6292 * @class: the class of the value
6293 * @value: a pointer to the unboxed data
6294 * @error: set on error
6296 * Returns: A newly created object which contains @value. On failure
6297 * returns NULL and sets @error.
6300 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6302 MONO_REQ_GC_UNSAFE_MODE;
6307 mono_error_init (error);
6309 g_assert (klass->valuetype);
6310 if (mono_class_is_nullable (klass))
6311 return mono_nullable_box ((guint8 *)value, klass, error);
6313 vtable = mono_class_vtable (domain, klass);
6316 size = mono_class_instance_size (klass);
6317 res = mono_object_new_alloc_specific_checked (vtable, error);
6318 return_val_if_nok (error, NULL);
6320 size = size - sizeof (MonoObject);
6323 g_assert (size == mono_class_value_size (klass, NULL));
6324 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6326 #if NO_UNALIGNED_ACCESS
6327 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6331 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6334 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6337 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6340 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6343 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6347 if (klass->has_finalize) {
6348 mono_object_register_finalizer (res);
6349 return_val_if_nok (error, NULL);
6356 * @dest: destination pointer
6357 * @src: source pointer
6358 * @klass: a valuetype class
6360 * Copy a valuetype from @src to @dest. This function must be used
6361 * when @klass contains references fields.
6364 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6366 MONO_REQ_GC_UNSAFE_MODE;
6368 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6372 * mono_value_copy_array:
6373 * @dest: destination array
6374 * @dest_idx: index in the @dest array
6375 * @src: source pointer
6376 * @count: number of items
6378 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6379 * This function must be used when @klass contains references fields.
6380 * Overlap is handled.
6383 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6385 MONO_REQ_GC_UNSAFE_MODE;
6387 int size = mono_array_element_size (dest->obj.vtable->klass);
6388 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6389 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6390 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6394 * mono_object_get_domain:
6395 * @obj: object to query
6397 * Returns: the MonoDomain where the object is hosted
6400 mono_object_get_domain (MonoObject *obj)
6402 MONO_REQ_GC_UNSAFE_MODE;
6404 return mono_object_domain (obj);
6408 * mono_object_get_class:
6409 * @obj: object to query
6411 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6413 * Returns: the MonoClass of the object.
6416 mono_object_get_class (MonoObject *obj)
6418 MONO_REQ_GC_UNSAFE_MODE;
6420 return mono_object_class (obj);
6423 * mono_object_get_size:
6424 * @o: object to query
6426 * Returns: the size, in bytes, of @o
6429 mono_object_get_size (MonoObject* o)
6431 MONO_REQ_GC_UNSAFE_MODE;
6433 MonoClass* klass = mono_object_class (o);
6434 if (klass == mono_defaults.string_class) {
6435 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6436 } else if (o->vtable->rank) {
6437 MonoArray *array = (MonoArray*)o;
6438 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6439 if (array->bounds) {
6442 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6446 return mono_class_instance_size (klass);
6451 * mono_object_unbox:
6452 * @obj: object to unbox
6454 * Returns: a pointer to the start of the valuetype boxed in this
6457 * This method will assert if the object passed is not a valuetype.
6460 mono_object_unbox (MonoObject *obj)
6462 MONO_REQ_GC_UNSAFE_MODE;
6464 /* add assert for valuetypes? */
6465 g_assert (obj->vtable->klass->valuetype);
6466 return ((char*)obj) + sizeof (MonoObject);
6470 * mono_object_isinst:
6472 * @klass: a pointer to a class
6474 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6477 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6479 MONO_REQ_GC_UNSAFE_MODE;
6481 HANDLE_FUNCTION_ENTER ();
6482 MONO_HANDLE_DCL (MonoObject, obj);
6484 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6485 mono_error_cleanup (&error);
6486 HANDLE_FUNCTION_RETURN_OBJ (result);
6491 * mono_object_isinst_checked:
6493 * @klass: a pointer to a class
6494 * @error: set on error
6496 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6497 * On failure returns NULL and sets @error.
6500 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6502 MONO_REQ_GC_UNSAFE_MODE;
6504 HANDLE_FUNCTION_ENTER ();
6505 mono_error_init (error);
6506 MONO_HANDLE_DCL (MonoObject, obj);
6507 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6508 HANDLE_FUNCTION_RETURN_OBJ (result);
6512 * mono_object_handle_isinst:
6514 * @klass: a pointer to a class
6515 * @error: set on error
6517 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6518 * On failure returns NULL and sets @error.
6521 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6523 mono_error_init (error);
6526 mono_class_init (klass);
6528 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6529 return mono_object_handle_isinst_mbyref (obj, klass, error);
6532 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6534 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6535 MONO_HANDLE_ASSIGN (result, obj);
6540 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6542 MONO_REQ_GC_UNSAFE_MODE;
6544 HANDLE_FUNCTION_ENTER ();
6546 MONO_HANDLE_DCL (MonoObject, obj);
6547 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6548 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6549 HANDLE_FUNCTION_RETURN_OBJ (result);
6553 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6555 mono_error_init (error);
6557 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6559 if (MONO_HANDLE_IS_NULL (obj))
6562 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6564 if (mono_class_is_interface (klass)) {
6565 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6566 MONO_HANDLE_ASSIGN (result, obj);
6570 /* casting an array one of the invariant interfaces that must act as such */
6571 if (klass->is_array_special_interface) {
6572 if (mono_class_is_assignable_from (klass, vt->klass)) {
6573 MONO_HANDLE_ASSIGN (result, obj);
6578 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6579 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6580 MONO_HANDLE_ASSIGN (result, obj);
6584 MonoClass *oklass = vt->klass;
6585 if (mono_class_is_transparent_proxy (oklass)){
6586 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6587 oklass = remote_class->proxy_class;
6590 mono_class_setup_supertypes (klass);
6591 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6592 MONO_HANDLE_ASSIGN (result, obj);
6596 #ifndef DISABLE_REMOTING
6597 if (mono_class_is_transparent_proxy (vt->klass))
6599 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6600 if (!custom_type_info)
6602 MonoDomain *domain = mono_domain_get ();
6603 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6604 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6605 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6606 MonoMethod *im = NULL;
6609 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6611 mono_error_set_not_supported (error, "Linked away.");
6614 im = mono_object_handle_get_virtual_method (rp, im, error);
6619 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6623 pa [0] = MONO_HANDLE_RAW (reftype);
6624 pa [1] = MONO_HANDLE_RAW (obj);
6625 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6629 if (*(MonoBoolean *) mono_object_unbox(res)) {
6630 /* Update the vtable of the remote type, so it can safely cast to this new type */
6631 mono_upgrade_remote_class (domain, obj, klass, error);
6634 MONO_HANDLE_ASSIGN (result, obj);
6637 #endif /* DISABLE_REMOTING */
6643 * mono_object_castclass_mbyref:
6645 * @klass: a pointer to a class
6647 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6650 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6652 MONO_REQ_GC_UNSAFE_MODE;
6653 HANDLE_FUNCTION_ENTER ();
6655 MONO_HANDLE_DCL (MonoObject, obj);
6656 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6657 if (MONO_HANDLE_IS_NULL (obj))
6659 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6660 mono_error_cleanup (&error);
6662 HANDLE_FUNCTION_RETURN_OBJ (result);
6666 MonoDomain *orig_domain;
6672 str_lookup (MonoDomain *domain, gpointer user_data)
6674 MONO_REQ_GC_UNSAFE_MODE;
6676 LDStrInfo *info = (LDStrInfo *)user_data;
6677 if (info->res || domain == info->orig_domain)
6679 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6683 mono_string_get_pinned (MonoString *str, MonoError *error)
6685 MONO_REQ_GC_UNSAFE_MODE;
6687 mono_error_init (error);
6689 /* We only need to make a pinned version of a string if this is a moving GC */
6690 if (!mono_gc_is_moving ())
6694 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6695 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6697 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6698 news->length = mono_string_length (str);
6700 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6706 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6708 MONO_REQ_GC_UNSAFE_MODE;
6710 MonoGHashTable *ldstr_table;
6711 MonoString *s, *res;
6714 mono_error_init (error);
6716 domain = ((MonoObject *)str)->vtable->domain;
6717 ldstr_table = domain->ldstr_table;
6719 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6725 /* Allocate outside the lock */
6727 s = mono_string_get_pinned (str, error);
6728 return_val_if_nok (error, NULL);
6731 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6736 mono_g_hash_table_insert (ldstr_table, s, s);
6741 LDStrInfo ldstr_info;
6742 ldstr_info.orig_domain = domain;
6743 ldstr_info.ins = str;
6744 ldstr_info.res = NULL;
6746 mono_domain_foreach (str_lookup, &ldstr_info);
6747 if (ldstr_info.res) {
6749 * the string was already interned in some other domain:
6750 * intern it in the current one as well.
6752 mono_g_hash_table_insert (ldstr_table, str, str);
6762 * mono_string_is_interned:
6763 * @o: String to probe
6765 * Returns whether the string has been interned.
6768 mono_string_is_interned (MonoString *o)
6771 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6772 /* This function does not fail. */
6773 mono_error_assert_ok (&error);
6778 * mono_string_intern:
6779 * @o: String to intern
6781 * Interns the string passed.
6782 * Returns: The interned string.
6785 mono_string_intern (MonoString *str)
6788 MonoString *result = mono_string_intern_checked (str, &error);
6789 mono_error_assert_ok (&error);
6794 * mono_string_intern_checked:
6795 * @o: String to intern
6796 * @error: set on error.
6798 * Interns the string passed.
6799 * Returns: The interned string. On failure returns NULL and sets @error
6802 mono_string_intern_checked (MonoString *str, MonoError *error)
6804 MONO_REQ_GC_UNSAFE_MODE;
6806 mono_error_init (error);
6808 return mono_string_is_interned_lookup (str, TRUE, error);
6813 * @domain: the domain where the string will be used.
6814 * @image: a metadata context
6815 * @idx: index into the user string table.
6817 * Implementation for the ldstr opcode.
6818 * Returns: a loaded string from the @image/@idx combination.
6821 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6824 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6825 mono_error_cleanup (&error);
6830 * mono_ldstr_checked:
6831 * @domain: the domain where the string will be used.
6832 * @image: a metadata context
6833 * @idx: index into the user string table.
6834 * @error: set on error.
6836 * Implementation for the ldstr opcode.
6837 * Returns: a loaded string from the @image/@idx combination.
6838 * On failure returns NULL and sets @error.
6841 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6843 MONO_REQ_GC_UNSAFE_MODE;
6844 mono_error_init (error);
6846 if (image->dynamic) {
6847 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6850 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6851 return NULL; /*FIXME we should probably be raising an exception here*/
6852 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6858 * mono_ldstr_metadata_sig
6859 * @domain: the domain for the string
6860 * @sig: the signature of a metadata string
6861 * @error: set on error
6863 * Returns: a MonoString for a string stored in the metadata. On
6864 * failure returns NULL and sets @error.
6867 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6869 MONO_REQ_GC_UNSAFE_MODE;
6871 mono_error_init (error);
6872 const char *str = sig;
6873 MonoString *o, *interned;
6876 len2 = mono_metadata_decode_blob_size (str, &str);
6879 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6880 return_val_if_nok (error, NULL);
6881 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6884 guint16 *p2 = (guint16*)mono_string_chars (o);
6885 for (i = 0; i < len2; ++i) {
6886 *p2 = GUINT16_FROM_LE (*p2);
6892 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6895 return interned; /* o will get garbage collected */
6897 o = mono_string_get_pinned (o, error);
6900 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6902 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6914 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6918 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6924 GError *gerror = NULL;
6926 mono_error_init (error);
6928 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6929 return NULL; /*FIXME we should probably be raising an exception here*/
6930 str = mono_metadata_user_string (image, idx);
6932 len2 = mono_metadata_decode_blob_size (str, &str);
6935 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6937 mono_error_set_argument (error, "string", "%s", gerror->message);
6938 g_error_free (gerror);
6941 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6942 if (len2 > written) {
6943 /* allocate the total length and copy the part of the string that has been converted */
6944 char *as2 = (char *)g_malloc0 (len2);
6945 memcpy (as2, as, written);
6954 * mono_string_to_utf8:
6955 * @s: a System.String
6957 * Returns the UTF8 representation for @s.
6958 * The resulting buffer needs to be freed with mono_free().
6960 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6963 mono_string_to_utf8 (MonoString *s)
6965 MONO_REQ_GC_UNSAFE_MODE;
6968 char *result = mono_string_to_utf8_checked (s, &error);
6970 if (!is_ok (&error)) {
6971 mono_error_cleanup (&error);
6978 * mono_string_to_utf8_checked:
6979 * @s: a System.String
6980 * @error: a MonoError.
6982 * Converts a MonoString to its UTF8 representation. May fail; check
6983 * @error to determine whether the conversion was successful.
6984 * The resulting buffer should be freed with mono_free().
6987 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6989 MONO_REQ_GC_UNSAFE_MODE;
6993 GError *gerror = NULL;
6995 mono_error_init (error);
7001 return g_strdup ("");
7003 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7005 mono_error_set_argument (error, "string", "%s", gerror->message);
7006 g_error_free (gerror);
7009 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7010 if (s->length > written) {
7011 /* allocate the total length and copy the part of the string that has been converted */
7012 char *as2 = (char *)g_malloc0 (s->length);
7013 memcpy (as2, as, written);
7022 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7024 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7028 * mono_string_to_utf8_ignore:
7031 * Converts a MonoString to its UTF8 representation. Will ignore
7032 * invalid surrogate pairs.
7033 * The resulting buffer should be freed with mono_free().
7037 mono_string_to_utf8_ignore (MonoString *s)
7039 MONO_REQ_GC_UNSAFE_MODE;
7048 return g_strdup ("");
7050 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7052 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7053 if (s->length > written) {
7054 /* allocate the total length and copy the part of the string that has been converted */
7055 char *as2 = (char *)g_malloc0 (s->length);
7056 memcpy (as2, as, written);
7065 * mono_string_to_utf8_image_ignore:
7066 * @s: a System.String
7068 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7071 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7073 MONO_REQ_GC_UNSAFE_MODE;
7075 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7079 * mono_string_to_utf8_mp_ignore:
7080 * @s: a System.String
7082 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7085 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7087 MONO_REQ_GC_UNSAFE_MODE;
7089 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7094 * mono_string_to_utf16:
7097 * Return an null-terminated array of the utf-16 chars
7098 * contained in @s. The result must be freed with g_free().
7099 * This is a temporary helper until our string implementation
7100 * is reworked to always include the null terminating char.
7103 mono_string_to_utf16 (MonoString *s)
7105 MONO_REQ_GC_UNSAFE_MODE;
7112 as = (char *)g_malloc ((s->length * 2) + 2);
7113 as [(s->length * 2)] = '\0';
7114 as [(s->length * 2) + 1] = '\0';
7117 return (gunichar2 *)(as);
7120 memcpy (as, mono_string_chars(s), s->length * 2);
7121 return (gunichar2 *)(as);
7125 * mono_string_to_utf32:
7128 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7129 * contained in @s. The result must be freed with g_free().
7132 mono_string_to_utf32 (MonoString *s)
7134 MONO_REQ_GC_UNSAFE_MODE;
7136 mono_unichar4 *utf32_output = NULL;
7137 GError *error = NULL;
7138 glong items_written;
7143 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7146 g_error_free (error);
7148 return utf32_output;
7152 * mono_string_from_utf16:
7153 * @data: the UTF16 string (LPWSTR) to convert
7155 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7157 * Returns: a MonoString.
7160 mono_string_from_utf16 (gunichar2 *data)
7163 MonoString *result = mono_string_from_utf16_checked (data, &error);
7164 mono_error_cleanup (&error);
7169 * mono_string_from_utf16_checked:
7170 * @data: the UTF16 string (LPWSTR) to convert
7171 * @error: set on error
7173 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7175 * Returns: a MonoString. On failure sets @error and returns NULL.
7178 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7181 MONO_REQ_GC_UNSAFE_MODE;
7183 mono_error_init (error);
7184 MonoDomain *domain = mono_domain_get ();
7190 while (data [len]) len++;
7192 return mono_string_new_utf16_checked (domain, data, len, error);
7196 * mono_string_from_utf32:
7197 * @data: the UTF32 string (LPWSTR) to convert
7199 * Converts a UTF32 (UCS-4)to a MonoString.
7201 * Returns: a MonoString.
7204 mono_string_from_utf32 (mono_unichar4 *data)
7207 MonoString *result = mono_string_from_utf32_checked (data, &error);
7208 mono_error_cleanup (&error);
7213 * mono_string_from_utf32_checked:
7214 * @data: the UTF32 string (LPWSTR) to convert
7215 * @error: set on error
7217 * Converts a UTF32 (UCS-4)to a MonoString.
7219 * Returns: a MonoString. On failure returns NULL and sets @error.
7222 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7224 MONO_REQ_GC_UNSAFE_MODE;
7226 mono_error_init (error);
7227 MonoString* result = NULL;
7228 mono_unichar2 *utf16_output = NULL;
7229 GError *gerror = NULL;
7230 glong items_written;
7236 while (data [len]) len++;
7238 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7241 g_error_free (gerror);
7243 result = mono_string_from_utf16_checked (utf16_output, error);
7244 g_free (utf16_output);
7249 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7251 MONO_REQ_GC_UNSAFE_MODE;
7258 r = mono_string_to_utf8_ignore (s);
7260 r = mono_string_to_utf8_checked (s, error);
7261 if (!mono_error_ok (error))
7268 len = strlen (r) + 1;
7270 mp_s = (char *)mono_mempool_alloc (mp, len);
7272 mp_s = (char *)mono_image_alloc (image, len);
7274 memcpy (mp_s, r, len);
7282 * mono_string_to_utf8_image:
7283 * @s: a System.String
7285 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7288 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7290 MONO_REQ_GC_UNSAFE_MODE;
7292 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7296 * mono_string_to_utf8_mp:
7297 * @s: a System.String
7299 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7302 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7304 MONO_REQ_GC_UNSAFE_MODE;
7306 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7310 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7313 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7315 eh_callbacks = *cbs;
7318 MonoRuntimeExceptionHandlingCallbacks *
7319 mono_get_eh_callbacks (void)
7321 return &eh_callbacks;
7325 * mono_raise_exception:
7326 * @ex: exception object
7328 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7331 mono_raise_exception (MonoException *ex)
7333 MONO_REQ_GC_UNSAFE_MODE;
7336 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7337 * that will cause gcc to omit the function epilog, causing problems when
7338 * the JIT tries to walk the stack, since the return address on the stack
7339 * will point into the next function in the executable, not this one.
7341 eh_callbacks.mono_raise_exception (ex);
7345 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7347 MONO_REQ_GC_UNSAFE_MODE;
7349 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7353 * mono_wait_handle_new:
7354 * @domain: Domain where the object will be created
7355 * @handle: Handle for the wait handle
7356 * @error: set on error.
7358 * Returns: A new MonoWaitHandle created in the given domain for the
7359 * given handle. On failure returns NULL and sets @rror.
7362 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7364 MONO_REQ_GC_UNSAFE_MODE;
7366 MonoWaitHandle *res;
7367 gpointer params [1];
7368 static MonoMethod *handle_set;
7370 mono_error_init (error);
7371 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7372 return_val_if_nok (error, NULL);
7374 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7376 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7378 params [0] = &handle;
7380 mono_runtime_invoke_checked (handle_set, res, params, error);
7385 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7387 MONO_REQ_GC_UNSAFE_MODE;
7389 static MonoClassField *f_safe_handle = NULL;
7392 if (!f_safe_handle) {
7393 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7394 g_assert (f_safe_handle);
7397 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7403 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7405 MONO_REQ_GC_UNSAFE_MODE;
7407 RuntimeInvokeFunction runtime_invoke;
7409 mono_error_init (error);
7411 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7412 MonoMethod *method = mono_get_context_capture_method ();
7413 MonoMethod *wrapper;
7416 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7417 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7418 return_val_if_nok (error, NULL);
7419 domain->capture_context_method = mono_compile_method_checked (method, error);
7420 return_val_if_nok (error, NULL);
7423 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7425 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7428 * mono_async_result_new:
7429 * @domain:domain where the object will be created.
7430 * @handle: wait handle.
7431 * @state: state to pass to AsyncResult
7432 * @data: C closure data.
7433 * @error: set on error.
7435 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7436 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7437 * On failure returns NULL and sets @error.
7441 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7443 MONO_REQ_GC_UNSAFE_MODE;
7445 mono_error_init (error);
7446 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7447 return_val_if_nok (error, NULL);
7448 MonoObject *context = mono_runtime_capture_context (domain, error);
7449 return_val_if_nok (error, NULL);
7450 /* we must capture the execution context from the original thread */
7452 MONO_OBJECT_SETREF (res, execution_context, context);
7453 /* note: result may be null if the flow is suppressed */
7456 res->data = (void **)data;
7457 MONO_OBJECT_SETREF (res, object_data, object_data);
7458 MONO_OBJECT_SETREF (res, async_state, state);
7459 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7460 return_val_if_nok (error, NULL);
7462 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7464 res->sync_completed = FALSE;
7465 res->completed = FALSE;
7471 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7473 MONO_REQ_GC_UNSAFE_MODE;
7480 g_assert (ares->async_delegate);
7482 ac = (MonoAsyncCall*) ares->object_data;
7484 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7485 if (mono_error_set_pending_exception (&error))
7488 gpointer wait_event = NULL;
7490 ac->msg->exc = NULL;
7492 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7494 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7495 mono_threads_begin_abort_protected_block ();
7497 if (!ac->msg->exc) {
7498 MonoException *ex = mono_error_convert_to_exception (&error);
7499 ac->msg->exc = (MonoObject *)ex;
7501 mono_error_cleanup (&error);
7504 MONO_OBJECT_SETREF (ac, res, res);
7506 mono_monitor_enter ((MonoObject*) ares);
7507 ares->completed = 1;
7509 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7510 mono_monitor_exit ((MonoObject*) ares);
7512 if (wait_event != NULL)
7513 mono_w32event_set (wait_event);
7515 mono_error_init (&error); //the else branch would leave it in an undefined state
7517 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7519 mono_threads_end_abort_protected_block ();
7521 if (mono_error_set_pending_exception (&error))
7529 mono_message_init (MonoDomain *domain,
7530 MonoMethodMessage *this_obj,
7531 MonoReflectionMethod *method,
7532 MonoArray *out_args,
7535 MONO_REQ_GC_UNSAFE_MODE;
7537 static MonoMethod *init_message_method = NULL;
7539 if (!init_message_method) {
7540 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7541 g_assert (init_message_method != NULL);
7544 mono_error_init (error);
7545 /* FIXME set domain instead? */
7546 g_assert (domain == mono_domain_get ());
7553 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7554 return is_ok (error);
7557 #ifndef DISABLE_REMOTING
7559 * mono_remoting_invoke:
7560 * @real_proxy: pointer to a RealProxy object
7561 * @msg: The MonoMethodMessage to execute
7562 * @exc: used to store exceptions
7563 * @out_args: used to store output arguments
7565 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7566 * IMessage interface and it is not trivial to extract results from there. So
7567 * we call an helper method PrivateInvoke instead of calling
7568 * RealProxy::Invoke() directly.
7570 * Returns: the result object.
7573 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7575 MONO_REQ_GC_UNSAFE_MODE;
7578 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7583 mono_error_init (error);
7585 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7588 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7590 mono_error_set_not_supported (error, "Linked away.");
7593 real_proxy->vtable->domain->private_invoke_method = im;
7596 pa [0] = real_proxy;
7601 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7602 return_val_if_nok (error, NULL);
7609 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7610 MonoObject **exc, MonoArray **out_args, MonoError *error)
7612 MONO_REQ_GC_UNSAFE_MODE;
7614 static MonoClass *object_array_klass;
7615 mono_error_init (error);
7619 MonoMethodSignature *sig;
7621 int i, j, outarg_count = 0;
7623 #ifndef DISABLE_REMOTING
7624 if (target && mono_object_is_transparent_proxy (target)) {
7625 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7626 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7627 target = tp->rp->unwrapped_server;
7629 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7634 domain = mono_domain_get ();
7635 method = msg->method->method;
7636 sig = mono_method_signature (method);
7638 for (i = 0; i < sig->param_count; i++) {
7639 if (sig->params [i]->byref)
7643 if (!object_array_klass) {
7646 klass = mono_array_class_get (mono_defaults.object_class, 1);
7649 mono_memory_barrier ();
7650 object_array_klass = klass;
7653 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7654 return_val_if_nok (error, NULL);
7656 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7659 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7660 return_val_if_nok (error, NULL);
7662 for (i = 0, j = 0; i < sig->param_count; i++) {
7663 if (sig->params [i]->byref) {
7665 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7666 mono_array_setref (*out_args, j, arg);
7675 * prepare_to_string_method:
7677 * @target: Set to @obj or unboxed value if a valuetype
7679 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7682 prepare_to_string_method (MonoObject *obj, void **target)
7684 MONO_REQ_GC_UNSAFE_MODE;
7686 static MonoMethod *to_string = NULL;
7694 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7696 method = mono_object_get_virtual_method (obj, to_string);
7698 // Unbox value type if needed
7699 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7700 *target = mono_object_unbox (obj);
7706 * mono_object_to_string:
7708 * @exc: Any exception thrown by ToString (). May be NULL.
7710 * Returns: the result of calling ToString () on an object.
7713 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7716 MonoString *s = NULL;
7718 MonoMethod *method = prepare_to_string_method (obj, &target);
7720 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7721 if (*exc == NULL && !mono_error_ok (&error))
7722 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7724 mono_error_cleanup (&error);
7726 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7727 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7734 * mono_object_to_string_checked:
7736 * @error: Set on error.
7738 * Returns: the result of calling ToString () on an object. If the
7739 * method cannot be invoked or if it raises an exception, sets @error
7743 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7745 mono_error_init (error);
7747 MonoMethod *method = prepare_to_string_method (obj, &target);
7748 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7752 * mono_object_try_to_string:
7754 * @exc: Any exception thrown by ToString (). Must not be NULL.
7755 * @error: Set if method cannot be invoked.
7757 * Returns: the result of calling ToString () on an object. If the
7758 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7762 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7765 mono_error_init (error);
7767 MonoMethod *method = prepare_to_string_method (obj, &target);
7768 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7774 get_native_backtrace (MonoException *exc_raw)
7776 HANDLE_FUNCTION_ENTER ();
7777 MONO_HANDLE_DCL(MonoException, exc);
7778 char * trace = mono_exception_handle_get_native_backtrace (exc);
7779 HANDLE_FUNCTION_RETURN_VAL (trace);
7783 * mono_print_unhandled_exception:
7784 * @exc: The exception
7786 * Prints the unhandled exception.
7789 mono_print_unhandled_exception (MonoObject *exc)
7791 MONO_REQ_GC_UNSAFE_MODE;
7794 char *message = (char*)"";
7795 gboolean free_message = FALSE;
7798 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7799 message = g_strdup ("OutOfMemoryException");
7800 free_message = TRUE;
7801 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7802 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7803 free_message = TRUE;
7806 if (((MonoException*)exc)->native_trace_ips) {
7807 message = get_native_backtrace ((MonoException*)exc);
7808 free_message = TRUE;
7810 MonoObject *other_exc = NULL;
7811 str = mono_object_try_to_string (exc, &other_exc, &error);
7812 if (other_exc == NULL && !is_ok (&error))
7813 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7815 mono_error_cleanup (&error);
7817 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7818 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7820 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7821 original_backtrace, nested_backtrace);
7823 g_free (original_backtrace);
7824 g_free (nested_backtrace);
7825 free_message = TRUE;
7827 message = mono_string_to_utf8_checked (str, &error);
7828 if (!mono_error_ok (&error)) {
7829 mono_error_cleanup (&error);
7830 message = (char *) "";
7832 free_message = TRUE;
7839 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7840 * exc->vtable->klass->name, message);
7842 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7849 * mono_delegate_ctor_with_method:
7850 * @this: pointer to an uninitialized delegate object
7851 * @target: target object
7852 * @addr: pointer to native code
7854 * @error: set on error.
7856 * Initialize a delegate and sets a specific method, not the one
7857 * associated with addr. This is useful when sharing generic code.
7858 * In that case addr will most probably not be associated with the
7859 * correct instantiation of the method.
7860 * On failure returns FALSE and sets @error.
7863 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7865 MONO_REQ_GC_UNSAFE_MODE;
7867 mono_error_init (error);
7868 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7870 g_assert (this_obj);
7873 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7876 delegate->method = method;
7878 mono_stats.delegate_creations++;
7880 #ifndef DISABLE_REMOTING
7881 if (target && mono_object_is_transparent_proxy (target)) {
7883 method = mono_marshal_get_remoting_invoke (method);
7884 delegate->method_ptr = mono_compile_method_checked (method, error);
7885 return_val_if_nok (error, FALSE);
7886 MONO_OBJECT_SETREF (delegate, target, target);
7890 delegate->method_ptr = addr;
7891 MONO_OBJECT_SETREF (delegate, target, target);
7894 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7895 if (callbacks.init_delegate)
7896 callbacks.init_delegate (delegate);
7901 * mono_delegate_ctor:
7902 * @this: pointer to an uninitialized delegate object
7903 * @target: target object
7904 * @addr: pointer to native code
7905 * @error: set on error.
7907 * This is used to initialize a delegate.
7908 * On failure returns FALSE and sets @error.
7911 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7913 MONO_REQ_GC_UNSAFE_MODE;
7915 mono_error_init (error);
7916 MonoDomain *domain = mono_domain_get ();
7918 MonoMethod *method = NULL;
7922 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7924 if (!ji && domain != mono_get_root_domain ())
7925 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7927 method = mono_jit_info_get_method (ji);
7928 g_assert (!mono_class_is_gtd (method->klass));
7931 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7935 * mono_method_call_message_new:
7936 * @method: method to encapsulate
7937 * @params: parameters to the method
7938 * @invoke: optional, delegate invoke.
7939 * @cb: async callback delegate.
7940 * @state: state passed to the async callback.
7941 * @error: set on error.
7943 * Translates arguments pointers into a MonoMethodMessage.
7944 * On failure returns NULL and sets @error.
7947 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7948 MonoDelegate **cb, MonoObject **state, MonoError *error)
7950 MONO_REQ_GC_UNSAFE_MODE;
7952 mono_error_init (error);
7954 MonoDomain *domain = mono_domain_get ();
7955 MonoMethodSignature *sig = mono_method_signature (method);
7956 MonoMethodMessage *msg;
7959 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7960 return_val_if_nok (error, NULL);
7963 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7964 return_val_if_nok (error, NULL);
7965 mono_message_init (domain, msg, rm, NULL, error);
7966 return_val_if_nok (error, NULL);
7967 count = sig->param_count - 2;
7969 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7970 return_val_if_nok (error, NULL);
7971 mono_message_init (domain, msg, rm, NULL, error);
7972 return_val_if_nok (error, NULL);
7973 count = sig->param_count;
7976 for (i = 0; i < count; i++) {
7981 if (sig->params [i]->byref)
7982 vpos = *((gpointer *)params [i]);
7986 klass = mono_class_from_mono_type (sig->params [i]);
7988 if (klass->valuetype) {
7989 arg = mono_value_box_checked (domain, klass, vpos, error);
7990 return_val_if_nok (error, NULL);
7992 arg = *((MonoObject **)vpos);
7994 mono_array_setref (msg->args, i, arg);
7997 if (cb != NULL && state != NULL) {
7998 *cb = *((MonoDelegate **)params [i]);
8000 *state = *((MonoObject **)params [i]);
8007 * mono_method_return_message_restore:
8009 * Restore results from message based processing back to arguments pointers
8012 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8014 MONO_REQ_GC_UNSAFE_MODE;
8016 mono_error_init (error);
8018 MonoMethodSignature *sig = mono_method_signature (method);
8019 int i, j, type, size, out_len;
8021 if (out_args == NULL)
8023 out_len = mono_array_length (out_args);
8027 for (i = 0, j = 0; i < sig->param_count; i++) {
8028 MonoType *pt = sig->params [i];
8033 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8037 arg = (char *)mono_array_get (out_args, gpointer, j);
8040 g_assert (type != MONO_TYPE_VOID);
8042 if (MONO_TYPE_IS_REFERENCE (pt)) {
8043 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8046 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8047 size = mono_class_value_size (klass, NULL);
8048 if (klass->has_references)
8049 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8051 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8053 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8054 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8063 #ifndef DISABLE_REMOTING
8066 * mono_load_remote_field:
8067 * @this: pointer to an object
8068 * @klass: klass of the object containing @field
8069 * @field: the field to load
8070 * @res: a storage to store the result
8072 * This method is called by the runtime on attempts to load fields of
8073 * transparent proxy objects. @this points to such TP, @klass is the class of
8074 * the object containing @field. @res is a storage location which can be
8075 * used to store the result.
8077 * Returns: an address pointing to the value of field.
8080 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8083 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8084 mono_error_cleanup (&error);
8089 * mono_load_remote_field_checked:
8090 * @this: pointer to an object
8091 * @klass: klass of the object containing @field
8092 * @field: the field to load
8093 * @res: a storage to store the result
8094 * @error: set on error
8096 * This method is called by the runtime on attempts to load fields of
8097 * transparent proxy objects. @this points to such TP, @klass is the class of
8098 * the object containing @field. @res is a storage location which can be
8099 * used to store the result.
8101 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8104 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8106 MONO_REQ_GC_UNSAFE_MODE;
8108 static MonoMethod *getter = NULL;
8110 mono_error_init (error);
8112 MonoDomain *domain = mono_domain_get ();
8113 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8114 MonoClass *field_class;
8115 MonoMethodMessage *msg;
8116 MonoArray *out_args;
8120 g_assert (mono_object_is_transparent_proxy (this_obj));
8121 g_assert (res != NULL);
8123 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8124 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8129 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8131 mono_error_set_not_supported (error, "Linked away.");
8136 field_class = mono_class_from_mono_type (field->type);
8138 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8139 return_val_if_nok (error, NULL);
8140 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8141 return_val_if_nok (error, NULL);
8142 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8143 return_val_if_nok (error, NULL);
8144 mono_message_init (domain, msg, rm, out_args, error);
8145 return_val_if_nok (error, NULL);
8147 full_name = mono_type_get_full_name (klass);
8148 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8149 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8152 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8153 return_val_if_nok (error, NULL);
8156 mono_error_set_exception_instance (error, (MonoException *)exc);
8160 if (mono_array_length (out_args) == 0)
8163 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8165 if (field_class->valuetype) {
8166 return ((char *)*res) + sizeof (MonoObject);
8172 * mono_load_remote_field_new:
8177 * Missing documentation.
8180 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8184 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8185 mono_error_cleanup (&error);
8190 * mono_load_remote_field_new_checked:
8191 * @this: pointer to an object
8192 * @klass: klass of the object containing @field
8193 * @field: the field to load
8194 * @error: set on error.
8196 * This method is called by the runtime on attempts to load fields of
8197 * transparent proxy objects. @this points to such TP, @klass is the class of
8198 * the object containing @field.
8200 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8203 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8205 MONO_REQ_GC_UNSAFE_MODE;
8207 mono_error_init (error);
8209 static MonoMethod *tp_load = NULL;
8211 g_assert (mono_object_is_transparent_proxy (this_obj));
8214 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8216 mono_error_set_not_supported (error, "Linked away.");
8221 /* MonoType *type = mono_class_get_type (klass); */
8227 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8231 * mono_store_remote_field:
8232 * @this_obj: pointer to an object
8233 * @klass: klass of the object containing @field
8234 * @field: the field to load
8235 * @val: the value/object to store
8237 * This method is called by the runtime on attempts to store fields of
8238 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8239 * the object containing @field. @val is the new value to store in @field.
8242 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8245 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8246 mono_error_cleanup (&error);
8250 * mono_store_remote_field_checked:
8251 * @this_obj: pointer to an object
8252 * @klass: klass of the object containing @field
8253 * @field: the field to load
8254 * @val: the value/object to store
8255 * @error: set on error
8257 * This method is called by the runtime on attempts to store fields of
8258 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8259 * the object containing @field. @val is the new value to store in @field.
8261 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8264 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8267 MONO_REQ_GC_UNSAFE_MODE;
8269 mono_error_init (error);
8271 MonoDomain *domain = mono_domain_get ();
8272 MonoClass *field_class;
8275 g_assert (mono_object_is_transparent_proxy (this_obj));
8277 field_class = mono_class_from_mono_type (field->type);
8279 if (field_class->valuetype) {
8280 arg = mono_value_box_checked (domain, field_class, val, error);
8281 return_val_if_nok (error, FALSE);
8283 arg = *((MonoObject**)val);
8286 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8290 * mono_store_remote_field_new:
8296 * Missing documentation
8299 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8302 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8303 mono_error_cleanup (&error);
8307 * mono_store_remote_field_new_checked:
8314 * Missing documentation
8317 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8319 MONO_REQ_GC_UNSAFE_MODE;
8321 static MonoMethod *tp_store = NULL;
8323 mono_error_init (error);
8325 g_assert (mono_object_is_transparent_proxy (this_obj));
8328 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8330 mono_error_set_not_supported (error, "Linked away.");
8340 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8341 return is_ok (error);
8346 * mono_create_ftnptr:
8348 * Given a function address, create a function descriptor for it.
8349 * This is only needed on some platforms.
8352 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8354 return callbacks.create_ftnptr (domain, addr);
8358 * mono_get_addr_from_ftnptr:
8360 * Given a pointer to a function descriptor, return the function address.
8361 * This is only needed on some platforms.
8364 mono_get_addr_from_ftnptr (gpointer descr)
8366 return callbacks.get_addr_from_ftnptr (descr);
8370 * mono_string_chars:
8373 * Returns a pointer to the UCS16 characters stored in the MonoString
8376 mono_string_chars (MonoString *s)
8378 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8384 * mono_string_length:
8387 * Returns the lenght in characters of the string
8390 mono_string_length (MonoString *s)
8392 MONO_REQ_GC_UNSAFE_MODE;
8398 * mono_array_length:
8399 * @array: a MonoArray*
8401 * Returns the total number of elements in the array. This works for
8402 * both vectors and multidimensional arrays.
8405 mono_array_length (MonoArray *array)
8407 MONO_REQ_GC_UNSAFE_MODE;
8409 return array->max_length;
8413 * mono_array_addr_with_size:
8414 * @array: a MonoArray*
8415 * @size: size of the array elements
8416 * @idx: index into the array
8418 * Use this function to obtain the address for the @idx item on the
8419 * @array containing elements of size @size.
8421 * This method performs no bounds checking or type checking.
8423 * Returns the address of the @idx element in the array.
8426 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8428 MONO_REQ_GC_UNSAFE_MODE;
8430 return ((char*)(array)->vector) + size * idx;
8435 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8437 MonoDomain *domain = mono_domain_get ();
8441 mono_error_init (error);
8445 len = g_list_length (list);
8446 res = mono_array_new_checked (domain, eclass, len, error);
8447 return_val_if_nok (error, NULL);
8449 for (i = 0; list; list = list->next, i++)
8450 mono_array_set (res, gpointer, i, list->data);
8457 * The following section is purely to declare prototypes and
8458 * document the API, as these C files are processed by our
8464 * @array: array to alter
8465 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8466 * @index: index into the array
8467 * @value: value to set
8469 * Value Type version: This sets the @index's element of the @array
8470 * with elements of size sizeof(type) to the provided @value.
8472 * This macro does not attempt to perform type checking or bounds checking.
8474 * Use this to set value types in a `MonoArray`.
8476 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8481 * mono_array_setref:
8482 * @array: array to alter
8483 * @index: index into the array
8484 * @value: value to set
8486 * Reference Type version: This sets the @index's element of the
8487 * @array with elements of size sizeof(type) to the provided @value.
8489 * This macro does not attempt to perform type checking or bounds checking.
8491 * Use this to reference types in a `MonoArray`.
8493 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8499 * @array: array on which to operate on
8500 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8501 * @index: index into the array
8503 * Use this macro to retrieve the @index element of an @array and
8504 * extract the value assuming that the elements of the array match
8505 * the provided type value.
8507 * This method can be used with both arrays holding value types and
8508 * reference types. For reference types, the @type parameter should
8509 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8511 * This macro does not attempt to perform type checking or bounds checking.
8513 * Returns: The element at the @index position in the @array.
8515 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)