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/utils/w32api.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 gboolean got_pending_interrupt = 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);
488 //This can happen if the cctor self-aborts
489 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
492 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
493 if (!pending_tae && got_pending_interrupt)
494 pending_tae = mono_thread_try_resume_interruption ();
496 /* this just blocks until the initializing thread is done */
497 mono_type_init_lock (lock);
498 mono_type_init_unlock (lock);
501 mono_type_initialization_lock ();
502 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
503 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
504 --lock->waiting_count;
505 if (lock->waiting_count == 0) {
506 mono_coop_mutex_destroy (&lock->initialization_section);
507 g_hash_table_remove (type_initialization_hash, vtable);
510 mono_memory_barrier ();
511 if (!vtable->init_failed)
512 vtable->initialized = 1;
513 mono_type_initialization_unlock ();
517 mono_error_set_exception_instance (error, pending_tae);
518 else if (vtable->init_failed) {
519 /* Either we were the initializing thread or we waited for the initialization */
520 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
527 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
529 MONO_REQ_GC_NEUTRAL_MODE;
531 MonoVTable *vtable = (MonoVTable*)key;
533 TypeInitializationLock *lock = (TypeInitializationLock*) value;
534 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
537 * Have to set this since it cannot be set by the normal code in
538 * mono_runtime_class_init (). In this case, the exception object is not stored,
539 * and get_type_init_exception_for_class () needs to be aware of this.
541 vtable->init_failed = 1;
542 mono_type_init_unlock (lock);
543 --lock->waiting_count;
544 if (lock->waiting_count == 0) {
545 mono_coop_mutex_destroy (&lock->initialization_section);
554 mono_release_type_locks (MonoInternalThread *thread)
556 MONO_REQ_GC_UNSAFE_MODE;
558 mono_type_initialization_lock ();
559 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
560 mono_type_initialization_unlock ();
563 #ifndef DISABLE_REMOTING
566 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
568 if (!callbacks.create_remoting_trampoline)
569 g_error ("remoting not installed");
570 return callbacks.create_remoting_trampoline (domain, method, target, error);
575 static MonoImtTrampolineBuilder imt_trampoline_builder;
576 static gboolean always_build_imt_trampolines;
578 #if (MONO_IMT_SIZE > 32)
579 #error "MONO_IMT_SIZE cannot be larger than 32"
583 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
585 memcpy (&callbacks, cbs, sizeof (*cbs));
588 MonoRuntimeCallbacks*
589 mono_get_runtime_callbacks (void)
595 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
597 imt_trampoline_builder = func;
601 mono_set_always_build_imt_trampolines (gboolean value)
603 always_build_imt_trampolines = value;
607 * mono_compile_method:
608 * @method: The method to compile.
610 * This JIT-compiles the method, and returns the pointer to the native code
614 mono_compile_method (MonoMethod *method)
617 gpointer result = mono_compile_method_checked (method, &error);
618 mono_error_cleanup (&error);
623 * mono_compile_method:
624 * @method: The method to compile.
625 * @error: set on error.
627 * This JIT-compiles the method, and returns the pointer to the native code
628 * produced. On failure returns NULL and sets @error.
631 mono_compile_method_checked (MonoMethod *method, MonoError *error)
635 MONO_REQ_GC_NEUTRAL_MODE
637 mono_error_init (error);
639 g_assert (callbacks.compile_method);
640 res = callbacks.compile_method (method, error);
645 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
649 MONO_REQ_GC_NEUTRAL_MODE;
651 mono_error_init (error);
652 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
657 mono_runtime_create_delegate_trampoline (MonoClass *klass)
659 MONO_REQ_GC_NEUTRAL_MODE
661 g_assert (callbacks.create_delegate_trampoline);
662 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
666 * mono_runtime_free_method:
667 * @domain; domain where the method is hosted
668 * @method: method to release
670 * This routine is invoked to free the resources associated with
671 * a method that has been JIT compiled. This is used to discard
672 * methods that were used only temporarily (for example, used in marshalling)
676 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
678 MONO_REQ_GC_NEUTRAL_MODE
680 if (callbacks.free_method)
681 callbacks.free_method (domain, method);
683 mono_method_clear_object (domain, method);
685 mono_free_method (method);
689 * The vtables in the root appdomain are assumed to be reachable by other
690 * roots, and we don't use typed allocation in the other domains.
693 /* The sync block is no longer a GC pointer */
694 #define GC_HEADER_BITMAP (0)
696 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
699 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
701 MONO_REQ_GC_NEUTRAL_MODE;
703 MonoClassField *field;
709 max_size = mono_class_data_size (klass) / sizeof (gpointer);
711 max_size = klass->instance_size / sizeof (gpointer);
712 if (max_size > size) {
713 g_assert (offset <= 0);
714 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
719 /*An Ephemeron cannot be marked by sgen*/
720 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
722 memset (bitmap, 0, size / 8);
727 for (p = klass; p != NULL; p = p->parent) {
728 gpointer iter = NULL;
729 while ((field = mono_class_get_fields (p, &iter))) {
733 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
735 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
738 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
741 /* FIXME: should not happen, flag as type load error */
742 if (field->type->byref)
745 if (static_fields && field->offset == -1)
749 pos = field->offset / sizeof (gpointer);
752 type = mono_type_get_underlying_type (field->type);
753 switch (type->type) {
756 case MONO_TYPE_FNPTR:
758 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
763 if (klass->image != mono_defaults.corlib)
766 case MONO_TYPE_STRING:
767 case MONO_TYPE_SZARRAY:
768 case MONO_TYPE_CLASS:
769 case MONO_TYPE_OBJECT:
770 case MONO_TYPE_ARRAY:
771 g_assert ((field->offset % sizeof(gpointer)) == 0);
773 g_assert (pos < size || pos <= max_size);
774 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
775 *max_set = MAX (*max_set, pos);
777 case MONO_TYPE_GENERICINST:
778 if (!mono_type_generic_inst_is_valuetype (type)) {
779 g_assert ((field->offset % sizeof(gpointer)) == 0);
781 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
782 *max_set = MAX (*max_set, pos);
787 case MONO_TYPE_VALUETYPE: {
788 MonoClass *fclass = mono_class_from_mono_type (field->type);
789 if (fclass->has_references) {
790 /* remove the object header */
791 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
805 case MONO_TYPE_BOOLEAN:
809 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
820 * mono_class_compute_bitmap:
822 * Mono internal function to compute a bitmap of reference fields in a class.
825 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
827 MONO_REQ_GC_NEUTRAL_MODE;
829 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
834 * similar to the above, but sets the bits in the bitmap for any non-ref field
835 * and ignores static fields
838 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
840 MonoClassField *field;
845 max_size = class->instance_size / sizeof (gpointer);
846 if (max_size >= size) {
847 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
850 for (p = class; p != NULL; p = p->parent) {
851 gpointer iter = NULL;
852 while ((field = mono_class_get_fields (p, &iter))) {
855 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
857 /* FIXME: should not happen, flag as type load error */
858 if (field->type->byref)
861 pos = field->offset / sizeof (gpointer);
864 type = mono_type_get_underlying_type (field->type);
865 switch (type->type) {
866 #if SIZEOF_VOID_P == 8
870 case MONO_TYPE_FNPTR:
875 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
876 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
877 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
880 #if SIZEOF_VOID_P == 4
884 case MONO_TYPE_FNPTR:
889 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
890 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
891 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
897 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
898 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
899 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
902 case MONO_TYPE_BOOLEAN:
905 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
907 case MONO_TYPE_STRING:
908 case MONO_TYPE_SZARRAY:
909 case MONO_TYPE_CLASS:
910 case MONO_TYPE_OBJECT:
911 case MONO_TYPE_ARRAY:
913 case MONO_TYPE_GENERICINST:
914 if (!mono_type_generic_inst_is_valuetype (type)) {
919 case MONO_TYPE_VALUETYPE: {
920 MonoClass *fclass = mono_class_from_mono_type (field->type);
921 /* remove the object header */
922 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
926 g_assert_not_reached ();
935 * mono_class_insecure_overlapping:
936 * check if a class with explicit layout has references and non-references
937 * fields overlapping.
939 * Returns: TRUE if it is insecure to load the type.
942 mono_class_insecure_overlapping (MonoClass *klass)
946 gsize default_bitmap [4] = {0};
948 gsize default_nrbitmap [4] = {0};
949 int i, insecure = FALSE;
952 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
953 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
955 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
956 int idx = i % (sizeof (bitmap [0]) * 8);
957 if (bitmap [idx] & nrbitmap [idx]) {
962 if (bitmap != default_bitmap)
964 if (nrbitmap != default_nrbitmap)
967 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
975 ves_icall_string_alloc (int length)
978 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
979 mono_error_set_pending_exception (&error);
984 /* LOCKING: Acquires the loader lock */
986 mono_class_compute_gc_descriptor (MonoClass *klass)
988 MONO_REQ_GC_NEUTRAL_MODE;
992 gsize default_bitmap [4] = {0};
993 static gboolean gcj_inited = FALSE;
994 MonoGCDescriptor gc_descr;
999 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1000 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1003 mono_loader_unlock ();
1007 mono_class_init (klass);
1009 if (klass->gc_descr_inited)
1012 bitmap = default_bitmap;
1013 if (klass == mono_defaults.string_class) {
1014 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1015 } else if (klass->rank) {
1016 mono_class_compute_gc_descriptor (klass->element_class);
1017 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1019 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1020 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1021 class->name_space, class->name);*/
1023 /* remove the object header */
1024 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1025 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));
1026 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1027 class->name_space, class->name);*/
1028 if (bitmap != default_bitmap)
1032 /*static int count = 0;
1035 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1036 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1038 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1039 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1041 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1042 if (bitmap != default_bitmap)
1046 /* Publish the data */
1047 mono_loader_lock ();
1048 klass->gc_descr = gc_descr;
1049 mono_memory_barrier ();
1050 klass->gc_descr_inited = TRUE;
1051 mono_loader_unlock ();
1055 * field_is_special_static:
1056 * @fklass: The MonoClass to look up.
1057 * @field: The MonoClassField describing the field.
1059 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1060 * SPECIAL_STATIC_NONE otherwise.
1063 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1065 MONO_REQ_GC_NEUTRAL_MODE;
1068 MonoCustomAttrInfo *ainfo;
1070 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1071 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1074 for (i = 0; i < ainfo->num_attrs; ++i) {
1075 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1076 if (klass->image == mono_defaults.corlib) {
1077 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1078 mono_custom_attrs_free (ainfo);
1079 return SPECIAL_STATIC_THREAD;
1081 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1082 mono_custom_attrs_free (ainfo);
1083 return SPECIAL_STATIC_CONTEXT;
1087 mono_custom_attrs_free (ainfo);
1088 return SPECIAL_STATIC_NONE;
1091 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1092 #define mix(a,b,c) { \
1093 a -= c; a ^= rot(c, 4); c += b; \
1094 b -= a; b ^= rot(a, 6); a += c; \
1095 c -= b; c ^= rot(b, 8); b += a; \
1096 a -= c; a ^= rot(c,16); c += b; \
1097 b -= a; b ^= rot(a,19); a += c; \
1098 c -= b; c ^= rot(b, 4); b += a; \
1100 #define final(a,b,c) { \
1101 c ^= b; c -= rot(b,14); \
1102 a ^= c; a -= rot(c,11); \
1103 b ^= a; b -= rot(a,25); \
1104 c ^= b; c -= rot(b,16); \
1105 a ^= c; a -= rot(c,4); \
1106 b ^= a; b -= rot(a,14); \
1107 c ^= b; c -= rot(b,24); \
1111 * mono_method_get_imt_slot:
1113 * The IMT slot is embedded into AOTed code, so this must return the same value
1114 * for the same method across all executions. This means:
1115 * - pointers shouldn't be used as hash values.
1116 * - mono_metadata_str_hash () should be used for hashing strings.
1119 mono_method_get_imt_slot (MonoMethod *method)
1121 MONO_REQ_GC_NEUTRAL_MODE;
1123 MonoMethodSignature *sig;
1125 guint32 *hashes_start, *hashes;
1129 /* This can be used to stress tests the collision code */
1133 * We do this to simplify generic sharing. It will hurt
1134 * performance in cases where a class implements two different
1135 * instantiations of the same generic interface.
1136 * The code in build_imt_slots () depends on this.
1138 if (method->is_inflated)
1139 method = ((MonoMethodInflated*)method)->declaring;
1141 sig = mono_method_signature (method);
1142 hashes_count = sig->param_count + 4;
1143 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1144 hashes = hashes_start;
1146 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1147 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1148 method->klass->name_space, method->klass->name, method->name);
1151 /* Initialize hashes */
1152 hashes [0] = mono_metadata_str_hash (method->klass->name);
1153 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1154 hashes [2] = mono_metadata_str_hash (method->name);
1155 hashes [3] = mono_metadata_type_hash (sig->ret);
1156 for (i = 0; i < sig->param_count; i++) {
1157 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1160 /* Setup internal state */
1161 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1163 /* Handle most of the hashes */
1164 while (hashes_count > 3) {
1173 /* Handle the last 3 hashes (all the case statements fall through) */
1174 switch (hashes_count) {
1175 case 3 : c += hashes [2];
1176 case 2 : b += hashes [1];
1177 case 1 : a += hashes [0];
1179 case 0: /* nothing left to add */
1183 g_free (hashes_start);
1184 /* Report the result */
1185 return c % MONO_IMT_SIZE;
1194 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1195 MONO_REQ_GC_NEUTRAL_MODE;
1197 guint32 imt_slot = mono_method_get_imt_slot (method);
1198 MonoImtBuilderEntry *entry;
1200 if (slot_num >= 0 && imt_slot != slot_num) {
1201 /* we build just a single imt slot and this is not it */
1205 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1206 entry->key = method;
1207 entry->value.vtable_slot = vtable_slot;
1208 entry->next = imt_builder [imt_slot];
1209 if (imt_builder [imt_slot] != NULL) {
1210 entry->children = imt_builder [imt_slot]->children + 1;
1211 if (entry->children == 1) {
1212 mono_stats.imt_slots_with_collisions++;
1213 *imt_collisions_bitmap |= (1 << imt_slot);
1216 entry->children = 0;
1217 mono_stats.imt_used_slots++;
1219 imt_builder [imt_slot] = entry;
1222 char *method_name = mono_method_full_name (method, TRUE);
1223 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1224 method, method_name, imt_slot, vtable_slot, entry->children);
1225 g_free (method_name);
1232 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1234 MonoMethod *method = e->key;
1235 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1239 method->klass->name_space,
1240 method->klass->name,
1243 printf (" * %s: NULL\n", message);
1249 compare_imt_builder_entries (const void *p1, const void *p2) {
1250 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1251 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1253 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1257 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1259 MONO_REQ_GC_NEUTRAL_MODE;
1261 int count = end - start;
1262 int chunk_start = out_array->len;
1265 for (i = start; i < end; ++i) {
1266 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1267 item->key = sorted_array [i]->key;
1268 item->value = sorted_array [i]->value;
1269 item->has_target_code = sorted_array [i]->has_target_code;
1270 item->is_equals = TRUE;
1272 item->check_target_idx = out_array->len + 1;
1274 item->check_target_idx = 0;
1275 g_ptr_array_add (out_array, item);
1278 int middle = start + count / 2;
1279 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1281 item->key = sorted_array [middle]->key;
1282 item->is_equals = FALSE;
1283 g_ptr_array_add (out_array, item);
1284 imt_emit_ir (sorted_array, start, middle, out_array);
1285 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1291 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1292 MONO_REQ_GC_NEUTRAL_MODE;
1294 int number_of_entries = entries->children + 1;
1295 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1296 GPtrArray *result = g_ptr_array_new ();
1297 MonoImtBuilderEntry *current_entry;
1300 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1301 sorted_array [i] = current_entry;
1303 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1305 /*for (i = 0; i < number_of_entries; i++) {
1306 print_imt_entry (" sorted array:", sorted_array [i], i);
1309 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1311 g_free (sorted_array);
1316 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1318 MONO_REQ_GC_NEUTRAL_MODE;
1320 if (imt_builder_entry != NULL) {
1321 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1322 /* No collision, return the vtable slot contents */
1323 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1325 /* Collision, build the trampoline */
1326 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1329 result = imt_trampoline_builder (vtable, domain,
1330 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1331 for (i = 0; i < imt_ir->len; ++i)
1332 g_free (g_ptr_array_index (imt_ir, i));
1333 g_ptr_array_free (imt_ir, TRUE);
1345 static MonoImtBuilderEntry*
1346 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1349 * LOCKING: requires the loader and domain locks.
1353 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1355 MONO_REQ_GC_NEUTRAL_MODE;
1359 guint32 imt_collisions_bitmap = 0;
1360 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1361 int method_count = 0;
1362 gboolean record_method_count_for_max_collisions = FALSE;
1363 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1366 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1368 for (i = 0; i < klass->interface_offsets_count; ++i) {
1369 MonoClass *iface = klass->interfaces_packed [i];
1370 int interface_offset = klass->interface_offsets_packed [i];
1371 int method_slot_in_interface, vt_slot;
1373 if (mono_class_has_variant_generic_params (iface))
1374 has_variant_iface = TRUE;
1376 mono_class_setup_methods (iface);
1377 vt_slot = interface_offset;
1378 int mcount = mono_class_get_method_count (iface);
1379 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1382 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1384 * The imt slot of the method is the same as for its declaring method,
1385 * see the comment in mono_method_get_imt_slot (), so we can
1386 * avoid inflating methods which will be discarded by
1387 * add_imt_builder_entry anyway.
1389 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1390 if (mono_method_get_imt_slot (method) != slot_num) {
1395 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1396 if (method->is_generic) {
1397 has_generic_virtual = TRUE;
1402 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1403 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1408 if (extra_interfaces) {
1409 int interface_offset = klass->vtable_size;
1411 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1412 MonoClass* iface = (MonoClass *)list_item->data;
1413 int method_slot_in_interface;
1414 int mcount = mono_class_get_method_count (iface);
1415 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1416 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1418 if (method->is_generic)
1419 has_generic_virtual = TRUE;
1420 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1422 interface_offset += mcount;
1425 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1426 /* overwrite the imt slot only if we're building all the entries or if
1427 * we're building this specific one
1429 if (slot_num < 0 || i == slot_num) {
1430 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1433 if (imt_builder [i]) {
1434 MonoImtBuilderEntry *entry;
1436 /* Link entries with imt_builder [i] */
1437 for (entry = entries; entry->next; entry = entry->next) {
1439 MonoMethod *method = (MonoMethod*)entry->key;
1440 char *method_name = mono_method_full_name (method, TRUE);
1441 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1442 g_free (method_name);
1445 entry->next = imt_builder [i];
1446 entries->children += imt_builder [i]->children + 1;
1448 imt_builder [i] = entries;
1451 if (has_generic_virtual || has_variant_iface) {
1453 * There might be collisions later when the the trampoline is expanded.
1455 imt_collisions_bitmap |= (1 << i);
1458 * The IMT trampoline might be called with an instance of one of the
1459 * generic virtual methods, so has to fallback to the IMT trampoline.
1461 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1463 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1466 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1470 if (imt_builder [i] != NULL) {
1471 int methods_in_slot = imt_builder [i]->children + 1;
1472 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1473 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1474 record_method_count_for_max_collisions = TRUE;
1476 method_count += methods_in_slot;
1480 mono_stats.imt_number_of_methods += method_count;
1481 if (record_method_count_for_max_collisions) {
1482 mono_stats.imt_method_count_when_max_collisions = method_count;
1485 for (i = 0; i < MONO_IMT_SIZE; i++) {
1486 MonoImtBuilderEntry* entry = imt_builder [i];
1487 while (entry != NULL) {
1488 MonoImtBuilderEntry* next = entry->next;
1493 g_free (imt_builder);
1494 /* we OR the bitmap since we may build just a single imt slot at a time */
1495 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1499 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1500 MONO_REQ_GC_NEUTRAL_MODE;
1502 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1506 * mono_vtable_build_imt_slot:
1507 * @vtable: virtual object table struct
1508 * @imt_slot: slot in the IMT table
1510 * Fill the given @imt_slot in the IMT table of @vtable with
1511 * a trampoline or a trampoline for the case of collisions.
1512 * This is part of the internal mono API.
1514 * LOCKING: Take the domain lock.
1517 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1519 MONO_REQ_GC_NEUTRAL_MODE;
1521 gpointer *imt = (gpointer*)vtable;
1522 imt -= MONO_IMT_SIZE;
1523 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1525 /* no support for extra interfaces: the proxy objects will need
1526 * to build the complete IMT
1527 * Update and heck needs to ahppen inside the proper domain lock, as all
1528 * the changes made to a MonoVTable.
1530 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1531 mono_domain_lock (vtable->domain);
1532 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1533 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1534 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1535 mono_domain_unlock (vtable->domain);
1536 mono_loader_unlock ();
1539 #define THUNK_THRESHOLD 10
1542 * mono_method_alloc_generic_virtual_trampoline:
1544 * @size: size in bytes
1546 * Allocs size bytes to be used for the code of a generic virtual
1547 * trampoline. It's either allocated from the domain's code manager or
1548 * reused from a previously invalidated piece.
1550 * LOCKING: The domain lock must be held.
1553 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1555 MONO_REQ_GC_NEUTRAL_MODE;
1557 static gboolean inited = FALSE;
1558 static int generic_virtual_trampolines_size = 0;
1561 mono_counters_register ("Generic virtual trampoline bytes",
1562 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1565 generic_virtual_trampolines_size += size;
1567 return mono_domain_code_reserve (domain, size);
1570 typedef struct _GenericVirtualCase {
1574 struct _GenericVirtualCase *next;
1575 } GenericVirtualCase;
1578 * get_generic_virtual_entries:
1580 * Return IMT entries for the generic virtual method instances and
1581 * variant interface methods for vtable slot
1584 static MonoImtBuilderEntry*
1585 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1587 MONO_REQ_GC_NEUTRAL_MODE;
1589 GenericVirtualCase *list;
1590 MonoImtBuilderEntry *entries;
1592 mono_domain_lock (domain);
1593 if (!domain->generic_virtual_cases)
1594 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1596 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1599 for (; list; list = list->next) {
1600 MonoImtBuilderEntry *entry;
1602 if (list->count < THUNK_THRESHOLD)
1605 entry = g_new0 (MonoImtBuilderEntry, 1);
1606 entry->key = list->method;
1607 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1608 entry->has_target_code = 1;
1610 entry->children = entries->children + 1;
1611 entry->next = entries;
1615 mono_domain_unlock (domain);
1617 /* FIXME: Leaking memory ? */
1622 * mono_method_add_generic_virtual_invocation:
1624 * @vtable_slot: pointer to the vtable slot
1625 * @method: the inflated generic virtual method
1626 * @code: the method's code
1628 * Registers a call via unmanaged code to a generic virtual method
1629 * instantiation or variant interface method. If the number of calls reaches a threshold
1630 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1631 * virtual method trampoline.
1634 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1635 gpointer *vtable_slot,
1636 MonoMethod *method, gpointer code)
1638 MONO_REQ_GC_NEUTRAL_MODE;
1640 static gboolean inited = FALSE;
1641 static int num_added = 0;
1642 static int num_freed = 0;
1644 GenericVirtualCase *gvc, *list;
1645 MonoImtBuilderEntry *entries;
1649 mono_domain_lock (domain);
1650 if (!domain->generic_virtual_cases)
1651 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1654 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1655 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1659 /* Check whether the case was already added */
1660 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1663 if (gvc->method == method)
1668 /* If not found, make a new one */
1670 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1671 gvc->method = method;
1674 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1676 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1681 if (++gvc->count == THUNK_THRESHOLD) {
1682 gpointer *old_thunk = (void **)*vtable_slot;
1683 gpointer vtable_trampoline = NULL;
1684 gpointer imt_trampoline = NULL;
1686 if ((gpointer)vtable_slot < (gpointer)vtable) {
1687 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1688 int imt_slot = MONO_IMT_SIZE + displacement;
1690 /* Force the rebuild of the trampoline at the next call */
1691 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1692 *vtable_slot = imt_trampoline;
1694 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1696 entries = get_generic_virtual_entries (domain, vtable_slot);
1698 sorted = imt_sort_slot_entries (entries);
1700 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1704 MonoImtBuilderEntry *next = entries->next;
1709 for (i = 0; i < sorted->len; ++i)
1710 g_free (g_ptr_array_index (sorted, i));
1711 g_ptr_array_free (sorted, TRUE);
1713 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1718 mono_domain_unlock (domain);
1721 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1724 * mono_class_vtable:
1725 * @domain: the application domain
1726 * @class: the class to initialize
1728 * VTables are domain specific because we create domain specific code, and
1729 * they contain the domain specific static class data.
1730 * On failure, NULL is returned, and class->exception_type is set.
1733 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1736 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1737 mono_error_cleanup (&error);
1742 * mono_class_vtable_full:
1743 * @domain: the application domain
1744 * @class: the class to initialize
1745 * @error set on failure.
1747 * VTables are domain specific because we create domain specific code, and
1748 * they contain the domain specific static class data.
1751 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1753 MONO_REQ_GC_UNSAFE_MODE;
1755 MonoClassRuntimeInfo *runtime_info;
1757 mono_error_init (error);
1761 if (mono_class_has_failure (klass)) {
1762 mono_error_set_for_class_failure (error, klass);
1766 /* this check can be inlined in jitted code, too */
1767 runtime_info = klass->runtime_info;
1768 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1769 return runtime_info->domain_vtables [domain->domain_id];
1770 return mono_class_create_runtime_vtable (domain, klass, error);
1774 * mono_class_try_get_vtable:
1775 * @domain: the application domain
1776 * @class: the class to initialize
1778 * This function tries to get the associated vtable from @class if
1779 * it was already created.
1782 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1784 MONO_REQ_GC_NEUTRAL_MODE;
1786 MonoClassRuntimeInfo *runtime_info;
1790 runtime_info = klass->runtime_info;
1791 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1792 return runtime_info->domain_vtables [domain->domain_id];
1797 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1799 MONO_REQ_GC_NEUTRAL_MODE;
1801 size_t alloc_offset;
1804 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1805 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1806 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1808 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1809 g_assert ((imt_table_bytes & 7) == 4);
1816 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1820 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1822 MONO_REQ_GC_UNSAFE_MODE;
1825 MonoClassRuntimeInfo *runtime_info, *old_info;
1826 MonoClassField *field;
1828 int i, vtable_slots;
1829 size_t imt_table_bytes;
1831 guint32 vtable_size, class_size;
1833 gpointer *interface_offsets;
1835 mono_error_init (error);
1837 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1838 mono_domain_lock (domain);
1839 runtime_info = klass->runtime_info;
1840 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1841 mono_domain_unlock (domain);
1842 mono_loader_unlock ();
1843 return runtime_info->domain_vtables [domain->domain_id];
1845 if (!klass->inited || mono_class_has_failure (klass)) {
1846 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1847 mono_domain_unlock (domain);
1848 mono_loader_unlock ();
1849 mono_error_set_for_class_failure (error, klass);
1854 /* Array types require that their element type be valid*/
1855 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1856 MonoClass *element_class = klass->element_class;
1857 if (!element_class->inited)
1858 mono_class_init (element_class);
1860 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1861 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1862 mono_class_setup_vtable (element_class);
1864 if (mono_class_has_failure (element_class)) {
1865 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1866 if (!mono_class_has_failure (klass))
1867 mono_class_set_type_load_failure (klass, "");
1868 mono_domain_unlock (domain);
1869 mono_loader_unlock ();
1870 mono_error_set_for_class_failure (error, klass);
1876 * For some classes, mono_class_init () already computed klass->vtable_size, and
1877 * that is all that is needed because of the vtable trampolines.
1879 if (!klass->vtable_size)
1880 mono_class_setup_vtable (klass);
1882 if (mono_class_is_ginst (klass) && !klass->vtable)
1883 mono_class_check_vtable_constraints (klass, NULL);
1885 /* Initialize klass->has_finalize */
1886 mono_class_has_finalizer (klass);
1888 if (mono_class_has_failure (klass)) {
1889 mono_domain_unlock (domain);
1890 mono_loader_unlock ();
1891 mono_error_set_for_class_failure (error, klass);
1895 vtable_slots = klass->vtable_size;
1896 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1897 class_size = mono_class_data_size (klass);
1901 if (klass->interface_offsets_count) {
1902 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1903 mono_stats.imt_number_of_tables++;
1904 mono_stats.imt_tables_size += imt_table_bytes;
1906 imt_table_bytes = 0;
1909 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1911 mono_stats.used_class_count++;
1912 mono_stats.class_vtable_size += vtable_size;
1914 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1915 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1916 g_assert (!((gsize)vt & 7));
1919 vt->rank = klass->rank;
1920 vt->domain = domain;
1922 mono_class_compute_gc_descriptor (klass);
1924 * We can't use typed allocation in the non-root domains, since the
1925 * collector needs the GC descriptor stored in the vtable even after
1926 * the mempool containing the vtable is destroyed when the domain is
1927 * unloaded. An alternative might be to allocate vtables in the GC
1928 * heap, but this does not seem to work (it leads to crashes inside
1929 * libgc). If that approach is tried, two gc descriptors need to be
1930 * allocated for each class: one for the root domain, and one for all
1931 * other domains. The second descriptor should contain a bit for the
1932 * vtable field in MonoObject, since we can no longer assume the
1933 * vtable is reachable by other roots after the appdomain is unloaded.
1935 #ifdef HAVE_BOEHM_GC
1936 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1937 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1940 vt->gc_descr = klass->gc_descr;
1942 gc_bits = mono_gc_get_vtable_bits (klass);
1943 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1945 vt->gc_bits = gc_bits;
1948 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1949 if (klass->has_static_refs) {
1950 MonoGCDescriptor statics_gc_descr;
1952 gsize default_bitmap [4] = {0};
1955 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1956 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1957 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1958 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1959 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1960 if (bitmap != default_bitmap)
1963 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1965 vt->has_static_fields = TRUE;
1966 mono_stats.class_static_data_size += class_size;
1970 while ((field = mono_class_get_fields (klass, &iter))) {
1971 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1973 if (mono_field_is_deleted (field))
1975 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1976 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
1977 if (special_static != SPECIAL_STATIC_NONE) {
1978 guint32 size, offset;
1980 gsize default_bitmap [4] = {0};
1985 if (mono_type_is_reference (field->type)) {
1986 default_bitmap [0] = 1;
1988 bitmap = default_bitmap;
1989 } else if (mono_type_is_struct (field->type)) {
1990 fclass = mono_class_from_mono_type (field->type);
1991 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1992 numbits = max_set + 1;
1994 default_bitmap [0] = 0;
1996 bitmap = default_bitmap;
1998 size = mono_type_size (field->type, &align);
1999 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2000 if (!domain->special_static_fields)
2001 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2002 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2003 if (bitmap != default_bitmap)
2006 * This marks the field as special static to speed up the
2007 * checks in mono_field_static_get/set_value ().
2013 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2014 MonoClass *fklass = mono_class_from_mono_type (field->type);
2015 const char *data = mono_field_get_data (field);
2017 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2018 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2019 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2022 if (fklass->valuetype) {
2023 memcpy (t, data, mono_class_value_size (fklass, NULL));
2025 /* it's a pointer type: add check */
2026 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2033 vt->max_interface_id = klass->max_interface_id;
2034 vt->interface_bitmap = klass->interface_bitmap;
2036 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2037 // class->name, klass->interface_offsets_count);
2039 /* Initialize vtable */
2040 if (callbacks.get_vtable_trampoline) {
2041 // This also covers the AOT case
2042 for (i = 0; i < klass->vtable_size; ++i) {
2043 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2046 mono_class_setup_vtable (klass);
2048 for (i = 0; i < klass->vtable_size; ++i) {
2051 cm = klass->vtable [i];
2053 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2054 if (!is_ok (error)) {
2055 mono_domain_unlock (domain);
2056 mono_loader_unlock ();
2063 if (imt_table_bytes) {
2064 /* Now that the vtable is full, we can actually fill up the IMT */
2065 for (i = 0; i < MONO_IMT_SIZE; ++i)
2066 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2070 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2071 * re-acquire them and check if another thread has created the vtable in the meantime.
2073 /* Special case System.MonoType to avoid infinite recursion */
2074 if (klass != mono_defaults.runtimetype_class) {
2075 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2076 if (!is_ok (error)) {
2077 mono_domain_unlock (domain);
2078 mono_loader_unlock ();
2082 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2083 /* This is unregistered in
2084 unregister_vtable_reflection_type() in
2086 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2089 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2091 /* class_vtable_array keeps an array of created vtables
2093 g_ptr_array_add (domain->class_vtable_array, vt);
2094 /* klass->runtime_info is protected by the loader lock, both when
2095 * it it enlarged and when it is stored info.
2099 * Store the vtable in klass->runtime_info.
2100 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2102 mono_memory_barrier ();
2104 old_info = klass->runtime_info;
2105 if (old_info && old_info->max_domain >= domain->domain_id) {
2106 /* someone already created a large enough runtime info */
2107 old_info->domain_vtables [domain->domain_id] = vt;
2109 int new_size = domain->domain_id;
2111 new_size = MAX (new_size, old_info->max_domain);
2113 /* make the new size a power of two */
2115 while (new_size > i)
2118 /* this is a bounded memory retention issue: may want to
2119 * handle it differently when we'll have a rcu-like system.
2121 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2122 runtime_info->max_domain = new_size - 1;
2123 /* copy the stuff from the older info */
2125 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2127 runtime_info->domain_vtables [domain->domain_id] = vt;
2129 mono_memory_barrier ();
2130 klass->runtime_info = runtime_info;
2133 if (klass == mono_defaults.runtimetype_class) {
2134 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2135 if (!is_ok (error)) {
2136 mono_domain_unlock (domain);
2137 mono_loader_unlock ();
2141 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2142 /* This is unregistered in
2143 unregister_vtable_reflection_type() in
2145 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2148 mono_domain_unlock (domain);
2149 mono_loader_unlock ();
2151 /* make sure the parent is initialized */
2152 /*FIXME shouldn't this fail the current type?*/
2154 mono_class_vtable_full (domain, klass->parent, error);
2159 #ifndef DISABLE_REMOTING
2161 * mono_class_proxy_vtable:
2162 * @domain: the application domain
2163 * @remove_class: the remote class
2164 * @error: set on error
2166 * Creates a vtable for transparent proxies. It is basically
2167 * a copy of the real vtable of the class wrapped in @remote_class,
2168 * but all function pointers invoke the remoting functions, and
2169 * vtable->klass points to the transparent proxy class, and not to @class.
2171 * On failure returns NULL and sets @error
2174 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2176 MONO_REQ_GC_UNSAFE_MODE;
2178 MonoVTable *vt, *pvt;
2179 int i, j, vtsize, extra_interface_vtsize = 0;
2180 guint32 max_interface_id;
2182 GSList *extra_interfaces = NULL;
2183 MonoClass *klass = remote_class->proxy_class;
2184 gpointer *interface_offsets;
2185 uint8_t *bitmap = NULL;
2187 size_t imt_table_bytes;
2189 #ifdef COMPRESSED_INTERFACE_BITMAP
2193 mono_error_init (error);
2195 vt = mono_class_vtable (domain, klass);
2196 g_assert (vt); /*FIXME property handle failure*/
2197 max_interface_id = vt->max_interface_id;
2199 /* Calculate vtable space for extra interfaces */
2200 for (j = 0; j < remote_class->interface_count; j++) {
2201 MonoClass* iclass = remote_class->interfaces[j];
2205 /*FIXME test for interfaces with variant generic arguments*/
2206 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2207 continue; /* interface implemented by the class */
2208 if (g_slist_find (extra_interfaces, iclass))
2211 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2213 method_count = mono_class_num_methods (iclass);
2215 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2219 for (i = 0; i < ifaces->len; ++i) {
2220 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2221 /*FIXME test for interfaces with variant generic arguments*/
2222 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2223 continue; /* interface implemented by the class */
2224 if (g_slist_find (extra_interfaces, ic))
2226 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2227 method_count += mono_class_num_methods (ic);
2229 g_ptr_array_free (ifaces, TRUE);
2233 extra_interface_vtsize += method_count * sizeof (gpointer);
2234 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2237 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2238 mono_stats.imt_number_of_tables++;
2239 mono_stats.imt_tables_size += imt_table_bytes;
2241 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2243 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2245 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2246 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2247 g_assert (!((gsize)pvt & 7));
2249 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2251 pvt->klass = mono_defaults.transparent_proxy_class;
2252 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2253 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2255 /* initialize vtable */
2256 mono_class_setup_vtable (klass);
2257 for (i = 0; i < klass->vtable_size; ++i) {
2260 if ((cm = klass->vtable [i])) {
2261 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2265 pvt->vtable [i] = NULL;
2268 if (mono_class_is_abstract (klass)) {
2269 /* create trampolines for abstract methods */
2270 for (k = klass; k; k = k->parent) {
2272 gpointer iter = NULL;
2273 while ((m = mono_class_get_methods (k, &iter)))
2274 if (!pvt->vtable [m->slot]) {
2275 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2282 pvt->max_interface_id = max_interface_id;
2283 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2284 #ifdef COMPRESSED_INTERFACE_BITMAP
2285 bitmap = (uint8_t *)g_malloc0 (bsize);
2287 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2290 for (i = 0; i < klass->interface_offsets_count; ++i) {
2291 int interface_id = klass->interfaces_packed [i]->interface_id;
2292 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2295 if (extra_interfaces) {
2296 int slot = klass->vtable_size;
2302 /* Create trampolines for the methods of the interfaces */
2303 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2304 interf = (MonoClass *)list_item->data;
2306 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2310 while ((cm = mono_class_get_methods (interf, &iter))) {
2311 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2316 slot += mono_class_num_methods (interf);
2320 /* Now that the vtable is full, we can actually fill up the IMT */
2321 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2322 if (extra_interfaces) {
2323 g_slist_free (extra_interfaces);
2326 #ifdef COMPRESSED_INTERFACE_BITMAP
2327 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2328 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2329 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2332 pvt->interface_bitmap = bitmap;
2336 if (extra_interfaces)
2337 g_slist_free (extra_interfaces);
2338 #ifdef COMPRESSED_INTERFACE_BITMAP
2344 #endif /* DISABLE_REMOTING */
2347 * mono_class_field_is_special_static:
2349 * Returns whether @field is a thread/context static field.
2352 mono_class_field_is_special_static (MonoClassField *field)
2354 MONO_REQ_GC_NEUTRAL_MODE
2356 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2358 if (mono_field_is_deleted (field))
2360 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2361 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2368 * mono_class_field_get_special_static_type:
2369 * @field: The MonoClassField describing the field.
2371 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2372 * SPECIAL_STATIC_NONE otherwise.
2375 mono_class_field_get_special_static_type (MonoClassField *field)
2377 MONO_REQ_GC_NEUTRAL_MODE
2379 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2380 return SPECIAL_STATIC_NONE;
2381 if (mono_field_is_deleted (field))
2382 return SPECIAL_STATIC_NONE;
2383 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2384 return field_is_special_static (field->parent, field);
2385 return SPECIAL_STATIC_NONE;
2389 * mono_class_has_special_static_fields:
2391 * Returns whenever @klass has any thread/context static fields.
2394 mono_class_has_special_static_fields (MonoClass *klass)
2396 MONO_REQ_GC_NEUTRAL_MODE
2398 MonoClassField *field;
2402 while ((field = mono_class_get_fields (klass, &iter))) {
2403 g_assert (field->parent == klass);
2404 if (mono_class_field_is_special_static (field))
2411 #ifndef DISABLE_REMOTING
2413 * create_remote_class_key:
2414 * Creates an array of pointers that can be used as a hash key for a remote class.
2415 * The first element of the array is the number of pointers.
2418 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2420 MONO_REQ_GC_NEUTRAL_MODE;
2425 if (remote_class == NULL) {
2426 if (mono_class_is_interface (extra_class)) {
2427 key = (void **)g_malloc (sizeof(gpointer) * 3);
2428 key [0] = GINT_TO_POINTER (2);
2429 key [1] = mono_defaults.marshalbyrefobject_class;
2430 key [2] = extra_class;
2432 key = (void **)g_malloc (sizeof(gpointer) * 2);
2433 key [0] = GINT_TO_POINTER (1);
2434 key [1] = extra_class;
2437 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2438 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2439 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2440 key [1] = remote_class->proxy_class;
2442 // Keep the list of interfaces sorted
2443 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2444 if (extra_class && remote_class->interfaces [i] > extra_class) {
2445 key [j++] = extra_class;
2448 key [j] = remote_class->interfaces [i];
2451 key [j] = extra_class;
2453 // Replace the old class. The interface list is the same
2454 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2455 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2456 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2457 for (i = 0; i < remote_class->interface_count; i++)
2458 key [2 + i] = remote_class->interfaces [i];
2466 * copy_remote_class_key:
2468 * Make a copy of KEY in the domain and return the copy.
2471 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2473 MONO_REQ_GC_NEUTRAL_MODE
2475 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2476 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2478 memcpy (mp_key, key, key_size);
2484 * mono_remote_class:
2485 * @domain: the application domain
2486 * @class_name: name of the remote class
2487 * @error: set on error
2489 * Creates and initializes a MonoRemoteClass object for a remote type.
2491 * On failure returns NULL and sets @error
2494 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2496 MONO_REQ_GC_UNSAFE_MODE;
2498 MonoRemoteClass *rc;
2499 gpointer* key, *mp_key;
2502 mono_error_init (error);
2504 key = create_remote_class_key (NULL, proxy_class);
2506 mono_domain_lock (domain);
2507 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2511 mono_domain_unlock (domain);
2515 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2516 if (!is_ok (error)) {
2518 mono_domain_unlock (domain);
2522 mp_key = copy_remote_class_key (domain, key);
2526 if (mono_class_is_interface (proxy_class)) {
2527 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2528 rc->interface_count = 1;
2529 rc->interfaces [0] = proxy_class;
2530 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2532 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2533 rc->interface_count = 0;
2534 rc->proxy_class = proxy_class;
2537 rc->default_vtable = NULL;
2538 rc->xdomain_vtable = NULL;
2539 rc->proxy_class_name = name;
2540 #ifndef DISABLE_PERFCOUNTERS
2541 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2544 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2546 mono_domain_unlock (domain);
2551 * clone_remote_class:
2552 * Creates a copy of the remote_class, adding the provided class or interface
2554 static MonoRemoteClass*
2555 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2557 MONO_REQ_GC_NEUTRAL_MODE;
2559 MonoRemoteClass *rc;
2560 gpointer* key, *mp_key;
2562 key = create_remote_class_key (remote_class, extra_class);
2563 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2569 mp_key = copy_remote_class_key (domain, key);
2573 if (mono_class_is_interface (extra_class)) {
2575 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2576 rc->proxy_class = remote_class->proxy_class;
2577 rc->interface_count = remote_class->interface_count + 1;
2579 // Keep the list of interfaces sorted, since the hash key of
2580 // the remote class depends on this
2581 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2582 if (remote_class->interfaces [i] > extra_class && i == j)
2583 rc->interfaces [j++] = extra_class;
2584 rc->interfaces [j] = remote_class->interfaces [i];
2587 rc->interfaces [j] = extra_class;
2589 // Replace the old class. The interface array is the same
2590 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2591 rc->proxy_class = extra_class;
2592 rc->interface_count = remote_class->interface_count;
2593 if (rc->interface_count > 0)
2594 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2597 rc->default_vtable = NULL;
2598 rc->xdomain_vtable = NULL;
2599 rc->proxy_class_name = remote_class->proxy_class_name;
2601 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2607 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2609 MONO_REQ_GC_UNSAFE_MODE;
2611 mono_error_init (error);
2613 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2614 mono_domain_lock (domain);
2615 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2616 if (target_domain_id != -1) {
2617 if (remote_class->xdomain_vtable == NULL)
2618 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2619 mono_domain_unlock (domain);
2620 mono_loader_unlock ();
2621 return_val_if_nok (error, NULL);
2622 return remote_class->xdomain_vtable;
2624 if (remote_class->default_vtable == NULL) {
2625 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2626 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2628 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2629 MonoClass *klass = mono_class_from_mono_type (type);
2631 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)))
2632 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2635 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2636 /* N.B. both branches of the if modify error */
2637 if (!is_ok (error)) {
2638 mono_domain_unlock (domain);
2639 mono_loader_unlock ();
2644 mono_domain_unlock (domain);
2645 mono_loader_unlock ();
2646 return remote_class->default_vtable;
2650 * mono_upgrade_remote_class:
2651 * @domain: the application domain
2652 * @tproxy: the proxy whose remote class has to be upgraded.
2653 * @klass: class to which the remote class can be casted.
2654 * @error: set on error
2656 * Updates the vtable of the remote class by adding the necessary method slots
2657 * and interface offsets so it can be safely casted to klass. klass can be a
2658 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2661 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2663 MONO_REQ_GC_UNSAFE_MODE;
2665 mono_error_init (error);
2667 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2668 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2670 gboolean redo_vtable;
2671 if (mono_class_is_interface (klass)) {
2674 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2675 if (remote_class->interfaces [i] == klass)
2676 redo_vtable = FALSE;
2679 redo_vtable = (remote_class->proxy_class != klass);
2682 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2683 mono_domain_lock (domain);
2685 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2686 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2687 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2688 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2689 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2695 mono_domain_unlock (domain);
2696 mono_loader_unlock ();
2697 return is_ok (error);
2699 #endif /* DISABLE_REMOTING */
2703 * mono_object_get_virtual_method:
2704 * @obj: object to operate on.
2707 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2708 * the instance of a callvirt of method.
2711 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2713 MONO_REQ_GC_UNSAFE_MODE;
2714 HANDLE_FUNCTION_ENTER ();
2716 MONO_HANDLE_DCL (MonoObject, obj);
2717 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2718 mono_error_assert_ok (&error);
2719 HANDLE_FUNCTION_RETURN_VAL (result);
2723 * mono_object_get_virtual_method:
2724 * @obj: object to operate on.
2727 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2728 * the instance of a callvirt of method.
2731 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2733 mono_error_init (error);
2735 gboolean is_proxy = FALSE;
2736 MonoClass *klass = mono_handle_class (obj);
2737 if (mono_class_is_transparent_proxy (klass)) {
2738 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2739 klass = remote_class->proxy_class;
2742 return class_get_virtual_method (klass, method, is_proxy, error);
2746 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2748 mono_error_init (error);
2751 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2754 mono_class_setup_vtable (klass);
2755 MonoMethod **vtable = klass->vtable;
2757 if (method->slot == -1) {
2758 /* method->slot might not be set for instances of generic methods */
2759 if (method->is_inflated) {
2760 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2761 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2764 g_assert_not_reached ();
2768 MonoMethod *res = NULL;
2769 /* check method->slot is a valid index: perform isinstance? */
2770 if (method->slot != -1) {
2771 if (mono_class_is_interface (method->klass)) {
2773 gboolean variance_used = FALSE;
2774 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2775 g_assert (iface_offset > 0);
2776 res = vtable [iface_offset + method->slot];
2779 res = vtable [method->slot];
2783 #ifndef DISABLE_REMOTING
2785 /* It may be an interface, abstract class method or generic method */
2786 if (!res || mono_method_signature (res)->generic_param_count)
2789 /* generic methods demand invoke_with_check */
2790 if (mono_method_signature (res)->generic_param_count)
2791 res = mono_marshal_get_remoting_invoke_with_check (res);
2794 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2795 res = mono_cominterop_get_invoke (res);
2798 res = mono_marshal_get_remoting_invoke (res);
2803 if (method->is_inflated) {
2804 /* Have to inflate the result */
2805 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2813 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2815 MONO_REQ_GC_UNSAFE_MODE;
2817 MonoObject *result = NULL;
2819 g_assert (callbacks.runtime_invoke);
2821 mono_error_init (error);
2823 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2824 mono_profiler_method_start_invoke (method);
2826 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2828 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2829 mono_profiler_method_end_invoke (method);
2831 if (!mono_error_ok (error))
2838 * mono_runtime_invoke:
2839 * @method: method to invoke
2840 * @obJ: object instance
2841 * @params: arguments to the method
2842 * @exc: exception information.
2844 * Invokes the method represented by @method on the object @obj.
2846 * obj is the 'this' pointer, it should be NULL for static
2847 * methods, a MonoObject* for object instances and a pointer to
2848 * the value type for value types.
2850 * The params array contains the arguments to the method with the
2851 * same convention: MonoObject* pointers for object instances and
2852 * pointers to the value type otherwise.
2854 * From unmanaged code you'll usually use the
2855 * mono_runtime_invoke() variant.
2857 * Note that this function doesn't handle virtual methods for
2858 * you, it will exec the exact method you pass: we still need to
2859 * expose a function to lookup the derived class implementation
2860 * of a virtual method (there are examples of this in the code,
2863 * You can pass NULL as the exc argument if you don't want to
2864 * catch exceptions, otherwise, *exc will be set to the exception
2865 * thrown, if any. if an exception is thrown, you can't use the
2866 * MonoObject* result from the function.
2868 * If the method returns a value type, it is boxed in an object
2872 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2877 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2878 if (*exc == NULL && !mono_error_ok(&error)) {
2879 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2881 mono_error_cleanup (&error);
2883 res = mono_runtime_invoke_checked (method, obj, params, &error);
2884 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2890 * mono_runtime_try_invoke:
2891 * @method: method to invoke
2892 * @obJ: object instance
2893 * @params: arguments to the method
2894 * @exc: exception information.
2895 * @error: set on error
2897 * Invokes the method represented by @method on the object @obj.
2899 * obj is the 'this' pointer, it should be NULL for static
2900 * methods, a MonoObject* for object instances and a pointer to
2901 * the value type for value types.
2903 * The params array contains the arguments to the method with the
2904 * same convention: MonoObject* pointers for object instances and
2905 * pointers to the value type otherwise.
2907 * From unmanaged code you'll usually use the
2908 * mono_runtime_invoke() variant.
2910 * Note that this function doesn't handle virtual methods for
2911 * you, it will exec the exact method you pass: we still need to
2912 * expose a function to lookup the derived class implementation
2913 * of a virtual method (there are examples of this in the code,
2916 * For this function, you must not pass NULL as the exc argument if
2917 * you don't want to catch exceptions, use
2918 * mono_runtime_invoke_checked(). If an exception is thrown, you
2919 * can't use the MonoObject* result from the function.
2921 * If this method cannot be invoked, @error will be set and @exc and
2922 * the return value must not be used.
2924 * If the method returns a value type, it is boxed in an object
2928 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2930 MONO_REQ_GC_UNSAFE_MODE;
2932 g_assert (exc != NULL);
2934 if (mono_runtime_get_no_exec ())
2935 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2937 return do_runtime_invoke (method, obj, params, exc, error);
2941 * mono_runtime_invoke_checked:
2942 * @method: method to invoke
2943 * @obJ: object instance
2944 * @params: arguments to the method
2945 * @error: set on error
2947 * Invokes the method represented by @method on the object @obj.
2949 * obj is the 'this' pointer, it should be NULL for static
2950 * methods, a MonoObject* for object instances and a pointer to
2951 * the value type for value types.
2953 * The params array contains the arguments to the method with the
2954 * same convention: MonoObject* pointers for object instances and
2955 * pointers to the value type otherwise.
2957 * From unmanaged code you'll usually use the
2958 * mono_runtime_invoke() variant.
2960 * Note that this function doesn't handle virtual methods for
2961 * you, it will exec the exact method you pass: we still need to
2962 * expose a function to lookup the derived class implementation
2963 * of a virtual method (there are examples of this in the code,
2966 * If an exception is thrown, you can't use the MonoObject* result
2967 * from the function.
2969 * If this method cannot be invoked, @error will be set. If the
2970 * method throws an exception (and we're in coop mode) the exception
2971 * will be set in @error.
2973 * If the method returns a value type, it is boxed in an object
2977 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
2979 MONO_REQ_GC_UNSAFE_MODE;
2981 if (mono_runtime_get_no_exec ())
2982 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2984 return do_runtime_invoke (method, obj, params, NULL, error);
2988 * mono_method_get_unmanaged_thunk:
2989 * @method: method to generate a thunk for.
2991 * Returns an unmanaged->managed thunk that can be used to call
2992 * a managed method directly from C.
2994 * The thunk's C signature closely matches the managed signature:
2996 * C#: public bool Equals (object obj);
2997 * C: typedef MonoBoolean (*Equals)(MonoObject*,
2998 * MonoObject*, MonoException**);
3000 * The 1st ("this") parameter must not be used with static methods:
3002 * C#: public static bool ReferenceEquals (object a, object b);
3003 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3006 * The last argument must be a non-null pointer of a MonoException* pointer.
3007 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3008 * exception has been thrown in managed code. Otherwise it will point
3009 * to the MonoException* caught by the thunk. In this case, the result of
3010 * the thunk is undefined:
3012 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3013 * MonoException *ex = NULL;
3014 * Equals func = mono_method_get_unmanaged_thunk (method);
3015 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3017 * // handle exception
3020 * The calling convention of the thunk matches the platform's default
3021 * convention. This means that under Windows, C declarations must
3022 * contain the __stdcall attribute:
3024 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3025 * MonoObject*, MonoException**);
3029 * Value type arguments and return values are treated as they were objects:
3031 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3032 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3034 * Arguments must be properly boxed upon trunk's invocation, while return
3035 * values must be unboxed.
3038 mono_method_get_unmanaged_thunk (MonoMethod *method)
3040 MONO_REQ_GC_NEUTRAL_MODE;
3041 MONO_REQ_API_ENTRYPOINT;
3046 g_assert (!mono_threads_is_coop_enabled ());
3048 MONO_ENTER_GC_UNSAFE;
3049 method = mono_marshal_get_thunk_invoke_wrapper (method);
3050 res = mono_compile_method_checked (method, &error);
3051 mono_error_cleanup (&error);
3052 MONO_EXIT_GC_UNSAFE;
3058 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3060 MONO_REQ_GC_UNSAFE_MODE;
3064 /* object fields cannot be byref, so we don't need a
3066 gpointer *p = (gpointer*)dest;
3073 case MONO_TYPE_BOOLEAN:
3075 case MONO_TYPE_U1: {
3076 guint8 *p = (guint8*)dest;
3077 *p = value ? *(guint8*)value : 0;
3082 case MONO_TYPE_CHAR: {
3083 guint16 *p = (guint16*)dest;
3084 *p = value ? *(guint16*)value : 0;
3087 #if SIZEOF_VOID_P == 4
3092 case MONO_TYPE_U4: {
3093 gint32 *p = (gint32*)dest;
3094 *p = value ? *(gint32*)value : 0;
3097 #if SIZEOF_VOID_P == 8
3102 case MONO_TYPE_U8: {
3103 gint64 *p = (gint64*)dest;
3104 *p = value ? *(gint64*)value : 0;
3107 case MONO_TYPE_R4: {
3108 float *p = (float*)dest;
3109 *p = value ? *(float*)value : 0;
3112 case MONO_TYPE_R8: {
3113 double *p = (double*)dest;
3114 *p = value ? *(double*)value : 0;
3117 case MONO_TYPE_STRING:
3118 case MONO_TYPE_SZARRAY:
3119 case MONO_TYPE_CLASS:
3120 case MONO_TYPE_OBJECT:
3121 case MONO_TYPE_ARRAY:
3122 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3124 case MONO_TYPE_FNPTR:
3125 case MONO_TYPE_PTR: {
3126 gpointer *p = (gpointer*)dest;
3127 *p = deref_pointer? *(gpointer*)value: value;
3130 case MONO_TYPE_VALUETYPE:
3131 /* note that 't' and 'type->type' can be different */
3132 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3133 t = mono_class_enum_basetype (type->data.klass)->type;
3136 MonoClass *klass = mono_class_from_mono_type (type);
3137 int size = mono_class_value_size (klass, NULL);
3139 mono_gc_bzero_atomic (dest, size);
3141 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3144 case MONO_TYPE_GENERICINST:
3145 t = type->data.generic_class->container_class->byval_arg.type;
3148 g_error ("got type %x", type->type);
3153 * mono_field_set_value:
3154 * @obj: Instance object
3155 * @field: MonoClassField describing the field to set
3156 * @value: The value to be set
3158 * Sets the value of the field described by @field in the object instance @obj
3159 * to the value passed in @value. This method should only be used for instance
3160 * fields. For static fields, use mono_field_static_set_value.
3162 * The value must be on the native format of the field type.
3165 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3167 MONO_REQ_GC_UNSAFE_MODE;
3171 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3173 dest = (char*)obj + field->offset;
3174 mono_copy_value (field->type, dest, value, FALSE);
3178 * mono_field_static_set_value:
3179 * @field: MonoClassField describing the field to set
3180 * @value: The value to be set
3182 * Sets the value of the static field described by @field
3183 * to the value passed in @value.
3185 * The value must be on the native format of the field type.
3188 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3190 MONO_REQ_GC_UNSAFE_MODE;
3194 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3195 /* you cant set a constant! */
3196 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3198 if (field->offset == -1) {
3199 /* Special static */
3202 mono_domain_lock (vt->domain);
3203 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3204 mono_domain_unlock (vt->domain);
3205 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3207 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3209 mono_copy_value (field->type, dest, value, FALSE);
3213 * mono_vtable_get_static_field_data:
3215 * Internal use function: return a pointer to the memory holding the static fields
3216 * for a class or NULL if there are no static fields.
3217 * This is exported only for use by the debugger.
3220 mono_vtable_get_static_field_data (MonoVTable *vt)
3222 MONO_REQ_GC_NEUTRAL_MODE
3224 if (!vt->has_static_fields)
3226 return vt->vtable [vt->klass->vtable_size];
3230 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3232 MONO_REQ_GC_UNSAFE_MODE;
3236 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3237 if (field->offset == -1) {
3238 /* Special static */
3241 mono_domain_lock (vt->domain);
3242 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3243 mono_domain_unlock (vt->domain);
3244 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3246 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3249 src = (guint8*)obj + field->offset;
3256 * mono_field_get_value:
3257 * @obj: Object instance
3258 * @field: MonoClassField describing the field to fetch information from
3259 * @value: pointer to the location where the value will be stored
3261 * Use this routine to get the value of the field @field in the object
3264 * The pointer provided by value must be of the field type, for reference
3265 * types this is a MonoObject*, for value types its the actual pointer to
3270 * mono_field_get_value (obj, int_field, &i);
3273 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3275 MONO_REQ_GC_UNSAFE_MODE;
3281 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3283 src = (char*)obj + field->offset;
3284 mono_copy_value (field->type, value, src, TRUE);
3288 * mono_field_get_value_object:
3289 * @domain: domain where the object will be created (if boxing)
3290 * @field: MonoClassField describing the field to fetch information from
3291 * @obj: The object instance for the field.
3293 * Returns: a new MonoObject with the value from the given field. If the
3294 * field represents a value type, the value is boxed.
3298 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3301 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3302 mono_error_assert_ok (&error);
3307 * mono_field_get_value_object_checked:
3308 * @domain: domain where the object will be created (if boxing)
3309 * @field: MonoClassField describing the field to fetch information from
3310 * @obj: The object instance for the field.
3311 * @error: Set on error.
3313 * Returns: a new MonoObject with the value from the given field. If the
3314 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3318 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3320 MONO_REQ_GC_UNSAFE_MODE;
3322 mono_error_init (error);
3326 MonoVTable *vtable = NULL;
3328 gboolean is_static = FALSE;
3329 gboolean is_ref = FALSE;
3330 gboolean is_literal = FALSE;
3331 gboolean is_ptr = FALSE;
3332 MonoType *type = mono_field_get_type_checked (field, error);
3334 return_val_if_nok (error, NULL);
3336 switch (type->type) {
3337 case MONO_TYPE_STRING:
3338 case MONO_TYPE_OBJECT:
3339 case MONO_TYPE_CLASS:
3340 case MONO_TYPE_ARRAY:
3341 case MONO_TYPE_SZARRAY:
3346 case MONO_TYPE_BOOLEAN:
3349 case MONO_TYPE_CHAR:
3358 case MONO_TYPE_VALUETYPE:
3359 is_ref = type->byref;
3361 case MONO_TYPE_GENERICINST:
3362 is_ref = !mono_type_generic_inst_is_valuetype (type);
3368 g_error ("type 0x%x not handled in "
3369 "mono_field_get_value_object", type->type);
3373 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3376 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3380 vtable = mono_class_vtable_full (domain, field->parent, error);
3381 return_val_if_nok (error, NULL);
3383 if (!vtable->initialized) {
3384 mono_runtime_class_init_full (vtable, error);
3385 return_val_if_nok (error, NULL);
3394 get_default_field_value (domain, field, &o, error);
3395 return_val_if_nok (error, NULL);
3396 } else if (is_static) {
3397 mono_field_static_get_value_checked (vtable, field, &o, error);
3398 return_val_if_nok (error, NULL);
3400 mono_field_get_value (obj, field, &o);
3406 static MonoMethod *m;
3412 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3413 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3419 get_default_field_value (domain, field, v, error);
3420 return_val_if_nok (error, NULL);
3421 } else if (is_static) {
3422 mono_field_static_get_value_checked (vtable, field, v, error);
3423 return_val_if_nok (error, NULL);
3425 mono_field_get_value (obj, field, v);
3428 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3429 args [0] = ptr ? *ptr : NULL;
3430 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3431 return_val_if_nok (error, NULL);
3433 o = mono_runtime_invoke_checked (m, NULL, args, error);
3434 return_val_if_nok (error, NULL);
3439 /* boxed value type */
3440 klass = mono_class_from_mono_type (type);
3442 if (mono_class_is_nullable (klass))
3443 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3445 o = mono_object_new_checked (domain, klass, error);
3446 return_val_if_nok (error, NULL);
3447 v = ((gchar *) o) + sizeof (MonoObject);
3450 get_default_field_value (domain, field, v, error);
3451 return_val_if_nok (error, NULL);
3452 } else if (is_static) {
3453 mono_field_static_get_value_checked (vtable, field, v, error);
3454 return_val_if_nok (error, NULL);
3456 mono_field_get_value (obj, field, v);
3463 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3465 MONO_REQ_GC_UNSAFE_MODE;
3467 mono_error_init (error);
3469 const char *p = blob;
3470 mono_metadata_decode_blob_size (p, &p);
3473 case MONO_TYPE_BOOLEAN:
3476 *(guint8 *) value = *p;
3478 case MONO_TYPE_CHAR:
3481 *(guint16*) value = read16 (p);
3485 *(guint32*) value = read32 (p);
3489 *(guint64*) value = read64 (p);
3492 readr4 (p, (float*) value);
3495 readr8 (p, (double*) value);
3497 case MONO_TYPE_STRING:
3498 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3500 case MONO_TYPE_CLASS:
3501 *(gpointer*) value = NULL;
3505 g_warning ("type 0x%02x should not be in constant table", type);
3511 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3513 MONO_REQ_GC_NEUTRAL_MODE;
3515 MonoTypeEnum def_type;
3518 mono_error_init (error);
3520 data = mono_class_get_field_default_value (field, &def_type);
3521 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3525 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3527 MONO_REQ_GC_UNSAFE_MODE;
3531 mono_error_init (error);
3533 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3535 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3536 get_default_field_value (vt->domain, field, value, error);
3540 if (field->offset == -1) {
3541 /* Special static */
3542 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3543 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3545 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3547 mono_copy_value (field->type, value, src, TRUE);
3551 * mono_field_static_get_value:
3552 * @vt: vtable to the object
3553 * @field: MonoClassField describing the field to fetch information from
3554 * @value: where the value is returned
3556 * Use this routine to get the value of the static field @field value.
3558 * The pointer provided by value must be of the field type, for reference
3559 * types this is a MonoObject*, for value types its the actual pointer to
3564 * mono_field_static_get_value (vt, int_field, &i);
3567 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3569 MONO_REQ_GC_NEUTRAL_MODE;
3572 mono_field_static_get_value_checked (vt, field, value, &error);
3573 mono_error_cleanup (&error);
3577 * mono_field_static_get_value_checked:
3578 * @vt: vtable to the object
3579 * @field: MonoClassField describing the field to fetch information from
3580 * @value: where the value is returned
3581 * @error: set on error
3583 * Use this routine to get the value of the static field @field value.
3585 * The pointer provided by value must be of the field type, for reference
3586 * types this is a MonoObject*, for value types its the actual pointer to
3591 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3592 * if (!is_ok (error)) { ... }
3594 * On failure sets @error.
3597 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3599 MONO_REQ_GC_NEUTRAL_MODE;
3601 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3605 * mono_property_set_value:
3606 * @prop: MonoProperty to set
3607 * @obj: instance object on which to act
3608 * @params: parameters to pass to the propery
3609 * @exc: optional exception
3611 * Invokes the property's set method with the given arguments on the
3612 * object instance obj (or NULL for static properties).
3614 * You can pass NULL as the exc argument if you don't want to
3615 * catch exceptions, otherwise, *exc will be set to the exception
3616 * thrown, if any. if an exception is thrown, you can't use the
3617 * MonoObject* result from the function.
3620 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3622 MONO_REQ_GC_UNSAFE_MODE;
3625 do_runtime_invoke (prop->set, obj, params, exc, &error);
3626 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3627 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3629 mono_error_cleanup (&error);
3634 * mono_property_set_value_checked:
3635 * @prop: MonoProperty to set
3636 * @obj: instance object on which to act
3637 * @params: parameters to pass to the propery
3638 * @error: set on error
3640 * Invokes the property's set method with the given arguments on the
3641 * object instance obj (or NULL for static properties).
3643 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3644 * If an exception is thrown, it will be caught and returned via @error.
3647 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3649 MONO_REQ_GC_UNSAFE_MODE;
3653 mono_error_init (error);
3654 do_runtime_invoke (prop->set, obj, params, &exc, error);
3655 if (exc != NULL && is_ok (error))
3656 mono_error_set_exception_instance (error, (MonoException*)exc);
3657 return is_ok (error);
3661 * mono_property_get_value:
3662 * @prop: MonoProperty to fetch
3663 * @obj: instance object on which to act
3664 * @params: parameters to pass to the propery
3665 * @exc: optional exception
3667 * Invokes the property's get method with the given arguments on the
3668 * object instance obj (or NULL for static properties).
3670 * You can pass NULL as the exc argument if you don't want to
3671 * catch exceptions, otherwise, *exc will be set to the exception
3672 * thrown, if any. if an exception is thrown, you can't use the
3673 * MonoObject* result from the function.
3675 * Returns: the value from invoking the get method on the property.
3678 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3680 MONO_REQ_GC_UNSAFE_MODE;
3683 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3684 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3685 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3687 mono_error_cleanup (&error); /* FIXME don't raise here */
3694 * mono_property_get_value_checked:
3695 * @prop: MonoProperty to fetch
3696 * @obj: instance object on which to act
3697 * @params: parameters to pass to the propery
3698 * @error: set on error
3700 * Invokes the property's get method with the given arguments on the
3701 * object instance obj (or NULL for static properties).
3703 * If an exception is thrown, you can't use the
3704 * MonoObject* result from the function. The exception will be propagated via @error.
3706 * Returns: the value from invoking the get method on the property. On
3707 * failure returns NULL and sets @error.
3710 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3712 MONO_REQ_GC_UNSAFE_MODE;
3715 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3716 if (exc != NULL && !is_ok (error))
3717 mono_error_set_exception_instance (error, (MonoException*) exc);
3725 * mono_nullable_init:
3726 * @buf: The nullable structure to initialize.
3727 * @value: the value to initialize from
3728 * @klass: the type for the object
3730 * Initialize the nullable structure pointed to by @buf from @value which
3731 * should be a boxed value type. The size of @buf should be able to hold
3732 * as much data as the @klass->instance_size (which is the number of bytes
3733 * that will be copies).
3735 * Since Nullables have variable structure, we can not define a C
3736 * structure for them.
3739 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3741 MONO_REQ_GC_UNSAFE_MODE;
3743 MonoClass *param_class = klass->cast_class;
3745 mono_class_setup_fields (klass);
3746 g_assert (klass->fields_inited);
3748 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3749 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3751 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3753 if (param_class->has_references)
3754 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3756 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3758 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3763 * mono_nullable_box:
3764 * @buf: The buffer representing the data to be boxed
3765 * @klass: the type to box it as.
3766 * @error: set on oerr
3768 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3769 * @buf. On failure returns NULL and sets @error
3772 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3774 MONO_REQ_GC_UNSAFE_MODE;
3776 mono_error_init (error);
3777 MonoClass *param_class = klass->cast_class;
3779 mono_class_setup_fields (klass);
3780 g_assert (klass->fields_inited);
3782 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3783 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3785 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3786 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3787 return_val_if_nok (error, NULL);
3788 if (param_class->has_references)
3789 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3791 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3799 * mono_get_delegate_invoke:
3800 * @klass: The delegate class
3802 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3805 mono_get_delegate_invoke (MonoClass *klass)
3807 MONO_REQ_GC_NEUTRAL_MODE;
3811 /* This is called at runtime, so avoid the slower search in metadata */
3812 mono_class_setup_methods (klass);
3813 if (mono_class_has_failure (klass))
3815 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3820 * mono_get_delegate_begin_invoke:
3821 * @klass: The delegate class
3823 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3826 mono_get_delegate_begin_invoke (MonoClass *klass)
3828 MONO_REQ_GC_NEUTRAL_MODE;
3832 /* This is called at runtime, so avoid the slower search in metadata */
3833 mono_class_setup_methods (klass);
3834 if (mono_class_has_failure (klass))
3836 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3841 * mono_get_delegate_end_invoke:
3842 * @klass: The delegate class
3844 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3847 mono_get_delegate_end_invoke (MonoClass *klass)
3849 MONO_REQ_GC_NEUTRAL_MODE;
3853 /* This is called at runtime, so avoid the slower search in metadata */
3854 mono_class_setup_methods (klass);
3855 if (mono_class_has_failure (klass))
3857 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3862 * mono_runtime_delegate_invoke:
3863 * @delegate: pointer to a delegate object.
3864 * @params: parameters for the delegate.
3865 * @exc: Pointer to the exception result.
3867 * Invokes the delegate method @delegate with the parameters provided.
3869 * You can pass NULL as the exc argument if you don't want to
3870 * catch exceptions, otherwise, *exc will be set to the exception
3871 * thrown, if any. if an exception is thrown, you can't use the
3872 * MonoObject* result from the function.
3875 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3877 MONO_REQ_GC_UNSAFE_MODE;
3881 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3883 mono_error_cleanup (&error);
3886 if (!is_ok (&error))
3887 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3891 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3892 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3898 * mono_runtime_delegate_try_invoke:
3899 * @delegate: pointer to a delegate object.
3900 * @params: parameters for the delegate.
3901 * @exc: Pointer to the exception result.
3902 * @error: set on error
3904 * Invokes the delegate method @delegate with the parameters provided.
3906 * You can pass NULL as the exc argument if you don't want to
3907 * catch exceptions, otherwise, *exc will be set to the exception
3908 * thrown, if any. On failure to execute, @error will be set.
3909 * if an exception is thrown, you can't use the
3910 * MonoObject* result from the function.
3913 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3915 MONO_REQ_GC_UNSAFE_MODE;
3917 mono_error_init (error);
3919 MonoClass *klass = delegate->vtable->klass;
3922 im = mono_get_delegate_invoke (klass);
3924 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3927 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3929 o = mono_runtime_invoke_checked (im, delegate, params, error);
3936 * mono_runtime_delegate_invoke_checked:
3937 * @delegate: pointer to a delegate object.
3938 * @params: parameters for the delegate.
3939 * @error: set on error
3941 * Invokes the delegate method @delegate with the parameters provided.
3943 * On failure @error will be set and you can't use the MonoObject*
3944 * result from the function.
3947 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3949 mono_error_init (error);
3950 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3953 static char **main_args = NULL;
3954 static int num_main_args = 0;
3957 * mono_runtime_get_main_args:
3959 * Returns: a MonoArray with the arguments passed to the main program
3962 mono_runtime_get_main_args (void)
3964 MONO_REQ_GC_UNSAFE_MODE;
3966 MonoArray *result = mono_runtime_get_main_args_checked (&error);
3967 mono_error_assert_ok (&error);
3972 * mono_runtime_get_main_args:
3973 * @error: set on error
3975 * Returns: a MonoArray with the arguments passed to the main
3976 * program. On failure returns NULL and sets @error.
3979 mono_runtime_get_main_args_checked (MonoError *error)
3983 MonoDomain *domain = mono_domain_get ();
3985 mono_error_init (error);
3987 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
3988 return_val_if_nok (error, NULL);
3990 for (i = 0; i < num_main_args; ++i)
3991 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3997 free_main_args (void)
3999 MONO_REQ_GC_NEUTRAL_MODE;
4003 for (i = 0; i < num_main_args; ++i)
4004 g_free (main_args [i]);
4011 * mono_runtime_set_main_args:
4012 * @argc: number of arguments from the command line
4013 * @argv: array of strings from the command line
4015 * Set the command line arguments from an embedding application that doesn't otherwise call
4016 * mono_runtime_run_main ().
4019 mono_runtime_set_main_args (int argc, char* argv[])
4021 MONO_REQ_GC_NEUTRAL_MODE;
4026 main_args = g_new0 (char*, argc);
4027 num_main_args = argc;
4029 for (i = 0; i < argc; ++i) {
4032 utf8_arg = mono_utf8_from_external (argv[i]);
4033 if (utf8_arg == NULL) {
4034 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4035 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4039 main_args [i] = utf8_arg;
4046 * Prepare an array of arguments in order to execute a standard Main()
4047 * method (argc/argv contains the executable name). This method also
4048 * sets the command line argument value needed by System.Environment.
4052 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4054 MONO_REQ_GC_UNSAFE_MODE;
4058 MonoArray *args = NULL;
4059 MonoDomain *domain = mono_domain_get ();
4060 gchar *utf8_fullpath;
4061 MonoMethodSignature *sig;
4063 g_assert (method != NULL);
4065 mono_thread_set_main (mono_thread_current ());
4067 main_args = g_new0 (char*, argc);
4068 num_main_args = argc;
4070 if (!g_path_is_absolute (argv [0])) {
4071 gchar *basename = g_path_get_basename (argv [0]);
4072 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4076 utf8_fullpath = mono_utf8_from_external (fullpath);
4077 if(utf8_fullpath == NULL) {
4078 /* Printing the arg text will cause glib to
4079 * whinge about "Invalid UTF-8", but at least
4080 * its relevant, and shows the problem text
4083 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4084 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4091 utf8_fullpath = mono_utf8_from_external (argv[0]);
4092 if(utf8_fullpath == NULL) {
4093 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4094 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4099 main_args [0] = utf8_fullpath;
4101 for (i = 1; i < argc; ++i) {
4104 utf8_arg=mono_utf8_from_external (argv[i]);
4105 if(utf8_arg==NULL) {
4106 /* Ditto the comment about Invalid UTF-8 here */
4107 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4108 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4112 main_args [i] = utf8_arg;
4117 sig = mono_method_signature (method);
4119 g_print ("Unable to load Main method.\n");
4123 if (sig->param_count) {
4124 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4125 mono_error_assert_ok (&error);
4126 for (i = 0; i < argc; ++i) {
4127 /* The encodings should all work, given that
4128 * we've checked all these args for the
4131 gchar *str = mono_utf8_from_external (argv [i]);
4132 MonoString *arg = mono_string_new (domain, str);
4133 mono_array_setref (args, i, arg);
4137 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4138 mono_error_assert_ok (&error);
4141 mono_assembly_set_main (method->klass->image->assembly);
4147 * mono_runtime_run_main:
4148 * @method: the method to start the application with (usually Main)
4149 * @argc: number of arguments from the command line
4150 * @argv: array of strings from the command line
4151 * @exc: excetption results
4153 * Execute a standard Main() method (argc/argv contains the
4154 * executable name). This method also sets the command line argument value
4155 * needed by System.Environment.
4160 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4163 MONO_REQ_GC_UNSAFE_MODE;
4166 MonoArray *args = prepare_run_main (method, argc, argv);
4169 res = mono_runtime_try_exec_main (method, args, exc);
4171 res = mono_runtime_exec_main_checked (method, args, &error);
4172 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4178 * mono_runtime_run_main_checked:
4179 * @method: the method to start the application with (usually Main)
4180 * @argc: number of arguments from the command line
4181 * @argv: array of strings from the command line
4182 * @error: set on error
4184 * Execute a standard Main() method (argc/argv contains the
4185 * executable name). This method also sets the command line argument value
4186 * needed by System.Environment. On failure sets @error.
4191 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4194 mono_error_init (error);
4195 MonoArray *args = prepare_run_main (method, argc, argv);
4196 return mono_runtime_exec_main_checked (method, args, error);
4200 * mono_runtime_try_run_main:
4201 * @method: the method to start the application with (usually Main)
4202 * @argc: number of arguments from the command line
4203 * @argv: array of strings from the command line
4204 * @exc: set if Main throws an exception
4205 * @error: set if Main can't be executed
4207 * Execute a standard Main() method (argc/argv contains the executable
4208 * name). This method also sets the command line argument value needed
4209 * by System.Environment. On failure sets @error if Main can't be
4210 * executed or @exc if it threw and exception.
4215 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4219 MonoArray *args = prepare_run_main (method, argc, argv);
4220 return mono_runtime_try_exec_main (method, args, exc);
4225 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4227 static MonoMethod *serialize_method;
4233 if (!serialize_method) {
4234 MonoClass *klass = mono_class_get_remoting_services_class ();
4235 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4238 if (!serialize_method) {
4243 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4248 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4249 if (*exc == NULL && !mono_error_ok (&error))
4250 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4252 mono_error_cleanup (&error);
4261 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4263 MONO_REQ_GC_UNSAFE_MODE;
4265 static MonoMethod *deserialize_method;
4271 if (!deserialize_method) {
4272 MonoClass *klass = mono_class_get_remoting_services_class ();
4273 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4275 if (!deserialize_method) {
4283 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4284 if (*exc == NULL && !mono_error_ok (&error))
4285 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4287 mono_error_cleanup (&error);
4295 #ifndef DISABLE_REMOTING
4297 make_transparent_proxy (MonoObject *obj, MonoError *error)
4299 MONO_REQ_GC_UNSAFE_MODE;
4301 static MonoMethod *get_proxy_method;
4303 MonoDomain *domain = mono_domain_get ();
4304 MonoRealProxy *real_proxy;
4305 MonoReflectionType *reflection_type;
4306 MonoTransparentProxy *transparent_proxy;
4308 mono_error_init (error);
4310 if (!get_proxy_method)
4311 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4313 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4315 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4316 return_val_if_nok (error, NULL);
4317 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4318 return_val_if_nok (error, NULL);
4320 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4321 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4323 MonoObject *exc = NULL;
4325 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4326 if (exc != NULL && is_ok (error))
4327 mono_error_set_exception_instance (error, (MonoException*)exc);
4329 return (MonoObject*) transparent_proxy;
4331 #endif /* DISABLE_REMOTING */
4334 * mono_object_xdomain_representation
4336 * @target_domain: a domain
4337 * @error: set on error.
4339 * Creates a representation of obj in the domain target_domain. This
4340 * is either a copy of obj arrived through via serialization and
4341 * deserialization or a proxy, depending on whether the object is
4342 * serializable or marshal by ref. obj must not be in target_domain.
4344 * If the object cannot be represented in target_domain, NULL is
4345 * returned and @error is set appropriately.
4348 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4350 MONO_REQ_GC_UNSAFE_MODE;
4352 mono_error_init (error);
4353 MonoObject *deserialized = NULL;
4355 #ifndef DISABLE_REMOTING
4356 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4357 deserialized = make_transparent_proxy (obj, error);
4362 gboolean failure = FALSE;
4363 MonoDomain *domain = mono_domain_get ();
4364 MonoObject *serialized;
4365 MonoObject *exc = NULL;
4367 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4368 serialized = serialize_object (obj, &failure, &exc);
4369 mono_domain_set_internal_with_options (target_domain, FALSE);
4371 deserialized = deserialize_object (serialized, &failure, &exc);
4372 if (domain != target_domain)
4373 mono_domain_set_internal_with_options (domain, FALSE);
4375 mono_error_set_exception_instance (error, (MonoException*)exc);
4378 return deserialized;
4381 /* Used in call_unhandled_exception_delegate */
4383 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4385 MONO_REQ_GC_UNSAFE_MODE;
4387 mono_error_init (error);
4390 MonoMethod *method = NULL;
4391 MonoBoolean is_terminating = TRUE;
4394 klass = mono_class_get_unhandled_exception_event_args_class ();
4395 mono_class_init (klass);
4397 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4398 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4402 args [1] = &is_terminating;
4404 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4405 return_val_if_nok (error, NULL);
4407 mono_runtime_invoke_checked (method, obj, args, error);
4408 return_val_if_nok (error, NULL);
4413 /* Used in mono_unhandled_exception */
4415 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4416 MONO_REQ_GC_UNSAFE_MODE;
4419 MonoObject *e = NULL;
4421 MonoDomain *current_domain = mono_domain_get ();
4423 if (domain != current_domain)
4424 mono_domain_set_internal_with_options (domain, FALSE);
4426 g_assert (domain == mono_object_domain (domain->domain));
4428 if (mono_object_domain (exc) != domain) {
4430 exc = mono_object_xdomain_representation (exc, domain, &error);
4432 if (!is_ok (&error)) {
4433 MonoError inner_error;
4434 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4435 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4436 mono_error_assert_ok (&inner_error);
4438 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4439 "System.Runtime.Serialization", "SerializationException",
4440 "Could not serialize unhandled exception.");
4444 g_assert (mono_object_domain (exc) == domain);
4446 pa [0] = domain->domain;
4447 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4448 mono_error_assert_ok (&error);
4449 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4450 if (!is_ok (&error)) {
4452 e = (MonoObject*)mono_error_convert_to_exception (&error);
4454 mono_error_cleanup (&error);
4457 if (domain != current_domain)
4458 mono_domain_set_internal_with_options (current_domain, FALSE);
4461 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4462 if (!mono_error_ok (&error)) {
4463 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4464 mono_error_cleanup (&error);
4466 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4472 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4475 * mono_runtime_unhandled_exception_policy_set:
4476 * @policy: the new policy
4478 * This is a VM internal routine.
4480 * Sets the runtime policy for handling unhandled exceptions.
4483 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4484 runtime_unhandled_exception_policy = policy;
4488 * mono_runtime_unhandled_exception_policy_get:
4490 * This is a VM internal routine.
4492 * Gets the runtime policy for handling unhandled exceptions.
4494 MonoRuntimeUnhandledExceptionPolicy
4495 mono_runtime_unhandled_exception_policy_get (void) {
4496 return runtime_unhandled_exception_policy;
4500 * mono_unhandled_exception:
4501 * @exc: exception thrown
4503 * This is a VM internal routine.
4505 * We call this function when we detect an unhandled exception
4506 * in the default domain.
4508 * It invokes the * UnhandledException event in AppDomain or prints
4509 * a warning to the console
4512 mono_unhandled_exception (MonoObject *exc)
4514 MONO_REQ_GC_UNSAFE_MODE;
4517 MonoClassField *field;
4518 MonoDomain *current_domain, *root_domain;
4519 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4521 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4524 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4527 current_domain = mono_domain_get ();
4528 root_domain = mono_get_root_domain ();
4530 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4531 mono_error_assert_ok (&error);
4532 if (current_domain != root_domain) {
4533 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4534 mono_error_assert_ok (&error);
4537 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4538 mono_print_unhandled_exception (exc);
4540 /* unhandled exception callbacks must not be aborted */
4541 mono_threads_begin_abort_protected_block ();
4542 if (root_appdomain_delegate)
4543 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4544 if (current_appdomain_delegate)
4545 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4546 mono_threads_end_abort_protected_block ();
4549 /* set exitcode only if we will abort the process */
4550 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4551 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4553 mono_environment_exitcode_set (1);
4558 * mono_runtime_exec_managed_code:
4559 * @domain: Application domain
4560 * @main_func: function to invoke from the execution thread
4561 * @main_args: parameter to the main_func
4563 * Launch a new thread to execute a function
4565 * main_func is called back from the thread with main_args as the
4566 * parameter. The callback function is expected to start Main()
4567 * eventually. This function then waits for all managed threads to
4569 * It is not necesseray anymore to execute managed code in a subthread,
4570 * so this function should not be used anymore by default: just
4571 * execute the code and then call mono_thread_manage ().
4574 mono_runtime_exec_managed_code (MonoDomain *domain,
4575 MonoMainThreadFunc main_func,
4579 mono_thread_create_checked (domain, main_func, main_args, &error);
4580 mono_error_assert_ok (&error);
4582 mono_thread_manage ();
4586 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4588 MonoInternalThread* thread = mono_thread_internal_current ();
4589 MonoCustomAttrInfo* cinfo;
4590 gboolean has_stathread_attribute;
4592 if (!domain->entry_assembly) {
4594 MonoAssembly *assembly;
4596 assembly = method->klass->image->assembly;
4597 domain->entry_assembly = assembly;
4598 /* Domains created from another domain already have application_base and configuration_file set */
4599 if (domain->setup->application_base == NULL) {
4600 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4603 if (domain->setup->configuration_file == NULL) {
4604 str = g_strconcat (assembly->image->name, ".config", NULL);
4605 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4607 mono_domain_set_options_from_config (domain);
4611 MonoError cattr_error;
4612 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4613 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4615 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4617 mono_custom_attrs_free (cinfo);
4619 has_stathread_attribute = FALSE;
4621 if (has_stathread_attribute) {
4622 thread->apartment_state = ThreadApartmentState_STA;
4624 thread->apartment_state = ThreadApartmentState_MTA;
4626 mono_thread_init_apartment_state ();
4631 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4633 MONO_REQ_GC_UNSAFE_MODE;
4638 mono_error_init (error);
4643 /* FIXME: check signature of method */
4644 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4646 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4648 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4651 mono_environment_exitcode_set (rval);
4653 mono_runtime_invoke_checked (method, NULL, pa, error);
4665 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4667 MONO_REQ_GC_UNSAFE_MODE;
4677 /* FIXME: check signature of method */
4678 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4679 MonoError inner_error;
4681 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4682 if (*exc == NULL && !mono_error_ok (&inner_error))
4683 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4685 mono_error_cleanup (&inner_error);
4688 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4692 mono_environment_exitcode_set (rval);
4694 MonoError inner_error;
4695 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4696 if (*exc == NULL && !mono_error_ok (&inner_error))
4697 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4699 mono_error_cleanup (&inner_error);
4704 /* If the return type of Main is void, only
4705 * set the exitcode if an exception was thrown
4706 * (we don't want to blow away an
4707 * explicitly-set exit code)
4710 mono_environment_exitcode_set (rval);
4718 * Execute a standard Main() method (args doesn't contain the
4722 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4725 prepare_thread_to_exec_main (mono_object_domain (args), method);
4727 int rval = do_try_exec_main (method, args, exc);
4730 int rval = do_exec_main_checked (method, args, &error);
4731 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4737 * Execute a standard Main() method (args doesn't contain the
4740 * On failure sets @error
4743 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4745 mono_error_init (error);
4746 prepare_thread_to_exec_main (mono_object_domain (args), method);
4747 return do_exec_main_checked (method, args, error);
4751 * Execute a standard Main() method (args doesn't contain the
4754 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4757 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4759 prepare_thread_to_exec_main (mono_object_domain (args), method);
4760 return do_try_exec_main (method, args, exc);
4765 /** invoke_array_extract_argument:
4766 * @params: array of arguments to the method.
4767 * @i: the index of the argument to extract.
4768 * @t: ith type from the method signature.
4769 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4770 * @error: set on error.
4772 * Given an array of method arguments, return the ith one using the corresponding type
4773 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4775 * On failure sets @error and returns NULL.
4778 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4780 MonoType *t_orig = t;
4781 gpointer result = NULL;
4782 mono_error_init (error);
4787 case MONO_TYPE_BOOLEAN:
4790 case MONO_TYPE_CHAR:
4799 case MONO_TYPE_VALUETYPE:
4800 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4801 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4802 result = mono_array_get (params, MonoObject*, i);
4804 *has_byref_nullables = TRUE;
4806 /* MS seems to create the objects if a null is passed in */
4807 if (!mono_array_get (params, MonoObject*, i)) {
4808 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4809 return_val_if_nok (error, NULL);
4810 mono_array_setref (params, i, o);
4815 * We can't pass the unboxed vtype byref to the callee, since
4816 * that would mean the callee would be able to modify boxed
4817 * primitive types. So we (and MS) make a copy of the boxed
4818 * object, pass that to the callee, and replace the original
4819 * boxed object in the arg array with the copy.
4821 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4822 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4823 return_val_if_nok (error, NULL);
4824 mono_array_setref (params, i, copy);
4827 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4830 case MONO_TYPE_STRING:
4831 case MONO_TYPE_OBJECT:
4832 case MONO_TYPE_CLASS:
4833 case MONO_TYPE_ARRAY:
4834 case MONO_TYPE_SZARRAY:
4836 result = mono_array_addr (params, MonoObject*, i);
4837 // FIXME: I need to check this code path
4839 result = mono_array_get (params, MonoObject*, i);
4841 case MONO_TYPE_GENERICINST:
4843 t = &t->data.generic_class->container_class->this_arg;
4845 t = &t->data.generic_class->container_class->byval_arg;
4847 case MONO_TYPE_PTR: {
4850 /* The argument should be an IntPtr */
4851 arg = mono_array_get (params, MonoObject*, i);
4855 g_assert (arg->vtable->klass == mono_defaults.int_class);
4856 result = ((MonoIntPtr*)arg)->m_value;
4861 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4866 * mono_runtime_invoke_array:
4867 * @method: method to invoke
4868 * @obJ: object instance
4869 * @params: arguments to the method
4870 * @exc: exception information.
4872 * Invokes the method represented by @method on the object @obj.
4874 * obj is the 'this' pointer, it should be NULL for static
4875 * methods, a MonoObject* for object instances and a pointer to
4876 * the value type for value types.
4878 * The params array contains the arguments to the method with the
4879 * same convention: MonoObject* pointers for object instances and
4880 * pointers to the value type otherwise. The _invoke_array
4881 * variant takes a C# object[] as the params argument (MonoArray
4882 * *params): in this case the value types are boxed inside the
4883 * respective reference representation.
4885 * From unmanaged code you'll usually use the
4886 * mono_runtime_invoke_checked() variant.
4888 * Note that this function doesn't handle virtual methods for
4889 * you, it will exec the exact method you pass: we still need to
4890 * expose a function to lookup the derived class implementation
4891 * of a virtual method (there are examples of this in the code,
4894 * You can pass NULL as the exc argument if you don't want to
4895 * catch exceptions, otherwise, *exc will be set to the exception
4896 * thrown, if any. if an exception is thrown, you can't use the
4897 * MonoObject* result from the function.
4899 * If the method returns a value type, it is boxed in an object
4903 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4908 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4910 mono_error_cleanup (&error);
4913 if (!is_ok (&error))
4914 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4918 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4919 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4925 * mono_runtime_invoke_array_checked:
4926 * @method: method to invoke
4927 * @obJ: object instance
4928 * @params: arguments to the method
4929 * @error: set on failure.
4931 * Invokes the method represented by @method on the object @obj.
4933 * obj is the 'this' pointer, it should be NULL for static
4934 * methods, a MonoObject* for object instances and a pointer to
4935 * the value type for value types.
4937 * The params array contains the arguments to the method with the
4938 * same convention: MonoObject* pointers for object instances and
4939 * pointers to the value type otherwise. The _invoke_array
4940 * variant takes a C# object[] as the params argument (MonoArray
4941 * *params): in this case the value types are boxed inside the
4942 * respective reference representation.
4944 * From unmanaged code you'll usually use the
4945 * mono_runtime_invoke_checked() variant.
4947 * Note that this function doesn't handle virtual methods for
4948 * you, it will exec the exact method you pass: we still need to
4949 * expose a function to lookup the derived class implementation
4950 * of a virtual method (there are examples of this in the code,
4953 * On failure or exception, @error will be set. In that case, you
4954 * can't use the MonoObject* result from the function.
4956 * If the method returns a value type, it is boxed in an object
4960 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4963 mono_error_init (error);
4964 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4968 * mono_runtime_try_invoke_array:
4969 * @method: method to invoke
4970 * @obJ: object instance
4971 * @params: arguments to the method
4972 * @exc: exception information.
4973 * @error: set on failure.
4975 * Invokes the method represented by @method on the object @obj.
4977 * obj is the 'this' pointer, it should be NULL for static
4978 * methods, a MonoObject* for object instances and a pointer to
4979 * the value type for value types.
4981 * The params array contains the arguments to the method with the
4982 * same convention: MonoObject* pointers for object instances and
4983 * pointers to the value type otherwise. The _invoke_array
4984 * variant takes a C# object[] as the params argument (MonoArray
4985 * *params): in this case the value types are boxed inside the
4986 * respective reference representation.
4988 * From unmanaged code you'll usually use the
4989 * mono_runtime_invoke_checked() variant.
4991 * Note that this function doesn't handle virtual methods for
4992 * you, it will exec the exact method you pass: we still need to
4993 * expose a function to lookup the derived class implementation
4994 * of a virtual method (there are examples of this in the code,
4997 * You can pass NULL as the exc argument if you don't want to catch
4998 * exceptions, otherwise, *exc will be set to the exception thrown, if
4999 * any. On other failures, @error will be set. If an exception is
5000 * thrown or there's an error, you can't use the MonoObject* result
5001 * from the function.
5003 * If the method returns a value type, it is boxed in an object
5007 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5008 MonoObject **exc, MonoError *error)
5010 MONO_REQ_GC_UNSAFE_MODE;
5012 mono_error_init (error);
5014 MonoMethodSignature *sig = mono_method_signature (method);
5015 gpointer *pa = NULL;
5018 gboolean has_byref_nullables = FALSE;
5020 if (NULL != params) {
5021 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5022 for (i = 0; i < mono_array_length (params); i++) {
5023 MonoType *t = sig->params [i];
5024 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5025 return_val_if_nok (error, NULL);
5029 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5032 if (mono_class_is_nullable (method->klass)) {
5033 /* Need to create a boxed vtype instead */
5039 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5044 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5045 mono_error_assert_ok (error);
5046 g_assert (obj); /*maybe we should raise a TLE instead?*/
5047 #ifndef DISABLE_REMOTING
5048 if (mono_object_is_transparent_proxy (obj)) {
5049 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5052 if (method->klass->valuetype)
5053 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5056 } else if (method->klass->valuetype) {
5057 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5058 return_val_if_nok (error, NULL);
5062 mono_runtime_try_invoke (method, o, pa, exc, error);
5064 mono_runtime_invoke_checked (method, o, pa, error);
5067 return (MonoObject *)obj;
5069 if (mono_class_is_nullable (method->klass)) {
5070 MonoObject *nullable;
5072 /* Convert the unboxed vtype into a Nullable structure */
5073 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5074 return_val_if_nok (error, NULL);
5076 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5077 return_val_if_nok (error, NULL);
5078 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5079 obj = mono_object_unbox (nullable);
5082 /* obj must be already unboxed if needed */
5084 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5086 res = mono_runtime_invoke_checked (method, obj, pa, error);
5088 return_val_if_nok (error, NULL);
5090 if (sig->ret->type == MONO_TYPE_PTR) {
5091 MonoClass *pointer_class;
5092 static MonoMethod *box_method;
5094 MonoObject *box_exc;
5097 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5098 * convert it to a Pointer object.
5100 pointer_class = mono_class_get_pointer_class ();
5102 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5104 g_assert (res->vtable->klass == mono_defaults.int_class);
5105 box_args [0] = ((MonoIntPtr*)res)->m_value;
5106 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5107 return_val_if_nok (error, NULL);
5109 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5110 g_assert (box_exc == NULL);
5111 mono_error_assert_ok (error);
5114 if (has_byref_nullables) {
5116 * The runtime invoke wrapper already converted byref nullables back,
5117 * and stored them in pa, we just need to copy them back to the
5120 for (i = 0; i < mono_array_length (params); i++) {
5121 MonoType *t = sig->params [i];
5123 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5124 mono_array_setref (params, i, pa [i]);
5134 * @klass: the class of the object that we want to create
5136 * Returns: a newly created object whose definition is
5137 * looked up using @klass. This will not invoke any constructors,
5138 * so the consumer of this routine has to invoke any constructors on
5139 * its own to initialize the object.
5141 * It returns NULL on failure.
5144 mono_object_new (MonoDomain *domain, MonoClass *klass)
5146 MONO_REQ_GC_UNSAFE_MODE;
5150 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5152 mono_error_cleanup (&error);
5157 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5159 MONO_REQ_GC_UNSAFE_MODE;
5163 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5165 mono_error_set_pending_exception (&error);
5170 * mono_object_new_checked:
5171 * @klass: the class of the object that we want to create
5172 * @error: set on error
5174 * Returns: a newly created object whose definition is
5175 * looked up using @klass. This will not invoke any constructors,
5176 * so the consumer of this routine has to invoke any constructors on
5177 * its own to initialize the object.
5179 * It returns NULL on failure and sets @error.
5182 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5184 MONO_REQ_GC_UNSAFE_MODE;
5188 vtable = mono_class_vtable (domain, klass);
5189 g_assert (vtable); /* FIXME don't swallow the error */
5191 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5196 * mono_object_new_pinned:
5198 * Same as mono_object_new, but the returned object will be pinned.
5199 * For SGEN, these objects will only be freed at appdomain unload.
5202 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5204 MONO_REQ_GC_UNSAFE_MODE;
5208 mono_error_init (error);
5210 vtable = mono_class_vtable (domain, klass);
5211 g_assert (vtable); /* FIXME don't swallow the error */
5213 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5215 if (G_UNLIKELY (!o))
5216 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5217 else if (G_UNLIKELY (vtable->klass->has_finalize))
5218 mono_object_register_finalizer (o);
5224 * mono_object_new_specific:
5225 * @vtable: the vtable of the object that we want to create
5227 * Returns: A newly created object with class and domain specified
5231 mono_object_new_specific (MonoVTable *vtable)
5234 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5235 mono_error_cleanup (&error);
5241 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5243 MONO_REQ_GC_UNSAFE_MODE;
5247 mono_error_init (error);
5249 /* check for is_com_object for COM Interop */
5250 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5253 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5256 MonoClass *klass = mono_class_get_activation_services_class ();
5259 mono_class_init (klass);
5261 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5263 mono_error_set_not_supported (error, "Linked away.");
5266 vtable->domain->create_proxy_for_type_method = im;
5269 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5270 if (!mono_error_ok (error))
5273 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5274 if (!mono_error_ok (error))
5281 return mono_object_new_alloc_specific_checked (vtable, error);
5285 ves_icall_object_new_specific (MonoVTable *vtable)
5288 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5289 mono_error_set_pending_exception (&error);
5295 * mono_object_new_alloc_specific:
5296 * @vtable: virtual table for the object.
5298 * This function allocates a new `MonoObject` with the type derived
5299 * from the @vtable information. If the class of this object has a
5300 * finalizer, then the object will be tracked for finalization.
5302 * This method might raise an exception on errors. Use the
5303 * `mono_object_new_fast_checked` method if you want to manually raise
5306 * Returns: the allocated object.
5309 mono_object_new_alloc_specific (MonoVTable *vtable)
5312 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5313 mono_error_cleanup (&error);
5319 * mono_object_new_alloc_specific_checked:
5320 * @vtable: virtual table for the object.
5321 * @error: holds the error return value.
5323 * This function allocates a new `MonoObject` with the type derived
5324 * from the @vtable information. If the class of this object has a
5325 * finalizer, then the object will be tracked for finalization.
5327 * If there is not enough memory, the @error parameter will be set
5328 * and will contain a user-visible message with the amount of bytes
5329 * that were requested.
5331 * Returns: the allocated object, or NULL if there is not enough memory
5335 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5337 MONO_REQ_GC_UNSAFE_MODE;
5341 mono_error_init (error);
5343 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5345 if (G_UNLIKELY (!o))
5346 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5347 else if (G_UNLIKELY (vtable->klass->has_finalize))
5348 mono_object_register_finalizer (o);
5354 * mono_object_new_fast:
5355 * @vtable: virtual table for the object.
5357 * This function allocates a new `MonoObject` with the type derived
5358 * from the @vtable information. The returned object is not tracked
5359 * for finalization. If your object implements a finalizer, you should
5360 * use `mono_object_new_alloc_specific` instead.
5362 * This method might raise an exception on errors. Use the
5363 * `mono_object_new_fast_checked` method if you want to manually raise
5366 * Returns: the allocated object.
5369 mono_object_new_fast (MonoVTable *vtable)
5372 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5373 mono_error_cleanup (&error);
5379 * mono_object_new_fast_checked:
5380 * @vtable: virtual table for the object.
5381 * @error: holds the error return value.
5383 * This function allocates a new `MonoObject` with the type derived
5384 * from the @vtable information. The returned object is not tracked
5385 * for finalization. If your object implements a finalizer, you should
5386 * use `mono_object_new_alloc_specific_checked` instead.
5388 * If there is not enough memory, the @error parameter will be set
5389 * and will contain a user-visible message with the amount of bytes
5390 * that were requested.
5392 * Returns: the allocated object, or NULL if there is not enough memory
5396 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5398 MONO_REQ_GC_UNSAFE_MODE;
5402 mono_error_init (error);
5404 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5406 if (G_UNLIKELY (!o))
5407 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5413 ves_icall_object_new_fast (MonoVTable *vtable)
5416 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5417 mono_error_set_pending_exception (&error);
5423 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5425 MONO_REQ_GC_UNSAFE_MODE;
5429 mono_error_init (error);
5431 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5433 if (G_UNLIKELY (!o))
5434 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5435 else if (G_UNLIKELY (vtable->klass->has_finalize))
5436 mono_object_register_finalizer (o);
5442 * mono_class_get_allocation_ftn:
5444 * @for_box: the object will be used for boxing
5445 * @pass_size_in_words:
5447 * Return the allocation function appropriate for the given class.
5451 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5453 MONO_REQ_GC_NEUTRAL_MODE;
5455 *pass_size_in_words = FALSE;
5457 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5458 return ves_icall_object_new_specific;
5460 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5462 return ves_icall_object_new_fast;
5465 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5466 * of the overhead of parameter passing.
5469 *pass_size_in_words = TRUE;
5470 #ifdef GC_REDIRECT_TO_LOCAL
5471 return GC_local_gcj_fast_malloc;
5473 return GC_gcj_fast_malloc;
5478 return ves_icall_object_new_specific;
5482 * mono_object_new_from_token:
5483 * @image: Context where the type_token is hosted
5484 * @token: a token of the type that we want to create
5486 * Returns: A newly created object whose definition is
5487 * looked up using @token in the @image image
5490 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5492 MONO_REQ_GC_UNSAFE_MODE;
5498 klass = mono_class_get_checked (image, token, &error);
5499 mono_error_assert_ok (&error);
5501 result = mono_object_new_checked (domain, klass, &error);
5503 mono_error_cleanup (&error);
5510 * mono_object_clone:
5511 * @obj: the object to clone
5513 * Returns: A newly created object who is a shallow copy of @obj
5516 mono_object_clone (MonoObject *obj)
5519 MonoObject *o = mono_object_clone_checked (obj, &error);
5520 mono_error_cleanup (&error);
5526 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5528 MONO_REQ_GC_UNSAFE_MODE;
5533 mono_error_init (error);
5535 size = obj->vtable->klass->instance_size;
5537 if (obj->vtable->klass->rank)
5538 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5540 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5542 if (G_UNLIKELY (!o)) {
5543 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5547 /* If the object doesn't contain references this will do a simple memmove. */
5548 mono_gc_wbarrier_object_copy (o, obj);
5550 if (obj->vtable->klass->has_finalize)
5551 mono_object_register_finalizer (o);
5556 * mono_array_full_copy:
5557 * @src: source array to copy
5558 * @dest: destination array
5560 * Copies the content of one array to another with exactly the same type and size.
5563 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5565 MONO_REQ_GC_UNSAFE_MODE;
5568 MonoClass *klass = src->obj.vtable->klass;
5570 g_assert (klass == dest->obj.vtable->klass);
5572 size = mono_array_length (src);
5573 g_assert (size == mono_array_length (dest));
5574 size *= mono_array_element_size (klass);
5576 if (klass->element_class->valuetype) {
5577 if (klass->element_class->has_references)
5578 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5580 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5582 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5585 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5590 * mono_array_clone_in_domain:
5591 * @domain: the domain in which the array will be cloned into
5592 * @array: the array to clone
5593 * @error: set on error
5595 * This routine returns a copy of the array that is hosted on the
5596 * specified MonoDomain. On failure returns NULL and sets @error.
5599 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5601 MONO_REQ_GC_UNSAFE_MODE;
5606 MonoClass *klass = array->obj.vtable->klass;
5608 mono_error_init (error);
5610 if (array->bounds == NULL) {
5611 size = mono_array_length (array);
5612 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5613 return_val_if_nok (error, NULL);
5615 size *= mono_array_element_size (klass);
5617 if (klass->element_class->valuetype) {
5618 if (klass->element_class->has_references)
5619 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5621 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5623 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5626 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5631 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5632 size = mono_array_element_size (klass);
5633 for (i = 0; i < klass->rank; ++i) {
5634 sizes [i] = array->bounds [i].length;
5635 size *= array->bounds [i].length;
5636 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5638 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5639 return_val_if_nok (error, NULL);
5641 if (klass->element_class->valuetype) {
5642 if (klass->element_class->has_references)
5643 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5645 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5647 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5650 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5658 * @array: the array to clone
5660 * Returns: A newly created array who is a shallow copy of @array
5663 mono_array_clone (MonoArray *array)
5665 MONO_REQ_GC_UNSAFE_MODE;
5668 MonoArray *result = mono_array_clone_checked (array, &error);
5669 mono_error_cleanup (&error);
5674 * mono_array_clone_checked:
5675 * @array: the array to clone
5676 * @error: set on error
5678 * Returns: A newly created array who is a shallow copy of @array. On
5679 * failure returns NULL and sets @error.
5682 mono_array_clone_checked (MonoArray *array, MonoError *error)
5685 MONO_REQ_GC_UNSAFE_MODE;
5686 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5689 /* helper macros to check for overflow when calculating the size of arrays */
5690 #ifdef MONO_BIG_ARRAYS
5691 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5692 #define MYGUINT_MAX MYGUINT64_MAX
5693 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5694 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5695 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5696 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5697 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5699 #define MYGUINT32_MAX 4294967295U
5700 #define MYGUINT_MAX MYGUINT32_MAX
5701 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5702 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5703 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5704 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5705 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5709 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5711 MONO_REQ_GC_NEUTRAL_MODE;
5715 byte_len = mono_array_element_size (klass);
5716 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5719 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5721 byte_len += MONO_SIZEOF_MONO_ARRAY;
5729 * mono_array_new_full:
5730 * @domain: domain where the object is created
5731 * @array_class: array class
5732 * @lengths: lengths for each dimension in the array
5733 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5735 * This routine creates a new array objects with the given dimensions,
5736 * lower bounds and type.
5739 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5742 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5743 mono_error_cleanup (&error);
5749 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5751 MONO_REQ_GC_UNSAFE_MODE;
5753 uintptr_t byte_len = 0, len, bounds_size;
5756 MonoArrayBounds *bounds;
5760 mono_error_init (error);
5762 if (!array_class->inited)
5763 mono_class_init (array_class);
5767 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5768 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5770 if (len > MONO_ARRAY_MAX_INDEX) {
5771 mono_error_set_generic_error (error, "System", "OverflowException", "");
5776 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5778 for (i = 0; i < array_class->rank; ++i) {
5779 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5780 mono_error_set_generic_error (error, "System", "OverflowException", "");
5783 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5784 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5791 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5792 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5798 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5799 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5802 byte_len = (byte_len + 3) & ~3;
5803 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5804 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5807 byte_len += bounds_size;
5810 * Following three lines almost taken from mono_object_new ():
5811 * they need to be kept in sync.
5813 vtable = mono_class_vtable_full (domain, array_class, error);
5814 return_val_if_nok (error, NULL);
5817 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5819 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5821 if (G_UNLIKELY (!o)) {
5822 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5826 array = (MonoArray*)o;
5828 bounds = array->bounds;
5831 for (i = 0; i < array_class->rank; ++i) {
5832 bounds [i].length = lengths [i];
5834 bounds [i].lower_bound = lower_bounds [i];
5843 * @domain: domain where the object is created
5844 * @eclass: element class
5845 * @n: number of array elements
5847 * This routine creates a new szarray with @n elements of type @eclass.
5850 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5852 MONO_REQ_GC_UNSAFE_MODE;
5855 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5856 mono_error_cleanup (&error);
5861 * mono_array_new_checked:
5862 * @domain: domain where the object is created
5863 * @eclass: element class
5864 * @n: number of array elements
5865 * @error: set on error
5867 * This routine creates a new szarray with @n elements of type @eclass.
5868 * On failure returns NULL and sets @error.
5871 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5875 mono_error_init (error);
5877 ac = mono_array_class_get (eclass, 1);
5880 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5881 return_val_if_nok (error, NULL);
5883 return mono_array_new_specific_checked (vtable, n, error);
5887 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5890 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5891 mono_error_set_pending_exception (&error);
5897 * mono_array_new_specific:
5898 * @vtable: a vtable in the appropriate domain for an initialized class
5899 * @n: number of array elements
5901 * This routine is a fast alternative to mono_array_new() for code which
5902 * can be sure about the domain it operates in.
5905 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5908 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5909 mono_error_cleanup (&error);
5915 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5917 MONO_REQ_GC_UNSAFE_MODE;
5922 mono_error_init (error);
5924 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5925 mono_error_set_generic_error (error, "System", "OverflowException", "");
5929 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5930 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5933 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5935 if (G_UNLIKELY (!o)) {
5936 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5940 return (MonoArray*)o;
5944 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5947 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5948 mono_error_set_pending_exception (&error);
5954 * mono_string_empty_wrapper:
5956 * Returns: The same empty string instance as the managed string.Empty
5959 mono_string_empty_wrapper (void)
5961 MonoDomain *domain = mono_domain_get ();
5962 return mono_string_empty (domain);
5966 * mono_string_empty:
5968 * Returns: The same empty string instance as the managed string.Empty
5971 mono_string_empty (MonoDomain *domain)
5974 g_assert (domain->empty_string);
5975 return domain->empty_string;
5979 * mono_string_new_utf16:
5980 * @text: a pointer to an utf16 string
5981 * @len: the length of the string
5983 * Returns: A newly created string object which contains @text.
5986 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5988 MONO_REQ_GC_UNSAFE_MODE;
5991 MonoString *res = NULL;
5992 res = mono_string_new_utf16_checked (domain, text, len, &error);
5993 mono_error_cleanup (&error);
5999 * mono_string_new_utf16_checked:
6000 * @text: a pointer to an utf16 string
6001 * @len: the length of the string
6002 * @error: written on error.
6004 * Returns: A newly created string object which contains @text.
6005 * On error, returns NULL and sets @error.
6008 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6010 MONO_REQ_GC_UNSAFE_MODE;
6014 mono_error_init (error);
6016 s = mono_string_new_size_checked (domain, len, error);
6018 memcpy (mono_string_chars (s), text, len * 2);
6024 * mono_string_new_utf32:
6025 * @text: a pointer to an utf32 string
6026 * @len: the length of the string
6027 * @error: set on failure.
6029 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6032 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6034 MONO_REQ_GC_UNSAFE_MODE;
6037 mono_unichar2 *utf16_output = NULL;
6038 gint32 utf16_len = 0;
6039 GError *gerror = NULL;
6040 glong items_written;
6042 mono_error_init (error);
6043 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6046 g_error_free (gerror);
6048 while (utf16_output [utf16_len]) utf16_len++;
6050 s = mono_string_new_size_checked (domain, utf16_len, error);
6051 return_val_if_nok (error, NULL);
6053 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6055 g_free (utf16_output);
6061 * mono_string_new_utf32:
6062 * @text: a pointer to an utf32 string
6063 * @len: the length of the string
6065 * Returns: A newly created string object which contains @text.
6068 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6071 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6072 mono_error_cleanup (&error);
6077 * mono_string_new_size:
6078 * @text: a pointer to an utf16 string
6079 * @len: the length of the string
6081 * Returns: A newly created string object of @len
6084 mono_string_new_size (MonoDomain *domain, gint32 len)
6087 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6088 mono_error_cleanup (&error);
6094 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6096 MONO_REQ_GC_UNSAFE_MODE;
6102 mono_error_init (error);
6104 /* check for overflow */
6105 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6106 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6110 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6111 g_assert (size > 0);
6113 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6116 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6118 if (G_UNLIKELY (!s)) {
6119 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6127 * mono_string_new_len:
6128 * @text: a pointer to an utf8 string
6129 * @length: number of bytes in @text to consider
6131 * Returns: A newly created string object which contains @text.
6134 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6136 MONO_REQ_GC_UNSAFE_MODE;
6139 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6140 mono_error_cleanup (&error);
6145 * mono_string_new_len_checked:
6146 * @text: a pointer to an utf8 string
6147 * @length: number of bytes in @text to consider
6148 * @error: set on error
6150 * Returns: A newly created string object which contains @text. On
6151 * failure returns NULL and sets @error.
6154 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6156 MONO_REQ_GC_UNSAFE_MODE;
6158 mono_error_init (error);
6160 GError *eg_error = NULL;
6161 MonoString *o = NULL;
6163 glong items_written;
6165 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6168 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6170 g_error_free (eg_error);
6179 * @text: a pointer to an utf8 string
6181 * Returns: A newly created string object which contains @text.
6183 * This function asserts if it cannot allocate a new string.
6185 * @deprecated Use mono_string_new_checked in new code.
6188 mono_string_new (MonoDomain *domain, const char *text)
6191 MonoString *res = NULL;
6192 res = mono_string_new_checked (domain, text, &error);
6193 mono_error_assert_ok (&error);
6198 * mono_string_new_checked:
6199 * @text: a pointer to an utf8 string
6200 * @merror: set on error
6202 * Returns: A newly created string object which contains @text.
6203 * On error returns NULL and sets @merror.
6206 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6208 MONO_REQ_GC_UNSAFE_MODE;
6210 GError *eg_error = NULL;
6211 MonoString *o = NULL;
6213 glong items_written;
6216 mono_error_init (error);
6220 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6223 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6225 g_error_free (eg_error);
6229 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6234 MonoString *o = NULL;
6236 if (!g_utf8_validate (text, -1, &end)) {
6237 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6241 len = g_utf8_strlen (text, -1);
6242 o = mono_string_new_size_checked (domain, len, error);
6245 str = mono_string_chars (o);
6247 while (text < end) {
6248 *str++ = g_utf8_get_char (text);
6249 text = g_utf8_next_char (text);
6258 * mono_string_new_wrapper:
6259 * @text: pointer to utf8 characters.
6261 * Helper function to create a string object from @text in the current domain.
6264 mono_string_new_wrapper (const char *text)
6266 MONO_REQ_GC_UNSAFE_MODE;
6268 MonoDomain *domain = mono_domain_get ();
6271 return mono_string_new (domain, text);
6278 * @class: the class of the value
6279 * @value: a pointer to the unboxed data
6281 * Returns: A newly created object which contains @value.
6284 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6287 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6288 mono_error_cleanup (&error);
6293 * mono_value_box_checked:
6294 * @domain: the domain of the new object
6295 * @class: the class of the value
6296 * @value: a pointer to the unboxed data
6297 * @error: set on error
6299 * Returns: A newly created object which contains @value. On failure
6300 * returns NULL and sets @error.
6303 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6305 MONO_REQ_GC_UNSAFE_MODE;
6310 mono_error_init (error);
6312 g_assert (klass->valuetype);
6313 if (mono_class_is_nullable (klass))
6314 return mono_nullable_box ((guint8 *)value, klass, error);
6316 vtable = mono_class_vtable (domain, klass);
6319 size = mono_class_instance_size (klass);
6320 res = mono_object_new_alloc_specific_checked (vtable, error);
6321 return_val_if_nok (error, NULL);
6323 size = size - sizeof (MonoObject);
6326 g_assert (size == mono_class_value_size (klass, NULL));
6327 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6329 #if NO_UNALIGNED_ACCESS
6330 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6334 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6337 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6340 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6343 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6346 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6350 if (klass->has_finalize) {
6351 mono_object_register_finalizer (res);
6352 return_val_if_nok (error, NULL);
6359 * @dest: destination pointer
6360 * @src: source pointer
6361 * @klass: a valuetype class
6363 * Copy a valuetype from @src to @dest. This function must be used
6364 * when @klass contains references fields.
6367 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6369 MONO_REQ_GC_UNSAFE_MODE;
6371 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6375 * mono_value_copy_array:
6376 * @dest: destination array
6377 * @dest_idx: index in the @dest array
6378 * @src: source pointer
6379 * @count: number of items
6381 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6382 * This function must be used when @klass contains references fields.
6383 * Overlap is handled.
6386 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6388 MONO_REQ_GC_UNSAFE_MODE;
6390 int size = mono_array_element_size (dest->obj.vtable->klass);
6391 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6392 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6393 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6397 * mono_object_get_domain:
6398 * @obj: object to query
6400 * Returns: the MonoDomain where the object is hosted
6403 mono_object_get_domain (MonoObject *obj)
6405 MONO_REQ_GC_UNSAFE_MODE;
6407 return mono_object_domain (obj);
6411 * mono_object_get_class:
6412 * @obj: object to query
6414 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6416 * Returns: the MonoClass of the object.
6419 mono_object_get_class (MonoObject *obj)
6421 MONO_REQ_GC_UNSAFE_MODE;
6423 return mono_object_class (obj);
6426 * mono_object_get_size:
6427 * @o: object to query
6429 * Returns: the size, in bytes, of @o
6432 mono_object_get_size (MonoObject* o)
6434 MONO_REQ_GC_UNSAFE_MODE;
6436 MonoClass* klass = mono_object_class (o);
6437 if (klass == mono_defaults.string_class) {
6438 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6439 } else if (o->vtable->rank) {
6440 MonoArray *array = (MonoArray*)o;
6441 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6442 if (array->bounds) {
6445 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6449 return mono_class_instance_size (klass);
6454 * mono_object_unbox:
6455 * @obj: object to unbox
6457 * Returns: a pointer to the start of the valuetype boxed in this
6460 * This method will assert if the object passed is not a valuetype.
6463 mono_object_unbox (MonoObject *obj)
6465 MONO_REQ_GC_UNSAFE_MODE;
6467 /* add assert for valuetypes? */
6468 g_assert (obj->vtable->klass->valuetype);
6469 return ((char*)obj) + sizeof (MonoObject);
6473 * mono_object_isinst:
6475 * @klass: a pointer to a class
6477 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6480 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6482 MONO_REQ_GC_UNSAFE_MODE;
6484 HANDLE_FUNCTION_ENTER ();
6485 MONO_HANDLE_DCL (MonoObject, obj);
6487 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6488 mono_error_cleanup (&error);
6489 HANDLE_FUNCTION_RETURN_OBJ (result);
6494 * mono_object_isinst_checked:
6496 * @klass: a pointer to a class
6497 * @error: set on error
6499 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6500 * On failure returns NULL and sets @error.
6503 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6505 MONO_REQ_GC_UNSAFE_MODE;
6507 HANDLE_FUNCTION_ENTER ();
6508 mono_error_init (error);
6509 MONO_HANDLE_DCL (MonoObject, obj);
6510 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6511 HANDLE_FUNCTION_RETURN_OBJ (result);
6515 * mono_object_handle_isinst:
6517 * @klass: a pointer to a class
6518 * @error: set on error
6520 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6521 * On failure returns NULL and sets @error.
6524 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6526 mono_error_init (error);
6529 mono_class_init (klass);
6531 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6532 return mono_object_handle_isinst_mbyref (obj, klass, error);
6535 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6537 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6538 MONO_HANDLE_ASSIGN (result, obj);
6543 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6545 MONO_REQ_GC_UNSAFE_MODE;
6547 HANDLE_FUNCTION_ENTER ();
6549 MONO_HANDLE_DCL (MonoObject, obj);
6550 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6551 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6552 HANDLE_FUNCTION_RETURN_OBJ (result);
6556 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6558 mono_error_init (error);
6560 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6562 if (MONO_HANDLE_IS_NULL (obj))
6565 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6567 if (mono_class_is_interface (klass)) {
6568 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6569 MONO_HANDLE_ASSIGN (result, obj);
6573 /* casting an array one of the invariant interfaces that must act as such */
6574 if (klass->is_array_special_interface) {
6575 if (mono_class_is_assignable_from (klass, vt->klass)) {
6576 MONO_HANDLE_ASSIGN (result, obj);
6581 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6582 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6583 MONO_HANDLE_ASSIGN (result, obj);
6587 MonoClass *oklass = vt->klass;
6588 if (mono_class_is_transparent_proxy (oklass)){
6589 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6590 oklass = remote_class->proxy_class;
6593 mono_class_setup_supertypes (klass);
6594 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6595 MONO_HANDLE_ASSIGN (result, obj);
6599 #ifndef DISABLE_REMOTING
6600 if (mono_class_is_transparent_proxy (vt->klass))
6602 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6603 if (!custom_type_info)
6605 MonoDomain *domain = mono_domain_get ();
6606 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6607 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6608 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6609 MonoMethod *im = NULL;
6612 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6614 mono_error_set_not_supported (error, "Linked away.");
6617 im = mono_object_handle_get_virtual_method (rp, im, error);
6622 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6626 pa [0] = MONO_HANDLE_RAW (reftype);
6627 pa [1] = MONO_HANDLE_RAW (obj);
6628 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6632 if (*(MonoBoolean *) mono_object_unbox(res)) {
6633 /* Update the vtable of the remote type, so it can safely cast to this new type */
6634 mono_upgrade_remote_class (domain, obj, klass, error);
6637 MONO_HANDLE_ASSIGN (result, obj);
6640 #endif /* DISABLE_REMOTING */
6646 * mono_object_castclass_mbyref:
6648 * @klass: a pointer to a class
6650 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6653 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6655 MONO_REQ_GC_UNSAFE_MODE;
6656 HANDLE_FUNCTION_ENTER ();
6658 MONO_HANDLE_DCL (MonoObject, obj);
6659 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6660 if (MONO_HANDLE_IS_NULL (obj))
6662 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6663 mono_error_cleanup (&error);
6665 HANDLE_FUNCTION_RETURN_OBJ (result);
6669 MonoDomain *orig_domain;
6675 str_lookup (MonoDomain *domain, gpointer user_data)
6677 MONO_REQ_GC_UNSAFE_MODE;
6679 LDStrInfo *info = (LDStrInfo *)user_data;
6680 if (info->res || domain == info->orig_domain)
6682 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6686 mono_string_get_pinned (MonoString *str, MonoError *error)
6688 MONO_REQ_GC_UNSAFE_MODE;
6690 mono_error_init (error);
6692 /* We only need to make a pinned version of a string if this is a moving GC */
6693 if (!mono_gc_is_moving ())
6697 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6698 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6700 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6701 news->length = mono_string_length (str);
6703 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6709 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6711 MONO_REQ_GC_UNSAFE_MODE;
6713 MonoGHashTable *ldstr_table;
6714 MonoString *s, *res;
6717 mono_error_init (error);
6719 domain = ((MonoObject *)str)->vtable->domain;
6720 ldstr_table = domain->ldstr_table;
6722 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6728 /* Allocate outside the lock */
6730 s = mono_string_get_pinned (str, error);
6731 return_val_if_nok (error, NULL);
6734 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6739 mono_g_hash_table_insert (ldstr_table, s, s);
6744 LDStrInfo ldstr_info;
6745 ldstr_info.orig_domain = domain;
6746 ldstr_info.ins = str;
6747 ldstr_info.res = NULL;
6749 mono_domain_foreach (str_lookup, &ldstr_info);
6750 if (ldstr_info.res) {
6752 * the string was already interned in some other domain:
6753 * intern it in the current one as well.
6755 mono_g_hash_table_insert (ldstr_table, str, str);
6765 * mono_string_is_interned:
6766 * @o: String to probe
6768 * Returns whether the string has been interned.
6771 mono_string_is_interned (MonoString *o)
6774 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6775 /* This function does not fail. */
6776 mono_error_assert_ok (&error);
6781 * mono_string_intern:
6782 * @o: String to intern
6784 * Interns the string passed.
6785 * Returns: The interned string.
6788 mono_string_intern (MonoString *str)
6791 MonoString *result = mono_string_intern_checked (str, &error);
6792 mono_error_assert_ok (&error);
6797 * mono_string_intern_checked:
6798 * @o: String to intern
6799 * @error: set on error.
6801 * Interns the string passed.
6802 * Returns: The interned string. On failure returns NULL and sets @error
6805 mono_string_intern_checked (MonoString *str, MonoError *error)
6807 MONO_REQ_GC_UNSAFE_MODE;
6809 mono_error_init (error);
6811 return mono_string_is_interned_lookup (str, TRUE, error);
6816 * @domain: the domain where the string will be used.
6817 * @image: a metadata context
6818 * @idx: index into the user string table.
6820 * Implementation for the ldstr opcode.
6821 * Returns: a loaded string from the @image/@idx combination.
6824 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6827 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6828 mono_error_cleanup (&error);
6833 * mono_ldstr_checked:
6834 * @domain: the domain where the string will be used.
6835 * @image: a metadata context
6836 * @idx: index into the user string table.
6837 * @error: set on error.
6839 * Implementation for the ldstr opcode.
6840 * Returns: a loaded string from the @image/@idx combination.
6841 * On failure returns NULL and sets @error.
6844 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6846 MONO_REQ_GC_UNSAFE_MODE;
6847 mono_error_init (error);
6849 if (image->dynamic) {
6850 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6853 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6854 return NULL; /*FIXME we should probably be raising an exception here*/
6855 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6861 * mono_ldstr_metadata_sig
6862 * @domain: the domain for the string
6863 * @sig: the signature of a metadata string
6864 * @error: set on error
6866 * Returns: a MonoString for a string stored in the metadata. On
6867 * failure returns NULL and sets @error.
6870 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6872 MONO_REQ_GC_UNSAFE_MODE;
6874 mono_error_init (error);
6875 const char *str = sig;
6876 MonoString *o, *interned;
6879 len2 = mono_metadata_decode_blob_size (str, &str);
6882 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6883 return_val_if_nok (error, NULL);
6884 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6887 guint16 *p2 = (guint16*)mono_string_chars (o);
6888 for (i = 0; i < len2; ++i) {
6889 *p2 = GUINT16_FROM_LE (*p2);
6895 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6898 return interned; /* o will get garbage collected */
6900 o = mono_string_get_pinned (o, error);
6903 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6905 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6917 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6921 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6927 GError *gerror = NULL;
6929 mono_error_init (error);
6931 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6932 return NULL; /*FIXME we should probably be raising an exception here*/
6933 str = mono_metadata_user_string (image, idx);
6935 len2 = mono_metadata_decode_blob_size (str, &str);
6938 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6940 mono_error_set_argument (error, "string", "%s", gerror->message);
6941 g_error_free (gerror);
6944 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6945 if (len2 > written) {
6946 /* allocate the total length and copy the part of the string that has been converted */
6947 char *as2 = (char *)g_malloc0 (len2);
6948 memcpy (as2, as, written);
6957 * mono_string_to_utf8:
6958 * @s: a System.String
6960 * Returns the UTF8 representation for @s.
6961 * The resulting buffer needs to be freed with mono_free().
6963 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6966 mono_string_to_utf8 (MonoString *s)
6968 MONO_REQ_GC_UNSAFE_MODE;
6971 char *result = mono_string_to_utf8_checked (s, &error);
6973 if (!is_ok (&error)) {
6974 mono_error_cleanup (&error);
6981 * mono_string_to_utf8_checked:
6982 * @s: a System.String
6983 * @error: a MonoError.
6985 * Converts a MonoString to its UTF8 representation. May fail; check
6986 * @error to determine whether the conversion was successful.
6987 * The resulting buffer should be freed with mono_free().
6990 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6992 MONO_REQ_GC_UNSAFE_MODE;
6996 GError *gerror = NULL;
6998 mono_error_init (error);
7004 return g_strdup ("");
7006 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7008 mono_error_set_argument (error, "string", "%s", gerror->message);
7009 g_error_free (gerror);
7012 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7013 if (s->length > written) {
7014 /* allocate the total length and copy the part of the string that has been converted */
7015 char *as2 = (char *)g_malloc0 (s->length);
7016 memcpy (as2, as, written);
7025 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7027 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7031 * mono_string_to_utf8_ignore:
7034 * Converts a MonoString to its UTF8 representation. Will ignore
7035 * invalid surrogate pairs.
7036 * The resulting buffer should be freed with mono_free().
7040 mono_string_to_utf8_ignore (MonoString *s)
7042 MONO_REQ_GC_UNSAFE_MODE;
7051 return g_strdup ("");
7053 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7055 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7056 if (s->length > written) {
7057 /* allocate the total length and copy the part of the string that has been converted */
7058 char *as2 = (char *)g_malloc0 (s->length);
7059 memcpy (as2, as, written);
7068 * mono_string_to_utf8_image_ignore:
7069 * @s: a System.String
7071 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7074 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7076 MONO_REQ_GC_UNSAFE_MODE;
7078 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7082 * mono_string_to_utf8_mp_ignore:
7083 * @s: a System.String
7085 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7088 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7090 MONO_REQ_GC_UNSAFE_MODE;
7092 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7097 * mono_string_to_utf16:
7100 * Return an null-terminated array of the utf-16 chars
7101 * contained in @s. The result must be freed with g_free().
7102 * This is a temporary helper until our string implementation
7103 * is reworked to always include the null terminating char.
7106 mono_string_to_utf16 (MonoString *s)
7108 MONO_REQ_GC_UNSAFE_MODE;
7115 as = (char *)g_malloc ((s->length * 2) + 2);
7116 as [(s->length * 2)] = '\0';
7117 as [(s->length * 2) + 1] = '\0';
7120 return (gunichar2 *)(as);
7123 memcpy (as, mono_string_chars(s), s->length * 2);
7124 return (gunichar2 *)(as);
7128 * mono_string_to_utf32:
7131 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7132 * contained in @s. The result must be freed with g_free().
7135 mono_string_to_utf32 (MonoString *s)
7137 MONO_REQ_GC_UNSAFE_MODE;
7139 mono_unichar4 *utf32_output = NULL;
7140 GError *error = NULL;
7141 glong items_written;
7146 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7149 g_error_free (error);
7151 return utf32_output;
7155 * mono_string_from_utf16:
7156 * @data: the UTF16 string (LPWSTR) to convert
7158 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7160 * Returns: a MonoString.
7163 mono_string_from_utf16 (gunichar2 *data)
7166 MonoString *result = mono_string_from_utf16_checked (data, &error);
7167 mono_error_cleanup (&error);
7172 * mono_string_from_utf16_checked:
7173 * @data: the UTF16 string (LPWSTR) to convert
7174 * @error: set on error
7176 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7178 * Returns: a MonoString. On failure sets @error and returns NULL.
7181 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7184 MONO_REQ_GC_UNSAFE_MODE;
7186 mono_error_init (error);
7187 MonoDomain *domain = mono_domain_get ();
7193 while (data [len]) len++;
7195 return mono_string_new_utf16_checked (domain, data, len, error);
7199 * mono_string_from_utf32:
7200 * @data: the UTF32 string (LPWSTR) to convert
7202 * Converts a UTF32 (UCS-4)to a MonoString.
7204 * Returns: a MonoString.
7207 mono_string_from_utf32 (mono_unichar4 *data)
7210 MonoString *result = mono_string_from_utf32_checked (data, &error);
7211 mono_error_cleanup (&error);
7216 * mono_string_from_utf32_checked:
7217 * @data: the UTF32 string (LPWSTR) to convert
7218 * @error: set on error
7220 * Converts a UTF32 (UCS-4)to a MonoString.
7222 * Returns: a MonoString. On failure returns NULL and sets @error.
7225 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7227 MONO_REQ_GC_UNSAFE_MODE;
7229 mono_error_init (error);
7230 MonoString* result = NULL;
7231 mono_unichar2 *utf16_output = NULL;
7232 GError *gerror = NULL;
7233 glong items_written;
7239 while (data [len]) len++;
7241 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7244 g_error_free (gerror);
7246 result = mono_string_from_utf16_checked (utf16_output, error);
7247 g_free (utf16_output);
7252 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7254 MONO_REQ_GC_UNSAFE_MODE;
7261 r = mono_string_to_utf8_ignore (s);
7263 r = mono_string_to_utf8_checked (s, error);
7264 if (!mono_error_ok (error))
7271 len = strlen (r) + 1;
7273 mp_s = (char *)mono_mempool_alloc (mp, len);
7275 mp_s = (char *)mono_image_alloc (image, len);
7277 memcpy (mp_s, r, len);
7285 * mono_string_to_utf8_image:
7286 * @s: a System.String
7288 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7291 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7293 MONO_REQ_GC_UNSAFE_MODE;
7295 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7299 * mono_string_to_utf8_mp:
7300 * @s: a System.String
7302 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7305 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7307 MONO_REQ_GC_UNSAFE_MODE;
7309 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7313 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7316 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7318 eh_callbacks = *cbs;
7321 MonoRuntimeExceptionHandlingCallbacks *
7322 mono_get_eh_callbacks (void)
7324 return &eh_callbacks;
7328 * mono_raise_exception:
7329 * @ex: exception object
7331 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7334 mono_raise_exception (MonoException *ex)
7336 MONO_REQ_GC_UNSAFE_MODE;
7339 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7340 * that will cause gcc to omit the function epilog, causing problems when
7341 * the JIT tries to walk the stack, since the return address on the stack
7342 * will point into the next function in the executable, not this one.
7344 eh_callbacks.mono_raise_exception (ex);
7348 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7350 MONO_REQ_GC_UNSAFE_MODE;
7352 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7356 * mono_wait_handle_new:
7357 * @domain: Domain where the object will be created
7358 * @handle: Handle for the wait handle
7359 * @error: set on error.
7361 * Returns: A new MonoWaitHandle created in the given domain for the
7362 * given handle. On failure returns NULL and sets @rror.
7365 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7367 MONO_REQ_GC_UNSAFE_MODE;
7369 MonoWaitHandle *res;
7370 gpointer params [1];
7371 static MonoMethod *handle_set;
7373 mono_error_init (error);
7374 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7375 return_val_if_nok (error, NULL);
7377 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7379 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7381 params [0] = &handle;
7383 mono_runtime_invoke_checked (handle_set, res, params, error);
7388 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7390 MONO_REQ_GC_UNSAFE_MODE;
7392 static MonoClassField *f_safe_handle = NULL;
7395 if (!f_safe_handle) {
7396 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7397 g_assert (f_safe_handle);
7400 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7406 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7408 MONO_REQ_GC_UNSAFE_MODE;
7410 RuntimeInvokeFunction runtime_invoke;
7412 mono_error_init (error);
7414 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7415 MonoMethod *method = mono_get_context_capture_method ();
7416 MonoMethod *wrapper;
7419 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7420 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7421 return_val_if_nok (error, NULL);
7422 domain->capture_context_method = mono_compile_method_checked (method, error);
7423 return_val_if_nok (error, NULL);
7426 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7428 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7431 * mono_async_result_new:
7432 * @domain:domain where the object will be created.
7433 * @handle: wait handle.
7434 * @state: state to pass to AsyncResult
7435 * @data: C closure data.
7436 * @error: set on error.
7438 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7439 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7440 * On failure returns NULL and sets @error.
7444 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7446 MONO_REQ_GC_UNSAFE_MODE;
7448 mono_error_init (error);
7449 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7450 return_val_if_nok (error, NULL);
7451 MonoObject *context = mono_runtime_capture_context (domain, error);
7452 return_val_if_nok (error, NULL);
7453 /* we must capture the execution context from the original thread */
7455 MONO_OBJECT_SETREF (res, execution_context, context);
7456 /* note: result may be null if the flow is suppressed */
7459 res->data = (void **)data;
7460 MONO_OBJECT_SETREF (res, object_data, object_data);
7461 MONO_OBJECT_SETREF (res, async_state, state);
7462 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7463 return_val_if_nok (error, NULL);
7465 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7467 res->sync_completed = FALSE;
7468 res->completed = FALSE;
7474 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7476 MONO_REQ_GC_UNSAFE_MODE;
7483 g_assert (ares->async_delegate);
7485 ac = (MonoAsyncCall*) ares->object_data;
7487 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7488 if (mono_error_set_pending_exception (&error))
7491 gpointer wait_event = NULL;
7493 ac->msg->exc = NULL;
7495 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7497 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7498 mono_threads_begin_abort_protected_block ();
7500 if (!ac->msg->exc) {
7501 MonoException *ex = mono_error_convert_to_exception (&error);
7502 ac->msg->exc = (MonoObject *)ex;
7504 mono_error_cleanup (&error);
7507 MONO_OBJECT_SETREF (ac, res, res);
7509 mono_monitor_enter ((MonoObject*) ares);
7510 ares->completed = 1;
7512 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7513 mono_monitor_exit ((MonoObject*) ares);
7515 if (wait_event != NULL)
7516 mono_w32event_set (wait_event);
7518 mono_error_init (&error); //the else branch would leave it in an undefined state
7520 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7522 mono_threads_end_abort_protected_block ();
7524 if (mono_error_set_pending_exception (&error))
7532 mono_message_init (MonoDomain *domain,
7533 MonoMethodMessage *this_obj,
7534 MonoReflectionMethod *method,
7535 MonoArray *out_args,
7538 MONO_REQ_GC_UNSAFE_MODE;
7540 static MonoMethod *init_message_method = NULL;
7542 if (!init_message_method) {
7543 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7544 g_assert (init_message_method != NULL);
7547 mono_error_init (error);
7548 /* FIXME set domain instead? */
7549 g_assert (domain == mono_domain_get ());
7556 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7557 return is_ok (error);
7560 #ifndef DISABLE_REMOTING
7562 * mono_remoting_invoke:
7563 * @real_proxy: pointer to a RealProxy object
7564 * @msg: The MonoMethodMessage to execute
7565 * @exc: used to store exceptions
7566 * @out_args: used to store output arguments
7568 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7569 * IMessage interface and it is not trivial to extract results from there. So
7570 * we call an helper method PrivateInvoke instead of calling
7571 * RealProxy::Invoke() directly.
7573 * Returns: the result object.
7576 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7578 MONO_REQ_GC_UNSAFE_MODE;
7581 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7586 mono_error_init (error);
7588 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7591 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7593 mono_error_set_not_supported (error, "Linked away.");
7596 real_proxy->vtable->domain->private_invoke_method = im;
7599 pa [0] = real_proxy;
7604 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7605 return_val_if_nok (error, NULL);
7612 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7613 MonoObject **exc, MonoArray **out_args, MonoError *error)
7615 MONO_REQ_GC_UNSAFE_MODE;
7617 static MonoClass *object_array_klass;
7618 mono_error_init (error);
7622 MonoMethodSignature *sig;
7624 int i, j, outarg_count = 0;
7626 #ifndef DISABLE_REMOTING
7627 if (target && mono_object_is_transparent_proxy (target)) {
7628 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7629 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7630 target = tp->rp->unwrapped_server;
7632 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7637 domain = mono_domain_get ();
7638 method = msg->method->method;
7639 sig = mono_method_signature (method);
7641 for (i = 0; i < sig->param_count; i++) {
7642 if (sig->params [i]->byref)
7646 if (!object_array_klass) {
7649 klass = mono_array_class_get (mono_defaults.object_class, 1);
7652 mono_memory_barrier ();
7653 object_array_klass = klass;
7656 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7657 return_val_if_nok (error, NULL);
7659 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7662 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7663 return_val_if_nok (error, NULL);
7665 for (i = 0, j = 0; i < sig->param_count; i++) {
7666 if (sig->params [i]->byref) {
7668 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7669 mono_array_setref (*out_args, j, arg);
7678 * prepare_to_string_method:
7680 * @target: Set to @obj or unboxed value if a valuetype
7682 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7685 prepare_to_string_method (MonoObject *obj, void **target)
7687 MONO_REQ_GC_UNSAFE_MODE;
7689 static MonoMethod *to_string = NULL;
7697 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7699 method = mono_object_get_virtual_method (obj, to_string);
7701 // Unbox value type if needed
7702 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7703 *target = mono_object_unbox (obj);
7709 * mono_object_to_string:
7711 * @exc: Any exception thrown by ToString (). May be NULL.
7713 * Returns: the result of calling ToString () on an object.
7716 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7719 MonoString *s = NULL;
7721 MonoMethod *method = prepare_to_string_method (obj, &target);
7723 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7724 if (*exc == NULL && !mono_error_ok (&error))
7725 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7727 mono_error_cleanup (&error);
7729 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7730 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7737 * mono_object_to_string_checked:
7739 * @error: Set on error.
7741 * Returns: the result of calling ToString () on an object. If the
7742 * method cannot be invoked or if it raises an exception, sets @error
7746 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7748 mono_error_init (error);
7750 MonoMethod *method = prepare_to_string_method (obj, &target);
7751 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7755 * mono_object_try_to_string:
7757 * @exc: Any exception thrown by ToString (). Must not be NULL.
7758 * @error: Set if method cannot be invoked.
7760 * Returns: the result of calling ToString () on an object. If the
7761 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7765 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7768 mono_error_init (error);
7770 MonoMethod *method = prepare_to_string_method (obj, &target);
7771 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7777 get_native_backtrace (MonoException *exc_raw)
7779 HANDLE_FUNCTION_ENTER ();
7780 MONO_HANDLE_DCL(MonoException, exc);
7781 char * trace = mono_exception_handle_get_native_backtrace (exc);
7782 HANDLE_FUNCTION_RETURN_VAL (trace);
7786 * mono_print_unhandled_exception:
7787 * @exc: The exception
7789 * Prints the unhandled exception.
7792 mono_print_unhandled_exception (MonoObject *exc)
7794 MONO_REQ_GC_UNSAFE_MODE;
7797 char *message = (char*)"";
7798 gboolean free_message = FALSE;
7801 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7802 message = g_strdup ("OutOfMemoryException");
7803 free_message = TRUE;
7804 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7805 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7806 free_message = TRUE;
7809 if (((MonoException*)exc)->native_trace_ips) {
7810 message = get_native_backtrace ((MonoException*)exc);
7811 free_message = TRUE;
7813 MonoObject *other_exc = NULL;
7814 str = mono_object_try_to_string (exc, &other_exc, &error);
7815 if (other_exc == NULL && !is_ok (&error))
7816 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7818 mono_error_cleanup (&error);
7820 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7821 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7823 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7824 original_backtrace, nested_backtrace);
7826 g_free (original_backtrace);
7827 g_free (nested_backtrace);
7828 free_message = TRUE;
7830 message = mono_string_to_utf8_checked (str, &error);
7831 if (!mono_error_ok (&error)) {
7832 mono_error_cleanup (&error);
7833 message = (char *) "";
7835 free_message = TRUE;
7842 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7843 * exc->vtable->klass->name, message);
7845 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7852 * mono_delegate_ctor_with_method:
7853 * @this: pointer to an uninitialized delegate object
7854 * @target: target object
7855 * @addr: pointer to native code
7857 * @error: set on error.
7859 * Initialize a delegate and sets a specific method, not the one
7860 * associated with addr. This is useful when sharing generic code.
7861 * In that case addr will most probably not be associated with the
7862 * correct instantiation of the method.
7863 * On failure returns FALSE and sets @error.
7866 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7868 MONO_REQ_GC_UNSAFE_MODE;
7870 mono_error_init (error);
7871 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7873 g_assert (this_obj);
7876 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7879 delegate->method = method;
7881 mono_stats.delegate_creations++;
7883 #ifndef DISABLE_REMOTING
7884 if (target && mono_object_is_transparent_proxy (target)) {
7886 method = mono_marshal_get_remoting_invoke (method);
7887 delegate->method_ptr = mono_compile_method_checked (method, error);
7888 return_val_if_nok (error, FALSE);
7889 MONO_OBJECT_SETREF (delegate, target, target);
7893 delegate->method_ptr = addr;
7894 MONO_OBJECT_SETREF (delegate, target, target);
7897 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7898 if (callbacks.init_delegate)
7899 callbacks.init_delegate (delegate);
7904 * mono_delegate_ctor:
7905 * @this: pointer to an uninitialized delegate object
7906 * @target: target object
7907 * @addr: pointer to native code
7908 * @error: set on error.
7910 * This is used to initialize a delegate.
7911 * On failure returns FALSE and sets @error.
7914 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7916 MONO_REQ_GC_UNSAFE_MODE;
7918 mono_error_init (error);
7919 MonoDomain *domain = mono_domain_get ();
7921 MonoMethod *method = NULL;
7925 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7927 if (!ji && domain != mono_get_root_domain ())
7928 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7930 method = mono_jit_info_get_method (ji);
7931 g_assert (!mono_class_is_gtd (method->klass));
7934 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7938 * mono_method_call_message_new:
7939 * @method: method to encapsulate
7940 * @params: parameters to the method
7941 * @invoke: optional, delegate invoke.
7942 * @cb: async callback delegate.
7943 * @state: state passed to the async callback.
7944 * @error: set on error.
7946 * Translates arguments pointers into a MonoMethodMessage.
7947 * On failure returns NULL and sets @error.
7950 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7951 MonoDelegate **cb, MonoObject **state, MonoError *error)
7953 MONO_REQ_GC_UNSAFE_MODE;
7955 mono_error_init (error);
7957 MonoDomain *domain = mono_domain_get ();
7958 MonoMethodSignature *sig = mono_method_signature (method);
7959 MonoMethodMessage *msg;
7962 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7963 return_val_if_nok (error, NULL);
7966 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7967 return_val_if_nok (error, NULL);
7968 mono_message_init (domain, msg, rm, NULL, error);
7969 return_val_if_nok (error, NULL);
7970 count = sig->param_count - 2;
7972 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7973 return_val_if_nok (error, NULL);
7974 mono_message_init (domain, msg, rm, NULL, error);
7975 return_val_if_nok (error, NULL);
7976 count = sig->param_count;
7979 for (i = 0; i < count; i++) {
7984 if (sig->params [i]->byref)
7985 vpos = *((gpointer *)params [i]);
7989 klass = mono_class_from_mono_type (sig->params [i]);
7991 if (klass->valuetype) {
7992 arg = mono_value_box_checked (domain, klass, vpos, error);
7993 return_val_if_nok (error, NULL);
7995 arg = *((MonoObject **)vpos);
7997 mono_array_setref (msg->args, i, arg);
8000 if (cb != NULL && state != NULL) {
8001 *cb = *((MonoDelegate **)params [i]);
8003 *state = *((MonoObject **)params [i]);
8010 * mono_method_return_message_restore:
8012 * Restore results from message based processing back to arguments pointers
8015 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8017 MONO_REQ_GC_UNSAFE_MODE;
8019 mono_error_init (error);
8021 MonoMethodSignature *sig = mono_method_signature (method);
8022 int i, j, type, size, out_len;
8024 if (out_args == NULL)
8026 out_len = mono_array_length (out_args);
8030 for (i = 0, j = 0; i < sig->param_count; i++) {
8031 MonoType *pt = sig->params [i];
8036 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8040 arg = (char *)mono_array_get (out_args, gpointer, j);
8043 g_assert (type != MONO_TYPE_VOID);
8045 if (MONO_TYPE_IS_REFERENCE (pt)) {
8046 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8049 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8050 size = mono_class_value_size (klass, NULL);
8051 if (klass->has_references)
8052 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8054 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8056 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8057 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8066 #ifndef DISABLE_REMOTING
8069 * mono_load_remote_field:
8070 * @this: pointer to an object
8071 * @klass: klass of the object containing @field
8072 * @field: the field to load
8073 * @res: a storage to store the result
8075 * This method is called by the runtime on attempts to load fields of
8076 * transparent proxy objects. @this points to such TP, @klass is the class of
8077 * the object containing @field. @res is a storage location which can be
8078 * used to store the result.
8080 * Returns: an address pointing to the value of field.
8083 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8086 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8087 mono_error_cleanup (&error);
8092 * mono_load_remote_field_checked:
8093 * @this: pointer to an object
8094 * @klass: klass of the object containing @field
8095 * @field: the field to load
8096 * @res: a storage to store the result
8097 * @error: set on error
8099 * This method is called by the runtime on attempts to load fields of
8100 * transparent proxy objects. @this points to such TP, @klass is the class of
8101 * the object containing @field. @res is a storage location which can be
8102 * used to store the result.
8104 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8107 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8109 MONO_REQ_GC_UNSAFE_MODE;
8111 static MonoMethod *getter = NULL;
8113 mono_error_init (error);
8115 MonoDomain *domain = mono_domain_get ();
8116 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8117 MonoClass *field_class;
8118 MonoMethodMessage *msg;
8119 MonoArray *out_args;
8123 g_assert (mono_object_is_transparent_proxy (this_obj));
8124 g_assert (res != NULL);
8126 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8127 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8132 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8134 mono_error_set_not_supported (error, "Linked away.");
8139 field_class = mono_class_from_mono_type (field->type);
8141 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8142 return_val_if_nok (error, NULL);
8143 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8144 return_val_if_nok (error, NULL);
8145 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8146 return_val_if_nok (error, NULL);
8147 mono_message_init (domain, msg, rm, out_args, error);
8148 return_val_if_nok (error, NULL);
8150 full_name = mono_type_get_full_name (klass);
8151 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8152 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8155 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8156 return_val_if_nok (error, NULL);
8159 mono_error_set_exception_instance (error, (MonoException *)exc);
8163 if (mono_array_length (out_args) == 0)
8166 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8168 if (field_class->valuetype) {
8169 return ((char *)*res) + sizeof (MonoObject);
8175 * mono_load_remote_field_new:
8180 * Missing documentation.
8183 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8187 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8188 mono_error_cleanup (&error);
8193 * mono_load_remote_field_new_checked:
8194 * @this: pointer to an object
8195 * @klass: klass of the object containing @field
8196 * @field: the field to load
8197 * @error: set on error.
8199 * This method is called by the runtime on attempts to load fields of
8200 * transparent proxy objects. @this points to such TP, @klass is the class of
8201 * the object containing @field.
8203 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8206 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8208 MONO_REQ_GC_UNSAFE_MODE;
8210 mono_error_init (error);
8212 static MonoMethod *tp_load = NULL;
8214 g_assert (mono_object_is_transparent_proxy (this_obj));
8217 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8219 mono_error_set_not_supported (error, "Linked away.");
8224 /* MonoType *type = mono_class_get_type (klass); */
8230 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8234 * mono_store_remote_field:
8235 * @this_obj: pointer to an object
8236 * @klass: klass of the object containing @field
8237 * @field: the field to load
8238 * @val: the value/object to store
8240 * This method is called by the runtime on attempts to store fields of
8241 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8242 * the object containing @field. @val is the new value to store in @field.
8245 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8248 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8249 mono_error_cleanup (&error);
8253 * mono_store_remote_field_checked:
8254 * @this_obj: pointer to an object
8255 * @klass: klass of the object containing @field
8256 * @field: the field to load
8257 * @val: the value/object to store
8258 * @error: set on error
8260 * This method is called by the runtime on attempts to store fields of
8261 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8262 * the object containing @field. @val is the new value to store in @field.
8264 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8267 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8270 MONO_REQ_GC_UNSAFE_MODE;
8272 mono_error_init (error);
8274 MonoDomain *domain = mono_domain_get ();
8275 MonoClass *field_class;
8278 g_assert (mono_object_is_transparent_proxy (this_obj));
8280 field_class = mono_class_from_mono_type (field->type);
8282 if (field_class->valuetype) {
8283 arg = mono_value_box_checked (domain, field_class, val, error);
8284 return_val_if_nok (error, FALSE);
8286 arg = *((MonoObject**)val);
8289 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8293 * mono_store_remote_field_new:
8299 * Missing documentation
8302 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8305 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8306 mono_error_cleanup (&error);
8310 * mono_store_remote_field_new_checked:
8317 * Missing documentation
8320 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8322 MONO_REQ_GC_UNSAFE_MODE;
8324 static MonoMethod *tp_store = NULL;
8326 mono_error_init (error);
8328 g_assert (mono_object_is_transparent_proxy (this_obj));
8331 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8333 mono_error_set_not_supported (error, "Linked away.");
8343 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8344 return is_ok (error);
8349 * mono_create_ftnptr:
8351 * Given a function address, create a function descriptor for it.
8352 * This is only needed on some platforms.
8355 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8357 return callbacks.create_ftnptr (domain, addr);
8361 * mono_get_addr_from_ftnptr:
8363 * Given a pointer to a function descriptor, return the function address.
8364 * This is only needed on some platforms.
8367 mono_get_addr_from_ftnptr (gpointer descr)
8369 return callbacks.get_addr_from_ftnptr (descr);
8373 * mono_string_chars:
8376 * Returns a pointer to the UCS16 characters stored in the MonoString
8379 mono_string_chars (MonoString *s)
8381 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8387 * mono_string_length:
8390 * Returns the lenght in characters of the string
8393 mono_string_length (MonoString *s)
8395 MONO_REQ_GC_UNSAFE_MODE;
8401 * mono_array_length:
8402 * @array: a MonoArray*
8404 * Returns the total number of elements in the array. This works for
8405 * both vectors and multidimensional arrays.
8408 mono_array_length (MonoArray *array)
8410 MONO_REQ_GC_UNSAFE_MODE;
8412 return array->max_length;
8416 * mono_array_addr_with_size:
8417 * @array: a MonoArray*
8418 * @size: size of the array elements
8419 * @idx: index into the array
8421 * Use this function to obtain the address for the @idx item on the
8422 * @array containing elements of size @size.
8424 * This method performs no bounds checking or type checking.
8426 * Returns the address of the @idx element in the array.
8429 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8431 MONO_REQ_GC_UNSAFE_MODE;
8433 return ((char*)(array)->vector) + size * idx;
8438 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8440 MonoDomain *domain = mono_domain_get ();
8444 mono_error_init (error);
8448 len = g_list_length (list);
8449 res = mono_array_new_checked (domain, eclass, len, error);
8450 return_val_if_nok (error, NULL);
8452 for (i = 0; list; list = list->next, i++)
8453 mono_array_set (res, gpointer, i, list->data);
8460 * The following section is purely to declare prototypes and
8461 * document the API, as these C files are processed by our
8467 * @array: array to alter
8468 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8469 * @index: index into the array
8470 * @value: value to set
8472 * Value Type version: This sets the @index's element of the @array
8473 * with elements of size sizeof(type) to the provided @value.
8475 * This macro does not attempt to perform type checking or bounds checking.
8477 * Use this to set value types in a `MonoArray`.
8479 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8484 * mono_array_setref:
8485 * @array: array to alter
8486 * @index: index into the array
8487 * @value: value to set
8489 * Reference Type version: This sets the @index's element of the
8490 * @array with elements of size sizeof(type) to the provided @value.
8492 * This macro does not attempt to perform type checking or bounds checking.
8494 * Use this to reference types in a `MonoArray`.
8496 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8502 * @array: array on which to operate on
8503 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8504 * @index: index into the array
8506 * Use this macro to retrieve the @index element of an @array and
8507 * extract the value assuming that the elements of the array match
8508 * the provided type value.
8510 * This method can be used with both arrays holding value types and
8511 * reference types. For reference types, the @type parameter should
8512 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8514 * This macro does not attempt to perform type checking or bounds checking.
8516 * Returns: The element at the @index position in the @array.
8518 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)