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 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
71 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
73 /* Class lazy loading functions */
74 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
75 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
76 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
77 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
78 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
81 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
82 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
83 static mono_mutex_t ldstr_section;
87 * mono_runtime_object_init:
88 * @this_obj: the object to initialize
90 * This function calls the zero-argument constructor (which must
91 * exist) for the given object.
94 mono_runtime_object_init (MonoObject *this_obj)
97 mono_runtime_object_init_checked (this_obj, &error);
98 mono_error_assert_ok (&error);
102 * mono_runtime_object_init_checked:
103 * @this_obj: the object to initialize
104 * @error: set on error.
106 * This function calls the zero-argument constructor (which must
107 * exist) for the given object and returns TRUE on success, or FALSE
108 * on error and sets @error.
111 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
113 MONO_REQ_GC_UNSAFE_MODE;
115 MonoMethod *method = NULL;
116 MonoClass *klass = this_obj->vtable->klass;
118 mono_error_init (error);
119 method = mono_class_get_method_from_name (klass, ".ctor", 0);
121 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
123 if (method->klass->valuetype)
124 this_obj = (MonoObject *)mono_object_unbox (this_obj);
126 mono_runtime_invoke_checked (method, this_obj, NULL, error);
127 return is_ok (error);
130 /* The pseudo algorithm for type initialization from the spec
131 Note it doesn't say anything about domains - only threads.
133 2. If the type is initialized you are done.
134 2.1. If the type is not yet initialized, try to take an
136 2.2. If successful, record this thread as responsible for
137 initializing the type and proceed to step 2.3.
138 2.2.1. If not, see whether this thread or any thread
139 waiting for this thread to complete already holds the lock.
140 2.2.2. If so, return since blocking would create a deadlock. This thread
141 will now see an incompletely initialized state for the type,
142 but no deadlock will arise.
143 2.2.3 If not, block until the type is initialized then return.
144 2.3 Initialize the parent type and then all interfaces implemented
146 2.4 Execute the type initialization code for this type.
147 2.5 Mark the type as initialized, release the initialization lock,
148 awaken any threads waiting for this type to be initialized,
155 MonoNativeThreadId initializing_tid;
156 guint32 waiting_count;
159 /* condvar used to wait for 'done' becoming TRUE */
161 } TypeInitializationLock;
163 /* for locking access to type_initialization_hash and blocked_thread_hash */
164 static MonoCoopMutex type_initialization_section;
167 mono_type_initialization_lock (void)
169 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
170 mono_coop_mutex_lock (&type_initialization_section);
174 mono_type_initialization_unlock (void)
176 mono_coop_mutex_unlock (&type_initialization_section);
180 mono_type_init_lock (TypeInitializationLock *lock)
182 MONO_REQ_GC_NEUTRAL_MODE;
184 mono_coop_mutex_lock (&lock->mutex);
188 mono_type_init_unlock (TypeInitializationLock *lock)
190 mono_coop_mutex_unlock (&lock->mutex);
193 /* from vtable to lock */
194 static GHashTable *type_initialization_hash;
196 /* from thread id to thread id being waited on */
197 static GHashTable *blocked_thread_hash;
200 static MonoThread *main_thread;
202 /* Functions supplied by the runtime */
203 static MonoRuntimeCallbacks callbacks;
206 * mono_thread_set_main:
207 * @thread: thread to set as the main thread
209 * This function can be used to instruct the runtime to treat @thread
210 * as the main thread, ie, the thread that would normally execute the Main()
211 * method. This basically means that at the end of @thread, the runtime will
212 * wait for the existing foreground threads to quit and other such details.
215 mono_thread_set_main (MonoThread *thread)
217 MONO_REQ_GC_UNSAFE_MODE;
219 static gboolean registered = FALSE;
222 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
226 main_thread = thread;
230 mono_thread_get_main (void)
232 MONO_REQ_GC_UNSAFE_MODE;
238 mono_type_initialization_init (void)
240 mono_coop_mutex_init_recursive (&type_initialization_section);
241 type_initialization_hash = g_hash_table_new (NULL, NULL);
242 blocked_thread_hash = g_hash_table_new (NULL, NULL);
243 mono_os_mutex_init_recursive (&ldstr_section);
247 mono_type_initialization_cleanup (void)
250 /* This is causing race conditions with
251 * mono_release_type_locks
253 mono_coop_mutex_destroy (&type_initialization_section);
254 g_hash_table_destroy (type_initialization_hash);
255 type_initialization_hash = NULL;
257 mono_os_mutex_destroy (&ldstr_section);
258 g_hash_table_destroy (blocked_thread_hash);
259 blocked_thread_hash = NULL;
265 * get_type_init_exception_for_vtable:
267 * Return the stored type initialization exception for VTABLE.
269 static MonoException*
270 get_type_init_exception_for_vtable (MonoVTable *vtable)
272 MONO_REQ_GC_UNSAFE_MODE;
275 MonoDomain *domain = vtable->domain;
276 MonoClass *klass = vtable->klass;
280 if (!vtable->init_failed)
281 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
284 * If the initializing thread was rudely aborted, the exception is not stored
288 mono_domain_lock (domain);
289 if (domain->type_init_exception_hash)
290 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
291 mono_domain_unlock (domain);
294 if (klass->name_space && *klass->name_space)
295 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
297 full_name = g_strdup (klass->name);
298 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
300 return_val_if_nok (&error, NULL);
307 * mono_runtime_class_init:
308 * @vtable: vtable that needs to be initialized
310 * This routine calls the class constructor for @vtable.
313 mono_runtime_class_init (MonoVTable *vtable)
315 MONO_REQ_GC_UNSAFE_MODE;
318 mono_runtime_class_init_full (vtable, &error);
319 mono_error_assert_ok (&error);
323 * Returns TRUE if the lock was freed.
324 * LOCKING: Caller should hold type_initialization_lock.
327 unref_type_lock (TypeInitializationLock *lock)
329 --lock->waiting_count;
330 if (lock->waiting_count == 0) {
331 mono_coop_mutex_destroy (&lock->mutex);
332 mono_coop_cond_destroy (&lock->cond);
341 * mono_runtime_class_init_full:
342 * @vtable that neeeds to be initialized
343 * @error set on error
345 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
349 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
351 MONO_REQ_GC_UNSAFE_MODE;
353 MonoMethod *method = NULL;
356 MonoDomain *domain = vtable->domain;
357 TypeInitializationLock *lock;
358 MonoNativeThreadId tid;
359 int do_initialization = 0;
360 MonoDomain *last_domain = NULL;
361 MonoException * pending_tae = NULL;
363 mono_error_init (error);
365 if (vtable->initialized)
368 klass = vtable->klass;
370 if (!klass->image->checked_module_cctor) {
371 mono_image_check_for_module_cctor (klass->image);
372 if (klass->image->has_module_cctor) {
373 MonoClass *module_klass;
374 MonoVTable *module_vtable;
376 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
381 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
384 if (!mono_runtime_class_init_full (module_vtable, error))
388 method = mono_class_get_cctor (klass);
390 vtable->initialized = 1;
394 tid = mono_native_thread_id_get ();
397 * Due some preprocessing inside a global lock. If we are the first thread
398 * trying to initialize this class, create a separate lock+cond var, and
399 * acquire it before leaving the global lock. The other threads will wait
403 mono_type_initialization_lock ();
404 /* double check... */
405 if (vtable->initialized) {
406 mono_type_initialization_unlock ();
409 if (vtable->init_failed) {
410 mono_type_initialization_unlock ();
412 /* The type initialization already failed once, rethrow the same exception */
413 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
416 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
418 /* This thread will get to do the initialization */
419 if (mono_domain_get () != domain) {
420 /* Transfer into the target domain */
421 last_domain = mono_domain_get ();
422 if (!mono_domain_set (domain, FALSE)) {
423 vtable->initialized = 1;
424 mono_type_initialization_unlock ();
425 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
429 lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
430 mono_coop_mutex_init_recursive (&lock->mutex);
431 mono_coop_cond_init (&lock->cond);
432 lock->initializing_tid = tid;
433 lock->waiting_count = 1;
435 /* grab the vtable lock while this thread still owns type_initialization_section */
436 /* This is why type_initialization_lock needs to enter blocking mode */
437 mono_type_init_lock (lock);
438 g_hash_table_insert (type_initialization_hash, vtable, lock);
439 do_initialization = 1;
442 TypeInitializationLock *pending_lock;
444 if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
445 mono_type_initialization_unlock ();
448 /* see if the thread doing the initialization is already blocked on this thread */
449 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
450 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
451 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
452 if (!pending_lock->done) {
453 mono_type_initialization_unlock ();
456 /* the thread doing the initialization is blocked on this thread,
457 but on a lock that has already been freed. It just hasn't got
462 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
464 ++lock->waiting_count;
465 /* record the fact that we are waiting on the initializing thread */
466 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
468 mono_type_initialization_unlock ();
470 if (do_initialization) {
471 MonoException *exc = NULL;
473 /* We are holding the per-vtable lock, do the actual initialization */
475 mono_threads_begin_abort_protected_block ();
476 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
477 gboolean got_pending_interrupt = mono_threads_end_abort_protected_block ();
479 //exception extracted, error will be set to the right value later
480 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
481 exc = mono_error_convert_to_exception (error);
483 mono_error_cleanup (error);
485 mono_error_init (error);
487 /* If the initialization failed, mark the class as unusable. */
488 /* Avoid infinite loops */
490 (klass->image == mono_defaults.corlib &&
491 !strcmp (klass->name_space, "System") &&
492 !strcmp (klass->name, "TypeInitializationException")))) {
493 vtable->init_failed = 1;
495 if (klass->name_space && *klass->name_space)
496 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
498 full_name = g_strdup (klass->name);
500 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
503 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
506 * Store the exception object so it could be thrown on subsequent
509 mono_domain_lock (domain);
510 if (!domain->type_init_exception_hash)
511 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");
512 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
513 mono_domain_unlock (domain);
517 mono_domain_set (last_domain, TRUE);
518 /* Signal to the other threads that we are done */
520 mono_coop_cond_broadcast (&lock->cond);
522 mono_type_init_unlock (lock);
524 //This can happen if the cctor self-aborts
525 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
528 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
529 if (!pending_tae && got_pending_interrupt)
530 pending_tae = mono_thread_try_resume_interruption ();
532 /* this just blocks until the initializing thread is done */
533 mono_type_init_lock (lock);
535 mono_coop_cond_wait (&lock->cond, &lock->mutex);
536 mono_type_init_unlock (lock);
539 /* Do cleanup and setting vtable->initialized inside the global lock again */
540 mono_type_initialization_lock ();
541 if (!do_initialization)
542 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
543 gboolean deleted = unref_type_lock (lock);
545 g_hash_table_remove (type_initialization_hash, vtable);
546 /* Have to set this here since we check it inside the global lock */
547 if (do_initialization && !vtable->init_failed)
548 vtable->initialized = 1;
549 mono_type_initialization_unlock ();
553 mono_error_set_exception_instance (error, pending_tae);
554 else if (vtable->init_failed) {
555 /* Either we were the initializing thread or we waited for the initialization */
556 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
563 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
565 MONO_REQ_GC_NEUTRAL_MODE;
567 MonoVTable *vtable = (MonoVTable*)key;
569 TypeInitializationLock *lock = (TypeInitializationLock*) value;
570 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
573 * Have to set this since it cannot be set by the normal code in
574 * mono_runtime_class_init (). In this case, the exception object is not stored,
575 * and get_type_init_exception_for_class () needs to be aware of this.
577 vtable->init_failed = 1;
578 mono_coop_cond_broadcast (&lock->cond);
579 mono_type_init_unlock (lock);
580 gboolean deleted = unref_type_lock (lock);
588 mono_release_type_locks (MonoInternalThread *thread)
590 MONO_REQ_GC_UNSAFE_MODE;
592 mono_type_initialization_lock ();
593 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
594 mono_type_initialization_unlock ();
597 #ifndef DISABLE_REMOTING
600 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
602 if (!callbacks.create_remoting_trampoline)
603 g_error ("remoting not installed");
604 return callbacks.create_remoting_trampoline (domain, method, target, error);
609 static MonoImtTrampolineBuilder imt_trampoline_builder;
610 static gboolean always_build_imt_trampolines;
612 #if (MONO_IMT_SIZE > 32)
613 #error "MONO_IMT_SIZE cannot be larger than 32"
617 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
619 memcpy (&callbacks, cbs, sizeof (*cbs));
622 MonoRuntimeCallbacks*
623 mono_get_runtime_callbacks (void)
629 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
631 imt_trampoline_builder = func;
635 mono_set_always_build_imt_trampolines (gboolean value)
637 always_build_imt_trampolines = value;
641 * mono_compile_method:
642 * @method: The method to compile.
644 * This JIT-compiles the method, and returns the pointer to the native code
648 mono_compile_method (MonoMethod *method)
651 gpointer result = mono_compile_method_checked (method, &error);
652 mono_error_cleanup (&error);
657 * mono_compile_method:
658 * @method: The method to compile.
659 * @error: set on error.
661 * This JIT-compiles the method, and returns the pointer to the native code
662 * produced. On failure returns NULL and sets @error.
665 mono_compile_method_checked (MonoMethod *method, MonoError *error)
669 MONO_REQ_GC_NEUTRAL_MODE
671 mono_error_init (error);
673 g_assert (callbacks.compile_method);
674 res = callbacks.compile_method (method, error);
679 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
683 MONO_REQ_GC_NEUTRAL_MODE;
685 mono_error_init (error);
686 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
691 mono_runtime_create_delegate_trampoline (MonoClass *klass)
693 MONO_REQ_GC_NEUTRAL_MODE
695 g_assert (callbacks.create_delegate_trampoline);
696 return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
700 * mono_runtime_free_method:
701 * @domain; domain where the method is hosted
702 * @method: method to release
704 * This routine is invoked to free the resources associated with
705 * a method that has been JIT compiled. This is used to discard
706 * methods that were used only temporarily (for example, used in marshalling)
710 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
712 MONO_REQ_GC_NEUTRAL_MODE
714 if (callbacks.free_method)
715 callbacks.free_method (domain, method);
717 mono_method_clear_object (domain, method);
719 mono_free_method (method);
723 * The vtables in the root appdomain are assumed to be reachable by other
724 * roots, and we don't use typed allocation in the other domains.
727 /* The sync block is no longer a GC pointer */
728 #define GC_HEADER_BITMAP (0)
730 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
733 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
735 MONO_REQ_GC_NEUTRAL_MODE;
737 MonoClassField *field;
743 max_size = mono_class_data_size (klass) / sizeof (gpointer);
745 max_size = klass->instance_size / sizeof (gpointer);
746 if (max_size > size) {
747 g_assert (offset <= 0);
748 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
753 /*An Ephemeron cannot be marked by sgen*/
754 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
756 memset (bitmap, 0, size / 8);
761 for (p = klass; p != NULL; p = p->parent) {
762 gpointer iter = NULL;
763 while ((field = mono_class_get_fields (p, &iter))) {
767 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
769 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
772 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
775 /* FIXME: should not happen, flag as type load error */
776 if (field->type->byref)
779 if (static_fields && field->offset == -1)
783 pos = field->offset / sizeof (gpointer);
786 type = mono_type_get_underlying_type (field->type);
787 switch (type->type) {
790 case MONO_TYPE_FNPTR:
792 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
797 if (klass->image != mono_defaults.corlib)
800 case MONO_TYPE_STRING:
801 case MONO_TYPE_SZARRAY:
802 case MONO_TYPE_CLASS:
803 case MONO_TYPE_OBJECT:
804 case MONO_TYPE_ARRAY:
805 g_assert ((field->offset % sizeof(gpointer)) == 0);
807 g_assert (pos < size || pos <= max_size);
808 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
809 *max_set = MAX (*max_set, pos);
811 case MONO_TYPE_GENERICINST:
812 if (!mono_type_generic_inst_is_valuetype (type)) {
813 g_assert ((field->offset % sizeof(gpointer)) == 0);
815 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
816 *max_set = MAX (*max_set, pos);
821 case MONO_TYPE_VALUETYPE: {
822 MonoClass *fclass = mono_class_from_mono_type (field->type);
823 if (fclass->has_references) {
824 /* remove the object header */
825 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
839 case MONO_TYPE_BOOLEAN:
843 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
854 * mono_class_compute_bitmap:
856 * Mono internal function to compute a bitmap of reference fields in a class.
859 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
861 MONO_REQ_GC_NEUTRAL_MODE;
863 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
868 * similar to the above, but sets the bits in the bitmap for any non-ref field
869 * and ignores static fields
872 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
874 MonoClassField *field;
879 max_size = class->instance_size / sizeof (gpointer);
880 if (max_size >= size) {
881 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
884 for (p = class; p != NULL; p = p->parent) {
885 gpointer iter = NULL;
886 while ((field = mono_class_get_fields (p, &iter))) {
889 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
891 /* FIXME: should not happen, flag as type load error */
892 if (field->type->byref)
895 pos = field->offset / sizeof (gpointer);
898 type = mono_type_get_underlying_type (field->type);
899 switch (type->type) {
900 #if SIZEOF_VOID_P == 8
904 case MONO_TYPE_FNPTR:
909 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
914 #if SIZEOF_VOID_P == 4
918 case MONO_TYPE_FNPTR:
923 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
924 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
925 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
931 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
932 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
933 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
936 case MONO_TYPE_BOOLEAN:
939 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
941 case MONO_TYPE_STRING:
942 case MONO_TYPE_SZARRAY:
943 case MONO_TYPE_CLASS:
944 case MONO_TYPE_OBJECT:
945 case MONO_TYPE_ARRAY:
947 case MONO_TYPE_GENERICINST:
948 if (!mono_type_generic_inst_is_valuetype (type)) {
953 case MONO_TYPE_VALUETYPE: {
954 MonoClass *fclass = mono_class_from_mono_type (field->type);
955 /* remove the object header */
956 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
960 g_assert_not_reached ();
969 * mono_class_insecure_overlapping:
970 * check if a class with explicit layout has references and non-references
971 * fields overlapping.
973 * Returns: TRUE if it is insecure to load the type.
976 mono_class_insecure_overlapping (MonoClass *klass)
980 gsize default_bitmap [4] = {0};
982 gsize default_nrbitmap [4] = {0};
983 int i, insecure = FALSE;
986 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
987 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
989 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
990 int idx = i % (sizeof (bitmap [0]) * 8);
991 if (bitmap [idx] & nrbitmap [idx]) {
996 if (bitmap != default_bitmap)
998 if (nrbitmap != default_nrbitmap)
1001 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1009 ves_icall_string_alloc (int length)
1012 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1013 mono_error_set_pending_exception (&error);
1018 /* LOCKING: Acquires the loader lock */
1020 mono_class_compute_gc_descriptor (MonoClass *klass)
1022 MONO_REQ_GC_NEUTRAL_MODE;
1026 gsize default_bitmap [4] = {0};
1027 static gboolean gcj_inited = FALSE;
1028 MonoGCDescriptor gc_descr;
1031 mono_loader_lock ();
1033 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1034 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1037 mono_loader_unlock ();
1041 mono_class_init (klass);
1043 if (klass->gc_descr_inited)
1046 bitmap = default_bitmap;
1047 if (klass == mono_defaults.string_class) {
1048 gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1049 } else if (klass->rank) {
1050 mono_class_compute_gc_descriptor (klass->element_class);
1051 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1053 gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1054 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1055 class->name_space, class->name);*/
1057 /* remove the object header */
1058 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1059 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));
1060 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1061 class->name_space, class->name);*/
1062 if (bitmap != default_bitmap)
1066 /*static int count = 0;
1069 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1070 gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1072 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1073 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1075 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1076 if (bitmap != default_bitmap)
1080 /* Publish the data */
1081 mono_loader_lock ();
1082 klass->gc_descr = gc_descr;
1083 mono_memory_barrier ();
1084 klass->gc_descr_inited = TRUE;
1085 mono_loader_unlock ();
1089 * field_is_special_static:
1090 * @fklass: The MonoClass to look up.
1091 * @field: The MonoClassField describing the field.
1093 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1094 * SPECIAL_STATIC_NONE otherwise.
1097 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1099 MONO_REQ_GC_NEUTRAL_MODE;
1102 MonoCustomAttrInfo *ainfo;
1104 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1105 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1108 for (i = 0; i < ainfo->num_attrs; ++i) {
1109 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1110 if (klass->image == mono_defaults.corlib) {
1111 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1112 mono_custom_attrs_free (ainfo);
1113 return SPECIAL_STATIC_THREAD;
1115 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1116 mono_custom_attrs_free (ainfo);
1117 return SPECIAL_STATIC_CONTEXT;
1121 mono_custom_attrs_free (ainfo);
1122 return SPECIAL_STATIC_NONE;
1125 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1126 #define mix(a,b,c) { \
1127 a -= c; a ^= rot(c, 4); c += b; \
1128 b -= a; b ^= rot(a, 6); a += c; \
1129 c -= b; c ^= rot(b, 8); b += a; \
1130 a -= c; a ^= rot(c,16); c += b; \
1131 b -= a; b ^= rot(a,19); a += c; \
1132 c -= b; c ^= rot(b, 4); b += a; \
1134 #define final(a,b,c) { \
1135 c ^= b; c -= rot(b,14); \
1136 a ^= c; a -= rot(c,11); \
1137 b ^= a; b -= rot(a,25); \
1138 c ^= b; c -= rot(b,16); \
1139 a ^= c; a -= rot(c,4); \
1140 b ^= a; b -= rot(a,14); \
1141 c ^= b; c -= rot(b,24); \
1145 * mono_method_get_imt_slot:
1147 * The IMT slot is embedded into AOTed code, so this must return the same value
1148 * for the same method across all executions. This means:
1149 * - pointers shouldn't be used as hash values.
1150 * - mono_metadata_str_hash () should be used for hashing strings.
1153 mono_method_get_imt_slot (MonoMethod *method)
1155 MONO_REQ_GC_NEUTRAL_MODE;
1157 MonoMethodSignature *sig;
1159 guint32 *hashes_start, *hashes;
1163 /* This can be used to stress tests the collision code */
1167 * We do this to simplify generic sharing. It will hurt
1168 * performance in cases where a class implements two different
1169 * instantiations of the same generic interface.
1170 * The code in build_imt_slots () depends on this.
1172 if (method->is_inflated)
1173 method = ((MonoMethodInflated*)method)->declaring;
1175 sig = mono_method_signature (method);
1176 hashes_count = sig->param_count + 4;
1177 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1178 hashes = hashes_start;
1180 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1181 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1182 method->klass->name_space, method->klass->name, method->name);
1185 /* Initialize hashes */
1186 hashes [0] = mono_metadata_str_hash (method->klass->name);
1187 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1188 hashes [2] = mono_metadata_str_hash (method->name);
1189 hashes [3] = mono_metadata_type_hash (sig->ret);
1190 for (i = 0; i < sig->param_count; i++) {
1191 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1194 /* Setup internal state */
1195 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1197 /* Handle most of the hashes */
1198 while (hashes_count > 3) {
1207 /* Handle the last 3 hashes (all the case statements fall through) */
1208 switch (hashes_count) {
1209 case 3 : c += hashes [2];
1210 case 2 : b += hashes [1];
1211 case 1 : a += hashes [0];
1213 case 0: /* nothing left to add */
1217 g_free (hashes_start);
1218 /* Report the result */
1219 return c % MONO_IMT_SIZE;
1228 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1229 MONO_REQ_GC_NEUTRAL_MODE;
1231 guint32 imt_slot = mono_method_get_imt_slot (method);
1232 MonoImtBuilderEntry *entry;
1234 if (slot_num >= 0 && imt_slot != slot_num) {
1235 /* we build just a single imt slot and this is not it */
1239 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1240 entry->key = method;
1241 entry->value.vtable_slot = vtable_slot;
1242 entry->next = imt_builder [imt_slot];
1243 if (imt_builder [imt_slot] != NULL) {
1244 entry->children = imt_builder [imt_slot]->children + 1;
1245 if (entry->children == 1) {
1246 mono_stats.imt_slots_with_collisions++;
1247 *imt_collisions_bitmap |= (1 << imt_slot);
1250 entry->children = 0;
1251 mono_stats.imt_used_slots++;
1253 imt_builder [imt_slot] = entry;
1256 char *method_name = mono_method_full_name (method, TRUE);
1257 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1258 method, method_name, imt_slot, vtable_slot, entry->children);
1259 g_free (method_name);
1266 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1268 MonoMethod *method = e->key;
1269 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1273 method->klass->name_space,
1274 method->klass->name,
1277 printf (" * %s: NULL\n", message);
1283 compare_imt_builder_entries (const void *p1, const void *p2) {
1284 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1285 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1287 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1291 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1293 MONO_REQ_GC_NEUTRAL_MODE;
1295 int count = end - start;
1296 int chunk_start = out_array->len;
1299 for (i = start; i < end; ++i) {
1300 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1301 item->key = sorted_array [i]->key;
1302 item->value = sorted_array [i]->value;
1303 item->has_target_code = sorted_array [i]->has_target_code;
1304 item->is_equals = TRUE;
1306 item->check_target_idx = out_array->len + 1;
1308 item->check_target_idx = 0;
1309 g_ptr_array_add (out_array, item);
1312 int middle = start + count / 2;
1313 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1315 item->key = sorted_array [middle]->key;
1316 item->is_equals = FALSE;
1317 g_ptr_array_add (out_array, item);
1318 imt_emit_ir (sorted_array, start, middle, out_array);
1319 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1325 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1326 MONO_REQ_GC_NEUTRAL_MODE;
1328 int number_of_entries = entries->children + 1;
1329 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1330 GPtrArray *result = g_ptr_array_new ();
1331 MonoImtBuilderEntry *current_entry;
1334 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1335 sorted_array [i] = current_entry;
1337 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1339 /*for (i = 0; i < number_of_entries; i++) {
1340 print_imt_entry (" sorted array:", sorted_array [i], i);
1343 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1345 g_free (sorted_array);
1350 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1352 MONO_REQ_GC_NEUTRAL_MODE;
1354 if (imt_builder_entry != NULL) {
1355 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1356 /* No collision, return the vtable slot contents */
1357 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1359 /* Collision, build the trampoline */
1360 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1363 result = imt_trampoline_builder (vtable, domain,
1364 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1365 for (i = 0; i < imt_ir->len; ++i)
1366 g_free (g_ptr_array_index (imt_ir, i));
1367 g_ptr_array_free (imt_ir, TRUE);
1379 static MonoImtBuilderEntry*
1380 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1383 * LOCKING: requires the loader and domain locks.
1387 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1389 MONO_REQ_GC_NEUTRAL_MODE;
1393 guint32 imt_collisions_bitmap = 0;
1394 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1395 int method_count = 0;
1396 gboolean record_method_count_for_max_collisions = FALSE;
1397 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1400 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1402 for (i = 0; i < klass->interface_offsets_count; ++i) {
1403 MonoClass *iface = klass->interfaces_packed [i];
1404 int interface_offset = klass->interface_offsets_packed [i];
1405 int method_slot_in_interface, vt_slot;
1407 if (mono_class_has_variant_generic_params (iface))
1408 has_variant_iface = TRUE;
1410 mono_class_setup_methods (iface);
1411 vt_slot = interface_offset;
1412 int mcount = mono_class_get_method_count (iface);
1413 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1416 if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1418 * The imt slot of the method is the same as for its declaring method,
1419 * see the comment in mono_method_get_imt_slot (), so we can
1420 * avoid inflating methods which will be discarded by
1421 * add_imt_builder_entry anyway.
1423 method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1424 if (mono_method_get_imt_slot (method) != slot_num) {
1429 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1430 if (method->is_generic) {
1431 has_generic_virtual = TRUE;
1436 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1437 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1442 if (extra_interfaces) {
1443 int interface_offset = klass->vtable_size;
1445 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1446 MonoClass* iface = (MonoClass *)list_item->data;
1447 int method_slot_in_interface;
1448 int mcount = mono_class_get_method_count (iface);
1449 for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1450 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1452 if (method->is_generic)
1453 has_generic_virtual = TRUE;
1454 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1456 interface_offset += mcount;
1459 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1460 /* overwrite the imt slot only if we're building all the entries or if
1461 * we're building this specific one
1463 if (slot_num < 0 || i == slot_num) {
1464 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1467 if (imt_builder [i]) {
1468 MonoImtBuilderEntry *entry;
1470 /* Link entries with imt_builder [i] */
1471 for (entry = entries; entry->next; entry = entry->next) {
1473 MonoMethod *method = (MonoMethod*)entry->key;
1474 char *method_name = mono_method_full_name (method, TRUE);
1475 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1476 g_free (method_name);
1479 entry->next = imt_builder [i];
1480 entries->children += imt_builder [i]->children + 1;
1482 imt_builder [i] = entries;
1485 if (has_generic_virtual || has_variant_iface) {
1487 * There might be collisions later when the the trampoline is expanded.
1489 imt_collisions_bitmap |= (1 << i);
1492 * The IMT trampoline might be called with an instance of one of the
1493 * generic virtual methods, so has to fallback to the IMT trampoline.
1495 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1497 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1500 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1504 if (imt_builder [i] != NULL) {
1505 int methods_in_slot = imt_builder [i]->children + 1;
1506 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1507 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1508 record_method_count_for_max_collisions = TRUE;
1510 method_count += methods_in_slot;
1514 mono_stats.imt_number_of_methods += method_count;
1515 if (record_method_count_for_max_collisions) {
1516 mono_stats.imt_method_count_when_max_collisions = method_count;
1519 for (i = 0; i < MONO_IMT_SIZE; i++) {
1520 MonoImtBuilderEntry* entry = imt_builder [i];
1521 while (entry != NULL) {
1522 MonoImtBuilderEntry* next = entry->next;
1527 g_free (imt_builder);
1528 /* we OR the bitmap since we may build just a single imt slot at a time */
1529 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1533 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1534 MONO_REQ_GC_NEUTRAL_MODE;
1536 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1540 * mono_vtable_build_imt_slot:
1541 * @vtable: virtual object table struct
1542 * @imt_slot: slot in the IMT table
1544 * Fill the given @imt_slot in the IMT table of @vtable with
1545 * a trampoline or a trampoline for the case of collisions.
1546 * This is part of the internal mono API.
1548 * LOCKING: Take the domain lock.
1551 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1553 MONO_REQ_GC_NEUTRAL_MODE;
1555 gpointer *imt = (gpointer*)vtable;
1556 imt -= MONO_IMT_SIZE;
1557 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1559 /* no support for extra interfaces: the proxy objects will need
1560 * to build the complete IMT
1561 * Update and heck needs to ahppen inside the proper domain lock, as all
1562 * the changes made to a MonoVTable.
1564 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1565 mono_domain_lock (vtable->domain);
1566 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1567 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1568 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1569 mono_domain_unlock (vtable->domain);
1570 mono_loader_unlock ();
1573 #define THUNK_THRESHOLD 10
1576 * mono_method_alloc_generic_virtual_trampoline:
1578 * @size: size in bytes
1580 * Allocs size bytes to be used for the code of a generic virtual
1581 * trampoline. It's either allocated from the domain's code manager or
1582 * reused from a previously invalidated piece.
1584 * LOCKING: The domain lock must be held.
1587 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1589 MONO_REQ_GC_NEUTRAL_MODE;
1591 static gboolean inited = FALSE;
1592 static int generic_virtual_trampolines_size = 0;
1595 mono_counters_register ("Generic virtual trampoline bytes",
1596 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1599 generic_virtual_trampolines_size += size;
1601 return mono_domain_code_reserve (domain, size);
1604 typedef struct _GenericVirtualCase {
1608 struct _GenericVirtualCase *next;
1609 } GenericVirtualCase;
1612 * get_generic_virtual_entries:
1614 * Return IMT entries for the generic virtual method instances and
1615 * variant interface methods for vtable slot
1618 static MonoImtBuilderEntry*
1619 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1621 MONO_REQ_GC_NEUTRAL_MODE;
1623 GenericVirtualCase *list;
1624 MonoImtBuilderEntry *entries;
1626 mono_domain_lock (domain);
1627 if (!domain->generic_virtual_cases)
1628 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1630 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1633 for (; list; list = list->next) {
1634 MonoImtBuilderEntry *entry;
1636 if (list->count < THUNK_THRESHOLD)
1639 entry = g_new0 (MonoImtBuilderEntry, 1);
1640 entry->key = list->method;
1641 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1642 entry->has_target_code = 1;
1644 entry->children = entries->children + 1;
1645 entry->next = entries;
1649 mono_domain_unlock (domain);
1651 /* FIXME: Leaking memory ? */
1656 * mono_method_add_generic_virtual_invocation:
1658 * @vtable_slot: pointer to the vtable slot
1659 * @method: the inflated generic virtual method
1660 * @code: the method's code
1662 * Registers a call via unmanaged code to a generic virtual method
1663 * instantiation or variant interface method. If the number of calls reaches a threshold
1664 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1665 * virtual method trampoline.
1668 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1669 gpointer *vtable_slot,
1670 MonoMethod *method, gpointer code)
1672 MONO_REQ_GC_NEUTRAL_MODE;
1674 static gboolean inited = FALSE;
1675 static int num_added = 0;
1676 static int num_freed = 0;
1678 GenericVirtualCase *gvc, *list;
1679 MonoImtBuilderEntry *entries;
1683 mono_domain_lock (domain);
1684 if (!domain->generic_virtual_cases)
1685 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1688 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1689 mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1693 /* Check whether the case was already added */
1694 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1697 if (gvc->method == method)
1702 /* If not found, make a new one */
1704 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1705 gvc->method = method;
1708 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1710 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1715 if (++gvc->count == THUNK_THRESHOLD) {
1716 gpointer *old_thunk = (void **)*vtable_slot;
1717 gpointer vtable_trampoline = NULL;
1718 gpointer imt_trampoline = NULL;
1720 if ((gpointer)vtable_slot < (gpointer)vtable) {
1721 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1722 int imt_slot = MONO_IMT_SIZE + displacement;
1724 /* Force the rebuild of the trampoline at the next call */
1725 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1726 *vtable_slot = imt_trampoline;
1728 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1730 entries = get_generic_virtual_entries (domain, vtable_slot);
1732 sorted = imt_sort_slot_entries (entries);
1734 *vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1738 MonoImtBuilderEntry *next = entries->next;
1743 for (i = 0; i < sorted->len; ++i)
1744 g_free (g_ptr_array_index (sorted, i));
1745 g_ptr_array_free (sorted, TRUE);
1747 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1752 mono_domain_unlock (domain);
1755 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1758 * mono_class_vtable:
1759 * @domain: the application domain
1760 * @class: the class to initialize
1762 * VTables are domain specific because we create domain specific code, and
1763 * they contain the domain specific static class data.
1764 * On failure, NULL is returned, and class->exception_type is set.
1767 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1770 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1771 mono_error_cleanup (&error);
1776 * mono_class_vtable_full:
1777 * @domain: the application domain
1778 * @class: the class to initialize
1779 * @error set on failure.
1781 * VTables are domain specific because we create domain specific code, and
1782 * they contain the domain specific static class data.
1785 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1787 MONO_REQ_GC_UNSAFE_MODE;
1789 MonoClassRuntimeInfo *runtime_info;
1791 mono_error_init (error);
1795 if (mono_class_has_failure (klass)) {
1796 mono_error_set_for_class_failure (error, klass);
1800 /* this check can be inlined in jitted code, too */
1801 runtime_info = klass->runtime_info;
1802 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1803 return runtime_info->domain_vtables [domain->domain_id];
1804 return mono_class_create_runtime_vtable (domain, klass, error);
1808 * mono_class_try_get_vtable:
1809 * @domain: the application domain
1810 * @class: the class to initialize
1812 * This function tries to get the associated vtable from @class if
1813 * it was already created.
1816 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1818 MONO_REQ_GC_NEUTRAL_MODE;
1820 MonoClassRuntimeInfo *runtime_info;
1824 runtime_info = klass->runtime_info;
1825 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1826 return runtime_info->domain_vtables [domain->domain_id];
1831 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1833 MONO_REQ_GC_NEUTRAL_MODE;
1835 size_t alloc_offset;
1838 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1839 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1840 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1842 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1843 g_assert ((imt_table_bytes & 7) == 4);
1850 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1854 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1856 MONO_REQ_GC_UNSAFE_MODE;
1859 MonoClassRuntimeInfo *runtime_info, *old_info;
1860 MonoClassField *field;
1862 int i, vtable_slots;
1863 size_t imt_table_bytes;
1865 guint32 vtable_size, class_size;
1867 gpointer *interface_offsets;
1869 mono_error_init (error);
1871 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1872 mono_domain_lock (domain);
1873 runtime_info = klass->runtime_info;
1874 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1875 mono_domain_unlock (domain);
1876 mono_loader_unlock ();
1877 return runtime_info->domain_vtables [domain->domain_id];
1879 if (!klass->inited || mono_class_has_failure (klass)) {
1880 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1881 mono_domain_unlock (domain);
1882 mono_loader_unlock ();
1883 mono_error_set_for_class_failure (error, klass);
1888 /* Array types require that their element type be valid*/
1889 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1890 MonoClass *element_class = klass->element_class;
1891 if (!element_class->inited)
1892 mono_class_init (element_class);
1894 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1895 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1896 mono_class_setup_vtable (element_class);
1898 if (mono_class_has_failure (element_class)) {
1899 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1900 if (!mono_class_has_failure (klass))
1901 mono_class_set_type_load_failure (klass, "");
1902 mono_domain_unlock (domain);
1903 mono_loader_unlock ();
1904 mono_error_set_for_class_failure (error, klass);
1910 * For some classes, mono_class_init () already computed klass->vtable_size, and
1911 * that is all that is needed because of the vtable trampolines.
1913 if (!klass->vtable_size)
1914 mono_class_setup_vtable (klass);
1916 if (mono_class_is_ginst (klass) && !klass->vtable)
1917 mono_class_check_vtable_constraints (klass, NULL);
1919 /* Initialize klass->has_finalize */
1920 mono_class_has_finalizer (klass);
1922 if (mono_class_has_failure (klass)) {
1923 mono_domain_unlock (domain);
1924 mono_loader_unlock ();
1925 mono_error_set_for_class_failure (error, klass);
1929 vtable_slots = klass->vtable_size;
1930 /* we add an additional vtable slot to store the pointer to static field data only when needed */
1931 class_size = mono_class_data_size (klass);
1935 if (klass->interface_offsets_count) {
1936 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1937 mono_stats.imt_number_of_tables++;
1938 mono_stats.imt_tables_size += imt_table_bytes;
1940 imt_table_bytes = 0;
1943 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1945 mono_stats.used_class_count++;
1946 mono_stats.class_vtable_size += vtable_size;
1948 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1949 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1950 g_assert (!((gsize)vt & 7));
1953 vt->rank = klass->rank;
1954 vt->domain = domain;
1956 mono_class_compute_gc_descriptor (klass);
1958 * We can't use typed allocation in the non-root domains, since the
1959 * collector needs the GC descriptor stored in the vtable even after
1960 * the mempool containing the vtable is destroyed when the domain is
1961 * unloaded. An alternative might be to allocate vtables in the GC
1962 * heap, but this does not seem to work (it leads to crashes inside
1963 * libgc). If that approach is tried, two gc descriptors need to be
1964 * allocated for each class: one for the root domain, and one for all
1965 * other domains. The second descriptor should contain a bit for the
1966 * vtable field in MonoObject, since we can no longer assume the
1967 * vtable is reachable by other roots after the appdomain is unloaded.
1969 #ifdef HAVE_BOEHM_GC
1970 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
1971 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1974 vt->gc_descr = klass->gc_descr;
1976 gc_bits = mono_gc_get_vtable_bits (klass);
1977 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1979 vt->gc_bits = gc_bits;
1982 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1983 if (klass->has_static_refs) {
1984 MonoGCDescriptor statics_gc_descr;
1986 gsize default_bitmap [4] = {0};
1989 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1990 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
1991 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
1992 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
1993 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
1994 if (bitmap != default_bitmap)
1997 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
1999 vt->has_static_fields = TRUE;
2000 mono_stats.class_static_data_size += class_size;
2004 while ((field = mono_class_get_fields (klass, &iter))) {
2005 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2007 if (mono_field_is_deleted (field))
2009 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2010 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2011 if (special_static != SPECIAL_STATIC_NONE) {
2012 guint32 size, offset;
2014 gsize default_bitmap [4] = {0};
2019 if (mono_type_is_reference (field->type)) {
2020 default_bitmap [0] = 1;
2022 bitmap = default_bitmap;
2023 } else if (mono_type_is_struct (field->type)) {
2024 fclass = mono_class_from_mono_type (field->type);
2025 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2026 numbits = max_set + 1;
2028 default_bitmap [0] = 0;
2030 bitmap = default_bitmap;
2032 size = mono_type_size (field->type, &align);
2033 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2034 if (!domain->special_static_fields)
2035 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2036 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2037 if (bitmap != default_bitmap)
2040 * This marks the field as special static to speed up the
2041 * checks in mono_field_static_get/set_value ().
2047 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2048 MonoClass *fklass = mono_class_from_mono_type (field->type);
2049 const char *data = mono_field_get_data (field);
2051 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2052 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2053 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2056 if (fklass->valuetype) {
2057 memcpy (t, data, mono_class_value_size (fklass, NULL));
2059 /* it's a pointer type: add check */
2060 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2067 vt->max_interface_id = klass->max_interface_id;
2068 vt->interface_bitmap = klass->interface_bitmap;
2070 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2071 // class->name, klass->interface_offsets_count);
2073 /* Initialize vtable */
2074 if (callbacks.get_vtable_trampoline) {
2075 // This also covers the AOT case
2076 for (i = 0; i < klass->vtable_size; ++i) {
2077 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2080 mono_class_setup_vtable (klass);
2082 for (i = 0; i < klass->vtable_size; ++i) {
2085 cm = klass->vtable [i];
2087 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2088 if (!is_ok (error)) {
2089 mono_domain_unlock (domain);
2090 mono_loader_unlock ();
2097 if (imt_table_bytes) {
2098 /* Now that the vtable is full, we can actually fill up the IMT */
2099 for (i = 0; i < MONO_IMT_SIZE; ++i)
2100 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2104 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2105 * re-acquire them and check if another thread has created the vtable in the meantime.
2107 /* Special case System.MonoType to avoid infinite recursion */
2108 if (klass != mono_defaults.runtimetype_class) {
2109 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2110 if (!is_ok (error)) {
2111 mono_domain_unlock (domain);
2112 mono_loader_unlock ();
2116 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2117 /* This is unregistered in
2118 unregister_vtable_reflection_type() in
2120 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2123 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2125 /* class_vtable_array keeps an array of created vtables
2127 g_ptr_array_add (domain->class_vtable_array, vt);
2128 /* klass->runtime_info is protected by the loader lock, both when
2129 * it it enlarged and when it is stored info.
2133 * Store the vtable in klass->runtime_info.
2134 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2136 mono_memory_barrier ();
2138 old_info = klass->runtime_info;
2139 if (old_info && old_info->max_domain >= domain->domain_id) {
2140 /* someone already created a large enough runtime info */
2141 old_info->domain_vtables [domain->domain_id] = vt;
2143 int new_size = domain->domain_id;
2145 new_size = MAX (new_size, old_info->max_domain);
2147 /* make the new size a power of two */
2149 while (new_size > i)
2152 /* this is a bounded memory retention issue: may want to
2153 * handle it differently when we'll have a rcu-like system.
2155 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2156 runtime_info->max_domain = new_size - 1;
2157 /* copy the stuff from the older info */
2159 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2161 runtime_info->domain_vtables [domain->domain_id] = vt;
2163 mono_memory_barrier ();
2164 klass->runtime_info = runtime_info;
2167 if (klass == mono_defaults.runtimetype_class) {
2168 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2169 if (!is_ok (error)) {
2170 mono_domain_unlock (domain);
2171 mono_loader_unlock ();
2175 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2176 /* This is unregistered in
2177 unregister_vtable_reflection_type() in
2179 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2182 mono_domain_unlock (domain);
2183 mono_loader_unlock ();
2185 /* make sure the parent is initialized */
2186 /*FIXME shouldn't this fail the current type?*/
2188 mono_class_vtable_full (domain, klass->parent, error);
2193 #ifndef DISABLE_REMOTING
2195 * mono_class_proxy_vtable:
2196 * @domain: the application domain
2197 * @remove_class: the remote class
2198 * @error: set on error
2200 * Creates a vtable for transparent proxies. It is basically
2201 * a copy of the real vtable of the class wrapped in @remote_class,
2202 * but all function pointers invoke the remoting functions, and
2203 * vtable->klass points to the transparent proxy class, and not to @class.
2205 * On failure returns NULL and sets @error
2208 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2210 MONO_REQ_GC_UNSAFE_MODE;
2212 MonoVTable *vt, *pvt;
2213 int i, j, vtsize, extra_interface_vtsize = 0;
2214 guint32 max_interface_id;
2216 GSList *extra_interfaces = NULL;
2217 MonoClass *klass = remote_class->proxy_class;
2218 gpointer *interface_offsets;
2219 uint8_t *bitmap = NULL;
2221 size_t imt_table_bytes;
2223 #ifdef COMPRESSED_INTERFACE_BITMAP
2227 mono_error_init (error);
2229 vt = mono_class_vtable (domain, klass);
2230 g_assert (vt); /*FIXME property handle failure*/
2231 max_interface_id = vt->max_interface_id;
2233 /* Calculate vtable space for extra interfaces */
2234 for (j = 0; j < remote_class->interface_count; j++) {
2235 MonoClass* iclass = remote_class->interfaces[j];
2239 /*FIXME test for interfaces with variant generic arguments*/
2240 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2241 continue; /* interface implemented by the class */
2242 if (g_slist_find (extra_interfaces, iclass))
2245 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2247 method_count = mono_class_num_methods (iclass);
2249 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2253 for (i = 0; i < ifaces->len; ++i) {
2254 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2255 /*FIXME test for interfaces with variant generic arguments*/
2256 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2257 continue; /* interface implemented by the class */
2258 if (g_slist_find (extra_interfaces, ic))
2260 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2261 method_count += mono_class_num_methods (ic);
2263 g_ptr_array_free (ifaces, TRUE);
2267 extra_interface_vtsize += method_count * sizeof (gpointer);
2268 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2271 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2272 mono_stats.imt_number_of_tables++;
2273 mono_stats.imt_tables_size += imt_table_bytes;
2275 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2277 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2279 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2280 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2281 g_assert (!((gsize)pvt & 7));
2283 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2285 pvt->klass = mono_defaults.transparent_proxy_class;
2286 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2287 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2289 /* initialize vtable */
2290 mono_class_setup_vtable (klass);
2291 for (i = 0; i < klass->vtable_size; ++i) {
2294 if ((cm = klass->vtable [i])) {
2295 pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2299 pvt->vtable [i] = NULL;
2302 if (mono_class_is_abstract (klass)) {
2303 /* create trampolines for abstract methods */
2304 for (k = klass; k; k = k->parent) {
2306 gpointer iter = NULL;
2307 while ((m = mono_class_get_methods (k, &iter)))
2308 if (!pvt->vtable [m->slot]) {
2309 pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2316 pvt->max_interface_id = max_interface_id;
2317 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2318 #ifdef COMPRESSED_INTERFACE_BITMAP
2319 bitmap = (uint8_t *)g_malloc0 (bsize);
2321 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2324 for (i = 0; i < klass->interface_offsets_count; ++i) {
2325 int interface_id = klass->interfaces_packed [i]->interface_id;
2326 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2329 if (extra_interfaces) {
2330 int slot = klass->vtable_size;
2336 /* Create trampolines for the methods of the interfaces */
2337 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2338 interf = (MonoClass *)list_item->data;
2340 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2344 while ((cm = mono_class_get_methods (interf, &iter))) {
2345 pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2350 slot += mono_class_num_methods (interf);
2354 /* Now that the vtable is full, we can actually fill up the IMT */
2355 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2356 if (extra_interfaces) {
2357 g_slist_free (extra_interfaces);
2360 #ifdef COMPRESSED_INTERFACE_BITMAP
2361 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2362 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2363 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2366 pvt->interface_bitmap = bitmap;
2370 if (extra_interfaces)
2371 g_slist_free (extra_interfaces);
2372 #ifdef COMPRESSED_INTERFACE_BITMAP
2378 #endif /* DISABLE_REMOTING */
2381 * mono_class_field_is_special_static:
2383 * Returns whether @field is a thread/context static field.
2386 mono_class_field_is_special_static (MonoClassField *field)
2388 MONO_REQ_GC_NEUTRAL_MODE
2390 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2392 if (mono_field_is_deleted (field))
2394 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2395 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2402 * mono_class_field_get_special_static_type:
2403 * @field: The MonoClassField describing the field.
2405 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2406 * SPECIAL_STATIC_NONE otherwise.
2409 mono_class_field_get_special_static_type (MonoClassField *field)
2411 MONO_REQ_GC_NEUTRAL_MODE
2413 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2414 return SPECIAL_STATIC_NONE;
2415 if (mono_field_is_deleted (field))
2416 return SPECIAL_STATIC_NONE;
2417 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2418 return field_is_special_static (field->parent, field);
2419 return SPECIAL_STATIC_NONE;
2423 * mono_class_has_special_static_fields:
2425 * Returns whenever @klass has any thread/context static fields.
2428 mono_class_has_special_static_fields (MonoClass *klass)
2430 MONO_REQ_GC_NEUTRAL_MODE
2432 MonoClassField *field;
2436 while ((field = mono_class_get_fields (klass, &iter))) {
2437 g_assert (field->parent == klass);
2438 if (mono_class_field_is_special_static (field))
2445 #ifndef DISABLE_REMOTING
2447 * create_remote_class_key:
2448 * Creates an array of pointers that can be used as a hash key for a remote class.
2449 * The first element of the array is the number of pointers.
2452 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2454 MONO_REQ_GC_NEUTRAL_MODE;
2459 if (remote_class == NULL) {
2460 if (mono_class_is_interface (extra_class)) {
2461 key = (void **)g_malloc (sizeof(gpointer) * 3);
2462 key [0] = GINT_TO_POINTER (2);
2463 key [1] = mono_defaults.marshalbyrefobject_class;
2464 key [2] = extra_class;
2466 key = (void **)g_malloc (sizeof(gpointer) * 2);
2467 key [0] = GINT_TO_POINTER (1);
2468 key [1] = extra_class;
2471 if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2472 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2473 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2474 key [1] = remote_class->proxy_class;
2476 // Keep the list of interfaces sorted
2477 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2478 if (extra_class && remote_class->interfaces [i] > extra_class) {
2479 key [j++] = extra_class;
2482 key [j] = remote_class->interfaces [i];
2485 key [j] = extra_class;
2487 // Replace the old class. The interface list is the same
2488 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2489 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2490 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2491 for (i = 0; i < remote_class->interface_count; i++)
2492 key [2 + i] = remote_class->interfaces [i];
2500 * copy_remote_class_key:
2502 * Make a copy of KEY in the domain and return the copy.
2505 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2507 MONO_REQ_GC_NEUTRAL_MODE
2509 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2510 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2512 memcpy (mp_key, key, key_size);
2518 * mono_remote_class:
2519 * @domain: the application domain
2520 * @class_name: name of the remote class
2521 * @error: set on error
2523 * Creates and initializes a MonoRemoteClass object for a remote type.
2525 * On failure returns NULL and sets @error
2528 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2530 MONO_REQ_GC_UNSAFE_MODE;
2532 MonoRemoteClass *rc;
2533 gpointer* key, *mp_key;
2536 mono_error_init (error);
2538 key = create_remote_class_key (NULL, proxy_class);
2540 mono_domain_lock (domain);
2541 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2545 mono_domain_unlock (domain);
2549 name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2550 if (!is_ok (error)) {
2552 mono_domain_unlock (domain);
2556 mp_key = copy_remote_class_key (domain, key);
2560 if (mono_class_is_interface (proxy_class)) {
2561 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2562 rc->interface_count = 1;
2563 rc->interfaces [0] = proxy_class;
2564 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2566 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2567 rc->interface_count = 0;
2568 rc->proxy_class = proxy_class;
2571 rc->default_vtable = NULL;
2572 rc->xdomain_vtable = NULL;
2573 rc->proxy_class_name = name;
2574 #ifndef DISABLE_PERFCOUNTERS
2575 mono_perfcounters->loader_bytes += mono_string_length (MONO_HANDLE_RAW (class_name)) + 1;
2578 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2580 mono_domain_unlock (domain);
2585 * clone_remote_class:
2586 * Creates a copy of the remote_class, adding the provided class or interface
2588 static MonoRemoteClass*
2589 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2591 MONO_REQ_GC_NEUTRAL_MODE;
2593 MonoRemoteClass *rc;
2594 gpointer* key, *mp_key;
2596 key = create_remote_class_key (remote_class, extra_class);
2597 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2603 mp_key = copy_remote_class_key (domain, key);
2607 if (mono_class_is_interface (extra_class)) {
2609 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2610 rc->proxy_class = remote_class->proxy_class;
2611 rc->interface_count = remote_class->interface_count + 1;
2613 // Keep the list of interfaces sorted, since the hash key of
2614 // the remote class depends on this
2615 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2616 if (remote_class->interfaces [i] > extra_class && i == j)
2617 rc->interfaces [j++] = extra_class;
2618 rc->interfaces [j] = remote_class->interfaces [i];
2621 rc->interfaces [j] = extra_class;
2623 // Replace the old class. The interface array is the same
2624 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2625 rc->proxy_class = extra_class;
2626 rc->interface_count = remote_class->interface_count;
2627 if (rc->interface_count > 0)
2628 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2631 rc->default_vtable = NULL;
2632 rc->xdomain_vtable = NULL;
2633 rc->proxy_class_name = remote_class->proxy_class_name;
2635 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2641 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2643 MONO_REQ_GC_UNSAFE_MODE;
2645 mono_error_init (error);
2647 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2648 mono_domain_lock (domain);
2649 gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2650 if (target_domain_id != -1) {
2651 if (remote_class->xdomain_vtable == NULL)
2652 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2653 mono_domain_unlock (domain);
2654 mono_loader_unlock ();
2655 return_val_if_nok (error, NULL);
2656 return remote_class->xdomain_vtable;
2658 if (remote_class->default_vtable == NULL) {
2659 MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2660 MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2662 MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2663 MonoClass *klass = mono_class_from_mono_type (type);
2665 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)))
2666 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2669 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2670 /* N.B. both branches of the if modify error */
2671 if (!is_ok (error)) {
2672 mono_domain_unlock (domain);
2673 mono_loader_unlock ();
2678 mono_domain_unlock (domain);
2679 mono_loader_unlock ();
2680 return remote_class->default_vtable;
2684 * mono_upgrade_remote_class:
2685 * @domain: the application domain
2686 * @tproxy: the proxy whose remote class has to be upgraded.
2687 * @klass: class to which the remote class can be casted.
2688 * @error: set on error
2690 * Updates the vtable of the remote class by adding the necessary method slots
2691 * and interface offsets so it can be safely casted to klass. klass can be a
2692 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2695 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2697 MONO_REQ_GC_UNSAFE_MODE;
2699 mono_error_init (error);
2701 MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2702 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2704 gboolean redo_vtable;
2705 if (mono_class_is_interface (klass)) {
2708 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2709 if (remote_class->interfaces [i] == klass)
2710 redo_vtable = FALSE;
2713 redo_vtable = (remote_class->proxy_class != klass);
2716 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2717 mono_domain_lock (domain);
2719 MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2720 MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2721 MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2722 MONO_HANDLE_GET (real_proxy, tproxy, rp);
2723 MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2729 mono_domain_unlock (domain);
2730 mono_loader_unlock ();
2731 return is_ok (error);
2733 #endif /* DISABLE_REMOTING */
2737 * mono_object_get_virtual_method:
2738 * @obj: object to operate on.
2741 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2742 * the instance of a callvirt of method.
2745 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2747 MONO_REQ_GC_UNSAFE_MODE;
2748 HANDLE_FUNCTION_ENTER ();
2750 MONO_HANDLE_DCL (MonoObject, obj);
2751 MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2752 mono_error_assert_ok (&error);
2753 HANDLE_FUNCTION_RETURN_VAL (result);
2757 * mono_object_get_virtual_method:
2758 * @obj: object to operate on.
2761 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2762 * the instance of a callvirt of method.
2765 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2767 mono_error_init (error);
2769 gboolean is_proxy = FALSE;
2770 MonoClass *klass = mono_handle_class (obj);
2771 if (mono_class_is_transparent_proxy (klass)) {
2772 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2773 klass = remote_class->proxy_class;
2776 return class_get_virtual_method (klass, method, is_proxy, error);
2780 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2782 mono_error_init (error);
2785 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2788 mono_class_setup_vtable (klass);
2789 MonoMethod **vtable = klass->vtable;
2791 if (method->slot == -1) {
2792 /* method->slot might not be set for instances of generic methods */
2793 if (method->is_inflated) {
2794 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2795 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2798 g_assert_not_reached ();
2802 MonoMethod *res = NULL;
2803 /* check method->slot is a valid index: perform isinstance? */
2804 if (method->slot != -1) {
2805 if (mono_class_is_interface (method->klass)) {
2807 gboolean variance_used = FALSE;
2808 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2809 g_assert (iface_offset > 0);
2810 res = vtable [iface_offset + method->slot];
2813 res = vtable [method->slot];
2817 #ifndef DISABLE_REMOTING
2819 /* It may be an interface, abstract class method or generic method */
2820 if (!res || mono_method_signature (res)->generic_param_count)
2823 /* generic methods demand invoke_with_check */
2824 if (mono_method_signature (res)->generic_param_count)
2825 res = mono_marshal_get_remoting_invoke_with_check (res);
2828 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2829 res = mono_cominterop_get_invoke (res);
2832 res = mono_marshal_get_remoting_invoke (res);
2837 if (method->is_inflated) {
2838 /* Have to inflate the result */
2839 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2847 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2849 MONO_REQ_GC_UNSAFE_MODE;
2851 MonoObject *result = NULL;
2853 g_assert (callbacks.runtime_invoke);
2855 mono_error_init (error);
2857 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2858 mono_profiler_method_start_invoke (method);
2860 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2862 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2863 mono_profiler_method_end_invoke (method);
2865 if (!mono_error_ok (error))
2872 * mono_runtime_invoke:
2873 * @method: method to invoke
2874 * @obJ: object instance
2875 * @params: arguments to the method
2876 * @exc: exception information.
2878 * Invokes the method represented by @method on the object @obj.
2880 * obj is the 'this' pointer, it should be NULL for static
2881 * methods, a MonoObject* for object instances and a pointer to
2882 * the value type for value types.
2884 * The params array contains the arguments to the method with the
2885 * same convention: MonoObject* pointers for object instances and
2886 * pointers to the value type otherwise.
2888 * From unmanaged code you'll usually use the
2889 * mono_runtime_invoke() variant.
2891 * Note that this function doesn't handle virtual methods for
2892 * you, it will exec the exact method you pass: we still need to
2893 * expose a function to lookup the derived class implementation
2894 * of a virtual method (there are examples of this in the code,
2897 * You can pass NULL as the exc argument if you don't want to
2898 * catch exceptions, otherwise, *exc will be set to the exception
2899 * thrown, if any. if an exception is thrown, you can't use the
2900 * MonoObject* result from the function.
2902 * If the method returns a value type, it is boxed in an object
2906 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2911 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2912 if (*exc == NULL && !mono_error_ok(&error)) {
2913 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2915 mono_error_cleanup (&error);
2917 res = mono_runtime_invoke_checked (method, obj, params, &error);
2918 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
2924 * mono_runtime_try_invoke:
2925 * @method: method to invoke
2926 * @obJ: object instance
2927 * @params: arguments to the method
2928 * @exc: exception information.
2929 * @error: set on error
2931 * Invokes the method represented by @method on the object @obj.
2933 * obj is the 'this' pointer, it should be NULL for static
2934 * methods, a MonoObject* for object instances and a pointer to
2935 * the value type for value types.
2937 * The params array contains the arguments to the method with the
2938 * same convention: MonoObject* pointers for object instances and
2939 * pointers to the value type otherwise.
2941 * From unmanaged code you'll usually use the
2942 * mono_runtime_invoke() variant.
2944 * Note that this function doesn't handle virtual methods for
2945 * you, it will exec the exact method you pass: we still need to
2946 * expose a function to lookup the derived class implementation
2947 * of a virtual method (there are examples of this in the code,
2950 * For this function, you must not pass NULL as the exc argument if
2951 * you don't want to catch exceptions, use
2952 * mono_runtime_invoke_checked(). If an exception is thrown, you
2953 * can't use the MonoObject* result from the function.
2955 * If this method cannot be invoked, @error will be set and @exc and
2956 * the return value must not be used.
2958 * If the method returns a value type, it is boxed in an object
2962 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2964 MONO_REQ_GC_UNSAFE_MODE;
2966 g_assert (exc != NULL);
2968 if (mono_runtime_get_no_exec ())
2969 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2971 return do_runtime_invoke (method, obj, params, exc, error);
2975 * mono_runtime_invoke_checked:
2976 * @method: method to invoke
2977 * @obJ: object instance
2978 * @params: arguments to the method
2979 * @error: set on error
2981 * Invokes the method represented by @method on the object @obj.
2983 * obj is the 'this' pointer, it should be NULL for static
2984 * methods, a MonoObject* for object instances and a pointer to
2985 * the value type for value types.
2987 * The params array contains the arguments to the method with the
2988 * same convention: MonoObject* pointers for object instances and
2989 * pointers to the value type otherwise.
2991 * From unmanaged code you'll usually use the
2992 * mono_runtime_invoke() variant.
2994 * Note that this function doesn't handle virtual methods for
2995 * you, it will exec the exact method you pass: we still need to
2996 * expose a function to lookup the derived class implementation
2997 * of a virtual method (there are examples of this in the code,
3000 * If an exception is thrown, you can't use the MonoObject* result
3001 * from the function.
3003 * If this method cannot be invoked, @error will be set. If the
3004 * method throws an exception (and we're in coop mode) the exception
3005 * will be set in @error.
3007 * If the method returns a value type, it is boxed in an object
3011 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3013 MONO_REQ_GC_UNSAFE_MODE;
3015 if (mono_runtime_get_no_exec ())
3016 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3018 return do_runtime_invoke (method, obj, params, NULL, error);
3022 * mono_method_get_unmanaged_thunk:
3023 * @method: method to generate a thunk for.
3025 * Returns an unmanaged->managed thunk that can be used to call
3026 * a managed method directly from C.
3028 * The thunk's C signature closely matches the managed signature:
3030 * C#: public bool Equals (object obj);
3031 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3032 * MonoObject*, MonoException**);
3034 * The 1st ("this") parameter must not be used with static methods:
3036 * C#: public static bool ReferenceEquals (object a, object b);
3037 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3040 * The last argument must be a non-null pointer of a MonoException* pointer.
3041 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3042 * exception has been thrown in managed code. Otherwise it will point
3043 * to the MonoException* caught by the thunk. In this case, the result of
3044 * the thunk is undefined:
3046 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3047 * MonoException *ex = NULL;
3048 * Equals func = mono_method_get_unmanaged_thunk (method);
3049 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3051 * // handle exception
3054 * The calling convention of the thunk matches the platform's default
3055 * convention. This means that under Windows, C declarations must
3056 * contain the __stdcall attribute:
3058 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3059 * MonoObject*, MonoException**);
3063 * Value type arguments and return values are treated as they were objects:
3065 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3066 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3068 * Arguments must be properly boxed upon trunk's invocation, while return
3069 * values must be unboxed.
3072 mono_method_get_unmanaged_thunk (MonoMethod *method)
3074 MONO_REQ_GC_NEUTRAL_MODE;
3075 MONO_REQ_API_ENTRYPOINT;
3080 g_assert (!mono_threads_is_coop_enabled ());
3082 MONO_ENTER_GC_UNSAFE;
3083 method = mono_marshal_get_thunk_invoke_wrapper (method);
3084 res = mono_compile_method_checked (method, &error);
3085 mono_error_cleanup (&error);
3086 MONO_EXIT_GC_UNSAFE;
3092 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3094 MONO_REQ_GC_UNSAFE_MODE;
3098 /* object fields cannot be byref, so we don't need a
3100 gpointer *p = (gpointer*)dest;
3107 case MONO_TYPE_BOOLEAN:
3109 case MONO_TYPE_U1: {
3110 guint8 *p = (guint8*)dest;
3111 *p = value ? *(guint8*)value : 0;
3116 case MONO_TYPE_CHAR: {
3117 guint16 *p = (guint16*)dest;
3118 *p = value ? *(guint16*)value : 0;
3121 #if SIZEOF_VOID_P == 4
3126 case MONO_TYPE_U4: {
3127 gint32 *p = (gint32*)dest;
3128 *p = value ? *(gint32*)value : 0;
3131 #if SIZEOF_VOID_P == 8
3136 case MONO_TYPE_U8: {
3137 gint64 *p = (gint64*)dest;
3138 *p = value ? *(gint64*)value : 0;
3141 case MONO_TYPE_R4: {
3142 float *p = (float*)dest;
3143 *p = value ? *(float*)value : 0;
3146 case MONO_TYPE_R8: {
3147 double *p = (double*)dest;
3148 *p = value ? *(double*)value : 0;
3151 case MONO_TYPE_STRING:
3152 case MONO_TYPE_SZARRAY:
3153 case MONO_TYPE_CLASS:
3154 case MONO_TYPE_OBJECT:
3155 case MONO_TYPE_ARRAY:
3156 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3158 case MONO_TYPE_FNPTR:
3159 case MONO_TYPE_PTR: {
3160 gpointer *p = (gpointer*)dest;
3161 *p = deref_pointer? *(gpointer*)value: value;
3164 case MONO_TYPE_VALUETYPE:
3165 /* note that 't' and 'type->type' can be different */
3166 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3167 t = mono_class_enum_basetype (type->data.klass)->type;
3170 MonoClass *klass = mono_class_from_mono_type (type);
3171 int size = mono_class_value_size (klass, NULL);
3173 mono_gc_bzero_atomic (dest, size);
3175 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3178 case MONO_TYPE_GENERICINST:
3179 t = type->data.generic_class->container_class->byval_arg.type;
3182 g_error ("got type %x", type->type);
3187 * mono_field_set_value:
3188 * @obj: Instance object
3189 * @field: MonoClassField describing the field to set
3190 * @value: The value to be set
3192 * Sets the value of the field described by @field in the object instance @obj
3193 * to the value passed in @value. This method should only be used for instance
3194 * fields. For static fields, use mono_field_static_set_value.
3196 * The value must be on the native format of the field type.
3199 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3201 MONO_REQ_GC_UNSAFE_MODE;
3205 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3207 dest = (char*)obj + field->offset;
3208 mono_copy_value (field->type, dest, value, FALSE);
3212 * mono_field_static_set_value:
3213 * @field: MonoClassField describing the field to set
3214 * @value: The value to be set
3216 * Sets the value of the static field described by @field
3217 * to the value passed in @value.
3219 * The value must be on the native format of the field type.
3222 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3224 MONO_REQ_GC_UNSAFE_MODE;
3228 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3229 /* you cant set a constant! */
3230 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3232 if (field->offset == -1) {
3233 /* Special static */
3236 mono_domain_lock (vt->domain);
3237 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3238 mono_domain_unlock (vt->domain);
3239 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3241 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3243 mono_copy_value (field->type, dest, value, FALSE);
3247 * mono_vtable_get_static_field_data:
3249 * Internal use function: return a pointer to the memory holding the static fields
3250 * for a class or NULL if there are no static fields.
3251 * This is exported only for use by the debugger.
3254 mono_vtable_get_static_field_data (MonoVTable *vt)
3256 MONO_REQ_GC_NEUTRAL_MODE
3258 if (!vt->has_static_fields)
3260 return vt->vtable [vt->klass->vtable_size];
3264 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3266 MONO_REQ_GC_UNSAFE_MODE;
3270 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3271 if (field->offset == -1) {
3272 /* Special static */
3275 mono_domain_lock (vt->domain);
3276 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3277 mono_domain_unlock (vt->domain);
3278 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3280 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3283 src = (guint8*)obj + field->offset;
3290 * mono_field_get_value:
3291 * @obj: Object instance
3292 * @field: MonoClassField describing the field to fetch information from
3293 * @value: pointer to the location where the value will be stored
3295 * Use this routine to get the value of the field @field in the object
3298 * The pointer provided by value must be of the field type, for reference
3299 * types this is a MonoObject*, for value types its the actual pointer to
3304 * mono_field_get_value (obj, int_field, &i);
3307 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3309 MONO_REQ_GC_UNSAFE_MODE;
3315 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3317 src = (char*)obj + field->offset;
3318 mono_copy_value (field->type, value, src, TRUE);
3322 * mono_field_get_value_object:
3323 * @domain: domain where the object will be created (if boxing)
3324 * @field: MonoClassField describing the field to fetch information from
3325 * @obj: The object instance for the field.
3327 * Returns: a new MonoObject with the value from the given field. If the
3328 * field represents a value type, the value is boxed.
3332 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3335 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3336 mono_error_assert_ok (&error);
3341 * mono_field_get_value_object_checked:
3342 * @domain: domain where the object will be created (if boxing)
3343 * @field: MonoClassField describing the field to fetch information from
3344 * @obj: The object instance for the field.
3345 * @error: Set on error.
3347 * Returns: a new MonoObject with the value from the given field. If the
3348 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3352 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3354 MONO_REQ_GC_UNSAFE_MODE;
3356 mono_error_init (error);
3360 MonoVTable *vtable = NULL;
3362 gboolean is_static = FALSE;
3363 gboolean is_ref = FALSE;
3364 gboolean is_literal = FALSE;
3365 gboolean is_ptr = FALSE;
3366 MonoType *type = mono_field_get_type_checked (field, error);
3368 return_val_if_nok (error, NULL);
3370 switch (type->type) {
3371 case MONO_TYPE_STRING:
3372 case MONO_TYPE_OBJECT:
3373 case MONO_TYPE_CLASS:
3374 case MONO_TYPE_ARRAY:
3375 case MONO_TYPE_SZARRAY:
3380 case MONO_TYPE_BOOLEAN:
3383 case MONO_TYPE_CHAR:
3392 case MONO_TYPE_VALUETYPE:
3393 is_ref = type->byref;
3395 case MONO_TYPE_GENERICINST:
3396 is_ref = !mono_type_generic_inst_is_valuetype (type);
3402 g_error ("type 0x%x not handled in "
3403 "mono_field_get_value_object", type->type);
3407 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3410 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3414 vtable = mono_class_vtable_full (domain, field->parent, error);
3415 return_val_if_nok (error, NULL);
3417 if (!vtable->initialized) {
3418 mono_runtime_class_init_full (vtable, error);
3419 return_val_if_nok (error, NULL);
3428 get_default_field_value (domain, field, &o, error);
3429 return_val_if_nok (error, NULL);
3430 } else if (is_static) {
3431 mono_field_static_get_value_checked (vtable, field, &o, error);
3432 return_val_if_nok (error, NULL);
3434 mono_field_get_value (obj, field, &o);
3440 static MonoMethod *m;
3446 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3447 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3453 get_default_field_value (domain, field, v, error);
3454 return_val_if_nok (error, NULL);
3455 } else if (is_static) {
3456 mono_field_static_get_value_checked (vtable, field, v, error);
3457 return_val_if_nok (error, NULL);
3459 mono_field_get_value (obj, field, v);
3462 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3463 args [0] = ptr ? *ptr : NULL;
3464 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3465 return_val_if_nok (error, NULL);
3467 o = mono_runtime_invoke_checked (m, NULL, args, error);
3468 return_val_if_nok (error, NULL);
3473 /* boxed value type */
3474 klass = mono_class_from_mono_type (type);
3476 if (mono_class_is_nullable (klass))
3477 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3479 o = mono_object_new_checked (domain, klass, error);
3480 return_val_if_nok (error, NULL);
3481 v = ((gchar *) o) + sizeof (MonoObject);
3484 get_default_field_value (domain, field, v, error);
3485 return_val_if_nok (error, NULL);
3486 } else if (is_static) {
3487 mono_field_static_get_value_checked (vtable, field, v, error);
3488 return_val_if_nok (error, NULL);
3490 mono_field_get_value (obj, field, v);
3497 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3499 MONO_REQ_GC_UNSAFE_MODE;
3501 mono_error_init (error);
3503 const char *p = blob;
3504 mono_metadata_decode_blob_size (p, &p);
3507 case MONO_TYPE_BOOLEAN:
3510 *(guint8 *) value = *p;
3512 case MONO_TYPE_CHAR:
3515 *(guint16*) value = read16 (p);
3519 *(guint32*) value = read32 (p);
3523 *(guint64*) value = read64 (p);
3526 readr4 (p, (float*) value);
3529 readr8 (p, (double*) value);
3531 case MONO_TYPE_STRING:
3532 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3534 case MONO_TYPE_CLASS:
3535 *(gpointer*) value = NULL;
3539 g_warning ("type 0x%02x should not be in constant table", type);
3545 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3547 MONO_REQ_GC_NEUTRAL_MODE;
3549 MonoTypeEnum def_type;
3552 mono_error_init (error);
3554 data = mono_class_get_field_default_value (field, &def_type);
3555 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3559 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3561 MONO_REQ_GC_UNSAFE_MODE;
3565 mono_error_init (error);
3567 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3569 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3570 get_default_field_value (vt->domain, field, value, error);
3574 if (field->offset == -1) {
3575 /* Special static */
3576 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3577 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3579 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3581 mono_copy_value (field->type, value, src, TRUE);
3585 * mono_field_static_get_value:
3586 * @vt: vtable to the object
3587 * @field: MonoClassField describing the field to fetch information from
3588 * @value: where the value is returned
3590 * Use this routine to get the value of the static field @field value.
3592 * The pointer provided by value must be of the field type, for reference
3593 * types this is a MonoObject*, for value types its the actual pointer to
3598 * mono_field_static_get_value (vt, int_field, &i);
3601 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3603 MONO_REQ_GC_NEUTRAL_MODE;
3606 mono_field_static_get_value_checked (vt, field, value, &error);
3607 mono_error_cleanup (&error);
3611 * mono_field_static_get_value_checked:
3612 * @vt: vtable to the object
3613 * @field: MonoClassField describing the field to fetch information from
3614 * @value: where the value is returned
3615 * @error: set on error
3617 * Use this routine to get the value of the static field @field value.
3619 * The pointer provided by value must be of the field type, for reference
3620 * types this is a MonoObject*, for value types its the actual pointer to
3625 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3626 * if (!is_ok (error)) { ... }
3628 * On failure sets @error.
3631 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3633 MONO_REQ_GC_NEUTRAL_MODE;
3635 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3639 * mono_property_set_value:
3640 * @prop: MonoProperty to set
3641 * @obj: instance object on which to act
3642 * @params: parameters to pass to the propery
3643 * @exc: optional exception
3645 * Invokes the property's set method with the given arguments on the
3646 * object instance obj (or NULL for static properties).
3648 * You can pass NULL as the exc argument if you don't want to
3649 * catch exceptions, otherwise, *exc will be set to the exception
3650 * thrown, if any. if an exception is thrown, you can't use the
3651 * MonoObject* result from the function.
3654 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3656 MONO_REQ_GC_UNSAFE_MODE;
3659 do_runtime_invoke (prop->set, obj, params, exc, &error);
3660 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3661 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3663 mono_error_cleanup (&error);
3668 * mono_property_set_value_checked:
3669 * @prop: MonoProperty to set
3670 * @obj: instance object on which to act
3671 * @params: parameters to pass to the propery
3672 * @error: set on error
3674 * Invokes the property's set method with the given arguments on the
3675 * object instance obj (or NULL for static properties).
3677 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3678 * If an exception is thrown, it will be caught and returned via @error.
3681 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3683 MONO_REQ_GC_UNSAFE_MODE;
3687 mono_error_init (error);
3688 do_runtime_invoke (prop->set, obj, params, &exc, error);
3689 if (exc != NULL && is_ok (error))
3690 mono_error_set_exception_instance (error, (MonoException*)exc);
3691 return is_ok (error);
3695 * mono_property_get_value:
3696 * @prop: MonoProperty to fetch
3697 * @obj: instance object on which to act
3698 * @params: parameters to pass to the propery
3699 * @exc: optional exception
3701 * Invokes the property's get method with the given arguments on the
3702 * object instance obj (or NULL for static properties).
3704 * You can pass NULL as the exc argument if you don't want to
3705 * catch exceptions, otherwise, *exc will be set to the exception
3706 * thrown, if any. if an exception is thrown, you can't use the
3707 * MonoObject* result from the function.
3709 * Returns: the value from invoking the get method on the property.
3712 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3714 MONO_REQ_GC_UNSAFE_MODE;
3717 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3718 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3719 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3721 mono_error_cleanup (&error); /* FIXME don't raise here */
3728 * mono_property_get_value_checked:
3729 * @prop: MonoProperty to fetch
3730 * @obj: instance object on which to act
3731 * @params: parameters to pass to the propery
3732 * @error: set on error
3734 * Invokes the property's get method with the given arguments on the
3735 * object instance obj (or NULL for static properties).
3737 * If an exception is thrown, you can't use the
3738 * MonoObject* result from the function. The exception will be propagated via @error.
3740 * Returns: the value from invoking the get method on the property. On
3741 * failure returns NULL and sets @error.
3744 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3746 MONO_REQ_GC_UNSAFE_MODE;
3749 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3750 if (exc != NULL && !is_ok (error))
3751 mono_error_set_exception_instance (error, (MonoException*) exc);
3759 * mono_nullable_init:
3760 * @buf: The nullable structure to initialize.
3761 * @value: the value to initialize from
3762 * @klass: the type for the object
3764 * Initialize the nullable structure pointed to by @buf from @value which
3765 * should be a boxed value type. The size of @buf should be able to hold
3766 * as much data as the @klass->instance_size (which is the number of bytes
3767 * that will be copies).
3769 * Since Nullables have variable structure, we can not define a C
3770 * structure for them.
3773 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3775 MONO_REQ_GC_UNSAFE_MODE;
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 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3787 if (param_class->has_references)
3788 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3790 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3792 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3797 * mono_nullable_box:
3798 * @buf: The buffer representing the data to be boxed
3799 * @klass: the type to box it as.
3800 * @error: set on oerr
3802 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3803 * @buf. On failure returns NULL and sets @error
3806 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3808 MONO_REQ_GC_UNSAFE_MODE;
3810 mono_error_init (error);
3811 MonoClass *param_class = klass->cast_class;
3813 mono_class_setup_fields (klass);
3814 g_assert (klass->fields_inited);
3816 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3817 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3819 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3820 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3821 return_val_if_nok (error, NULL);
3822 if (param_class->has_references)
3823 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3825 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3833 * mono_get_delegate_invoke:
3834 * @klass: The delegate class
3836 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3839 mono_get_delegate_invoke (MonoClass *klass)
3841 MONO_REQ_GC_NEUTRAL_MODE;
3845 /* This is called at runtime, so avoid the slower search in metadata */
3846 mono_class_setup_methods (klass);
3847 if (mono_class_has_failure (klass))
3849 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3854 * mono_get_delegate_begin_invoke:
3855 * @klass: The delegate class
3857 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3860 mono_get_delegate_begin_invoke (MonoClass *klass)
3862 MONO_REQ_GC_NEUTRAL_MODE;
3866 /* This is called at runtime, so avoid the slower search in metadata */
3867 mono_class_setup_methods (klass);
3868 if (mono_class_has_failure (klass))
3870 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3875 * mono_get_delegate_end_invoke:
3876 * @klass: The delegate class
3878 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3881 mono_get_delegate_end_invoke (MonoClass *klass)
3883 MONO_REQ_GC_NEUTRAL_MODE;
3887 /* This is called at runtime, so avoid the slower search in metadata */
3888 mono_class_setup_methods (klass);
3889 if (mono_class_has_failure (klass))
3891 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3896 * mono_runtime_delegate_invoke:
3897 * @delegate: pointer to a delegate object.
3898 * @params: parameters for the delegate.
3899 * @exc: Pointer to the exception result.
3901 * Invokes the delegate method @delegate with the parameters provided.
3903 * You can pass NULL as the exc argument if you don't want to
3904 * catch exceptions, otherwise, *exc will be set to the exception
3905 * thrown, if any. if an exception is thrown, you can't use the
3906 * MonoObject* result from the function.
3909 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3911 MONO_REQ_GC_UNSAFE_MODE;
3915 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3917 mono_error_cleanup (&error);
3920 if (!is_ok (&error))
3921 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
3925 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3926 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3932 * mono_runtime_delegate_try_invoke:
3933 * @delegate: pointer to a delegate object.
3934 * @params: parameters for the delegate.
3935 * @exc: Pointer to the exception result.
3936 * @error: set on error
3938 * Invokes the delegate method @delegate with the parameters provided.
3940 * You can pass NULL as the exc argument if you don't want to
3941 * catch exceptions, otherwise, *exc will be set to the exception
3942 * thrown, if any. On failure to execute, @error will be set.
3943 * if an exception is thrown, you can't use the
3944 * MonoObject* result from the function.
3947 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
3949 MONO_REQ_GC_UNSAFE_MODE;
3951 mono_error_init (error);
3953 MonoClass *klass = delegate->vtable->klass;
3956 im = mono_get_delegate_invoke (klass);
3958 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3961 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
3963 o = mono_runtime_invoke_checked (im, delegate, params, error);
3970 * mono_runtime_delegate_invoke_checked:
3971 * @delegate: pointer to a delegate object.
3972 * @params: parameters for the delegate.
3973 * @error: set on error
3975 * Invokes the delegate method @delegate with the parameters provided.
3977 * On failure @error will be set and you can't use the MonoObject*
3978 * result from the function.
3981 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
3983 mono_error_init (error);
3984 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
3987 static char **main_args = NULL;
3988 static int num_main_args = 0;
3991 * mono_runtime_get_main_args:
3993 * Returns: a MonoArray with the arguments passed to the main program
3996 mono_runtime_get_main_args (void)
3998 MONO_REQ_GC_UNSAFE_MODE;
4000 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4001 mono_error_assert_ok (&error);
4006 * mono_runtime_get_main_args:
4007 * @error: set on error
4009 * Returns: a MonoArray with the arguments passed to the main
4010 * program. On failure returns NULL and sets @error.
4013 mono_runtime_get_main_args_checked (MonoError *error)
4017 MonoDomain *domain = mono_domain_get ();
4019 mono_error_init (error);
4021 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4022 return_val_if_nok (error, NULL);
4024 for (i = 0; i < num_main_args; ++i)
4025 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4031 free_main_args (void)
4033 MONO_REQ_GC_NEUTRAL_MODE;
4037 for (i = 0; i < num_main_args; ++i)
4038 g_free (main_args [i]);
4045 * mono_runtime_set_main_args:
4046 * @argc: number of arguments from the command line
4047 * @argv: array of strings from the command line
4049 * Set the command line arguments from an embedding application that doesn't otherwise call
4050 * mono_runtime_run_main ().
4053 mono_runtime_set_main_args (int argc, char* argv[])
4055 MONO_REQ_GC_NEUTRAL_MODE;
4060 main_args = g_new0 (char*, argc);
4061 num_main_args = argc;
4063 for (i = 0; i < argc; ++i) {
4066 utf8_arg = mono_utf8_from_external (argv[i]);
4067 if (utf8_arg == NULL) {
4068 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4069 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4073 main_args [i] = utf8_arg;
4080 * Prepare an array of arguments in order to execute a standard Main()
4081 * method (argc/argv contains the executable name). This method also
4082 * sets the command line argument value needed by System.Environment.
4086 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4088 MONO_REQ_GC_UNSAFE_MODE;
4092 MonoArray *args = NULL;
4093 MonoDomain *domain = mono_domain_get ();
4094 gchar *utf8_fullpath;
4095 MonoMethodSignature *sig;
4097 g_assert (method != NULL);
4099 mono_thread_set_main (mono_thread_current ());
4101 main_args = g_new0 (char*, argc);
4102 num_main_args = argc;
4104 if (!g_path_is_absolute (argv [0])) {
4105 gchar *basename = g_path_get_basename (argv [0]);
4106 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4110 utf8_fullpath = mono_utf8_from_external (fullpath);
4111 if(utf8_fullpath == NULL) {
4112 /* Printing the arg text will cause glib to
4113 * whinge about "Invalid UTF-8", but at least
4114 * its relevant, and shows the problem text
4117 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4118 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4125 utf8_fullpath = mono_utf8_from_external (argv[0]);
4126 if(utf8_fullpath == NULL) {
4127 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4128 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4133 main_args [0] = utf8_fullpath;
4135 for (i = 1; i < argc; ++i) {
4138 utf8_arg=mono_utf8_from_external (argv[i]);
4139 if(utf8_arg==NULL) {
4140 /* Ditto the comment about Invalid UTF-8 here */
4141 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4142 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4146 main_args [i] = utf8_arg;
4151 sig = mono_method_signature (method);
4153 g_print ("Unable to load Main method.\n");
4157 if (sig->param_count) {
4158 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4159 mono_error_assert_ok (&error);
4160 for (i = 0; i < argc; ++i) {
4161 /* The encodings should all work, given that
4162 * we've checked all these args for the
4165 gchar *str = mono_utf8_from_external (argv [i]);
4166 MonoString *arg = mono_string_new (domain, str);
4167 mono_array_setref (args, i, arg);
4171 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4172 mono_error_assert_ok (&error);
4175 mono_assembly_set_main (method->klass->image->assembly);
4181 * mono_runtime_run_main:
4182 * @method: the method to start the application with (usually Main)
4183 * @argc: number of arguments from the command line
4184 * @argv: array of strings from the command line
4185 * @exc: excetption results
4187 * Execute a standard Main() method (argc/argv contains the
4188 * executable name). This method also sets the command line argument value
4189 * needed by System.Environment.
4194 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4197 MONO_REQ_GC_UNSAFE_MODE;
4200 MonoArray *args = prepare_run_main (method, argc, argv);
4203 res = mono_runtime_try_exec_main (method, args, exc);
4205 res = mono_runtime_exec_main_checked (method, args, &error);
4206 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4212 * mono_runtime_run_main_checked:
4213 * @method: the method to start the application with (usually Main)
4214 * @argc: number of arguments from the command line
4215 * @argv: array of strings from the command line
4216 * @error: set on error
4218 * Execute a standard Main() method (argc/argv contains the
4219 * executable name). This method also sets the command line argument value
4220 * needed by System.Environment. On failure sets @error.
4225 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4228 mono_error_init (error);
4229 MonoArray *args = prepare_run_main (method, argc, argv);
4230 return mono_runtime_exec_main_checked (method, args, error);
4234 * mono_runtime_try_run_main:
4235 * @method: the method to start the application with (usually Main)
4236 * @argc: number of arguments from the command line
4237 * @argv: array of strings from the command line
4238 * @exc: set if Main throws an exception
4239 * @error: set if Main can't be executed
4241 * Execute a standard Main() method (argc/argv contains the executable
4242 * name). This method also sets the command line argument value needed
4243 * by System.Environment. On failure sets @error if Main can't be
4244 * executed or @exc if it threw and exception.
4249 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4253 MonoArray *args = prepare_run_main (method, argc, argv);
4254 return mono_runtime_try_exec_main (method, args, exc);
4259 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4261 static MonoMethod *serialize_method;
4267 if (!serialize_method) {
4268 MonoClass *klass = mono_class_get_remoting_services_class ();
4269 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4272 if (!serialize_method) {
4277 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4282 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4283 if (*exc == NULL && !mono_error_ok (&error))
4284 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4286 mono_error_cleanup (&error);
4295 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4297 MONO_REQ_GC_UNSAFE_MODE;
4299 static MonoMethod *deserialize_method;
4305 if (!deserialize_method) {
4306 MonoClass *klass = mono_class_get_remoting_services_class ();
4307 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4309 if (!deserialize_method) {
4317 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4318 if (*exc == NULL && !mono_error_ok (&error))
4319 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4321 mono_error_cleanup (&error);
4329 #ifndef DISABLE_REMOTING
4331 make_transparent_proxy (MonoObject *obj, MonoError *error)
4333 MONO_REQ_GC_UNSAFE_MODE;
4335 static MonoMethod *get_proxy_method;
4337 MonoDomain *domain = mono_domain_get ();
4338 MonoRealProxy *real_proxy;
4339 MonoReflectionType *reflection_type;
4340 MonoTransparentProxy *transparent_proxy;
4342 mono_error_init (error);
4344 if (!get_proxy_method)
4345 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4347 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4349 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4350 return_val_if_nok (error, NULL);
4351 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4352 return_val_if_nok (error, NULL);
4354 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4355 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4357 MonoObject *exc = NULL;
4359 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4360 if (exc != NULL && is_ok (error))
4361 mono_error_set_exception_instance (error, (MonoException*)exc);
4363 return (MonoObject*) transparent_proxy;
4365 #endif /* DISABLE_REMOTING */
4368 * mono_object_xdomain_representation
4370 * @target_domain: a domain
4371 * @error: set on error.
4373 * Creates a representation of obj in the domain target_domain. This
4374 * is either a copy of obj arrived through via serialization and
4375 * deserialization or a proxy, depending on whether the object is
4376 * serializable or marshal by ref. obj must not be in target_domain.
4378 * If the object cannot be represented in target_domain, NULL is
4379 * returned and @error is set appropriately.
4382 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4384 MONO_REQ_GC_UNSAFE_MODE;
4386 mono_error_init (error);
4387 MonoObject *deserialized = NULL;
4389 #ifndef DISABLE_REMOTING
4390 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4391 deserialized = make_transparent_proxy (obj, error);
4396 gboolean failure = FALSE;
4397 MonoDomain *domain = mono_domain_get ();
4398 MonoObject *serialized;
4399 MonoObject *exc = NULL;
4401 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4402 serialized = serialize_object (obj, &failure, &exc);
4403 mono_domain_set_internal_with_options (target_domain, FALSE);
4405 deserialized = deserialize_object (serialized, &failure, &exc);
4406 if (domain != target_domain)
4407 mono_domain_set_internal_with_options (domain, FALSE);
4409 mono_error_set_exception_instance (error, (MonoException*)exc);
4412 return deserialized;
4415 /* Used in call_unhandled_exception_delegate */
4417 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4419 MONO_REQ_GC_UNSAFE_MODE;
4421 mono_error_init (error);
4424 MonoMethod *method = NULL;
4425 MonoBoolean is_terminating = TRUE;
4428 klass = mono_class_get_unhandled_exception_event_args_class ();
4429 mono_class_init (klass);
4431 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4432 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4436 args [1] = &is_terminating;
4438 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4439 return_val_if_nok (error, NULL);
4441 mono_runtime_invoke_checked (method, obj, args, error);
4442 return_val_if_nok (error, NULL);
4447 /* Used in mono_unhandled_exception */
4449 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4450 MONO_REQ_GC_UNSAFE_MODE;
4453 MonoObject *e = NULL;
4455 MonoDomain *current_domain = mono_domain_get ();
4457 if (domain != current_domain)
4458 mono_domain_set_internal_with_options (domain, FALSE);
4460 g_assert (domain == mono_object_domain (domain->domain));
4462 if (mono_object_domain (exc) != domain) {
4464 exc = mono_object_xdomain_representation (exc, domain, &error);
4466 if (!is_ok (&error)) {
4467 MonoError inner_error;
4468 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4469 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4470 mono_error_assert_ok (&inner_error);
4472 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4473 "System.Runtime.Serialization", "SerializationException",
4474 "Could not serialize unhandled exception.");
4478 g_assert (mono_object_domain (exc) == domain);
4480 pa [0] = domain->domain;
4481 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4482 mono_error_assert_ok (&error);
4483 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4484 if (!is_ok (&error)) {
4486 e = (MonoObject*)mono_error_convert_to_exception (&error);
4488 mono_error_cleanup (&error);
4491 if (domain != current_domain)
4492 mono_domain_set_internal_with_options (current_domain, FALSE);
4495 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4496 if (!mono_error_ok (&error)) {
4497 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4498 mono_error_cleanup (&error);
4500 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4506 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4509 * mono_runtime_unhandled_exception_policy_set:
4510 * @policy: the new policy
4512 * This is a VM internal routine.
4514 * Sets the runtime policy for handling unhandled exceptions.
4517 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4518 runtime_unhandled_exception_policy = policy;
4522 * mono_runtime_unhandled_exception_policy_get:
4524 * This is a VM internal routine.
4526 * Gets the runtime policy for handling unhandled exceptions.
4528 MonoRuntimeUnhandledExceptionPolicy
4529 mono_runtime_unhandled_exception_policy_get (void) {
4530 return runtime_unhandled_exception_policy;
4534 * mono_unhandled_exception:
4535 * @exc: exception thrown
4537 * This is a VM internal routine.
4539 * We call this function when we detect an unhandled exception
4540 * in the default domain.
4542 * It invokes the * UnhandledException event in AppDomain or prints
4543 * a warning to the console
4546 mono_unhandled_exception (MonoObject *exc)
4548 MONO_REQ_GC_UNSAFE_MODE;
4551 MonoClassField *field;
4552 MonoDomain *current_domain, *root_domain;
4553 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4555 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4558 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4561 current_domain = mono_domain_get ();
4562 root_domain = mono_get_root_domain ();
4564 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4565 mono_error_assert_ok (&error);
4566 if (current_domain != root_domain) {
4567 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4568 mono_error_assert_ok (&error);
4571 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4572 mono_print_unhandled_exception (exc);
4574 /* unhandled exception callbacks must not be aborted */
4575 mono_threads_begin_abort_protected_block ();
4576 if (root_appdomain_delegate)
4577 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4578 if (current_appdomain_delegate)
4579 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4580 mono_threads_end_abort_protected_block ();
4583 /* set exitcode only if we will abort the process */
4584 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4585 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4587 mono_environment_exitcode_set (1);
4592 * mono_runtime_exec_managed_code:
4593 * @domain: Application domain
4594 * @main_func: function to invoke from the execution thread
4595 * @main_args: parameter to the main_func
4597 * Launch a new thread to execute a function
4599 * main_func is called back from the thread with main_args as the
4600 * parameter. The callback function is expected to start Main()
4601 * eventually. This function then waits for all managed threads to
4603 * It is not necesseray anymore to execute managed code in a subthread,
4604 * so this function should not be used anymore by default: just
4605 * execute the code and then call mono_thread_manage ().
4608 mono_runtime_exec_managed_code (MonoDomain *domain,
4609 MonoMainThreadFunc main_func,
4613 mono_thread_create_checked (domain, main_func, main_args, &error);
4614 mono_error_assert_ok (&error);
4616 mono_thread_manage ();
4620 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4622 MonoInternalThread* thread = mono_thread_internal_current ();
4623 MonoCustomAttrInfo* cinfo;
4624 gboolean has_stathread_attribute;
4626 if (!domain->entry_assembly) {
4628 MonoAssembly *assembly;
4630 assembly = method->klass->image->assembly;
4631 domain->entry_assembly = assembly;
4632 /* Domains created from another domain already have application_base and configuration_file set */
4633 if (domain->setup->application_base == NULL) {
4634 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4637 if (domain->setup->configuration_file == NULL) {
4638 str = g_strconcat (assembly->image->name, ".config", NULL);
4639 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4641 mono_domain_set_options_from_config (domain);
4645 MonoError cattr_error;
4646 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4647 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4649 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4651 mono_custom_attrs_free (cinfo);
4653 has_stathread_attribute = FALSE;
4655 if (has_stathread_attribute) {
4656 thread->apartment_state = ThreadApartmentState_STA;
4658 thread->apartment_state = ThreadApartmentState_MTA;
4660 mono_thread_init_apartment_state ();
4665 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4667 MONO_REQ_GC_UNSAFE_MODE;
4672 mono_error_init (error);
4677 /* FIXME: check signature of method */
4678 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4680 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4682 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4685 mono_environment_exitcode_set (rval);
4687 mono_runtime_invoke_checked (method, NULL, pa, error);
4699 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4701 MONO_REQ_GC_UNSAFE_MODE;
4711 /* FIXME: check signature of method */
4712 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4713 MonoError inner_error;
4715 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4716 if (*exc == NULL && !mono_error_ok (&inner_error))
4717 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4719 mono_error_cleanup (&inner_error);
4722 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4726 mono_environment_exitcode_set (rval);
4728 MonoError inner_error;
4729 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4730 if (*exc == NULL && !mono_error_ok (&inner_error))
4731 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4733 mono_error_cleanup (&inner_error);
4738 /* If the return type of Main is void, only
4739 * set the exitcode if an exception was thrown
4740 * (we don't want to blow away an
4741 * explicitly-set exit code)
4744 mono_environment_exitcode_set (rval);
4752 * Execute a standard Main() method (args doesn't contain the
4756 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4759 prepare_thread_to_exec_main (mono_object_domain (args), method);
4761 int rval = do_try_exec_main (method, args, exc);
4764 int rval = do_exec_main_checked (method, args, &error);
4765 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4771 * Execute a standard Main() method (args doesn't contain the
4774 * On failure sets @error
4777 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4779 mono_error_init (error);
4780 prepare_thread_to_exec_main (mono_object_domain (args), method);
4781 return do_exec_main_checked (method, args, error);
4785 * Execute a standard Main() method (args doesn't contain the
4788 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4791 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4793 prepare_thread_to_exec_main (mono_object_domain (args), method);
4794 return do_try_exec_main (method, args, exc);
4799 /** invoke_array_extract_argument:
4800 * @params: array of arguments to the method.
4801 * @i: the index of the argument to extract.
4802 * @t: ith type from the method signature.
4803 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4804 * @error: set on error.
4806 * Given an array of method arguments, return the ith one using the corresponding type
4807 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4809 * On failure sets @error and returns NULL.
4812 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4814 MonoType *t_orig = t;
4815 gpointer result = NULL;
4816 mono_error_init (error);
4821 case MONO_TYPE_BOOLEAN:
4824 case MONO_TYPE_CHAR:
4833 case MONO_TYPE_VALUETYPE:
4834 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4835 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4836 result = mono_array_get (params, MonoObject*, i);
4838 *has_byref_nullables = TRUE;
4840 /* MS seems to create the objects if a null is passed in */
4841 if (!mono_array_get (params, MonoObject*, i)) {
4842 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4843 return_val_if_nok (error, NULL);
4844 mono_array_setref (params, i, o);
4849 * We can't pass the unboxed vtype byref to the callee, since
4850 * that would mean the callee would be able to modify boxed
4851 * primitive types. So we (and MS) make a copy of the boxed
4852 * object, pass that to the callee, and replace the original
4853 * boxed object in the arg array with the copy.
4855 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4856 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4857 return_val_if_nok (error, NULL);
4858 mono_array_setref (params, i, copy);
4861 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4864 case MONO_TYPE_STRING:
4865 case MONO_TYPE_OBJECT:
4866 case MONO_TYPE_CLASS:
4867 case MONO_TYPE_ARRAY:
4868 case MONO_TYPE_SZARRAY:
4870 result = mono_array_addr (params, MonoObject*, i);
4871 // FIXME: I need to check this code path
4873 result = mono_array_get (params, MonoObject*, i);
4875 case MONO_TYPE_GENERICINST:
4877 t = &t->data.generic_class->container_class->this_arg;
4879 t = &t->data.generic_class->container_class->byval_arg;
4881 case MONO_TYPE_PTR: {
4884 /* The argument should be an IntPtr */
4885 arg = mono_array_get (params, MonoObject*, i);
4889 g_assert (arg->vtable->klass == mono_defaults.int_class);
4890 result = ((MonoIntPtr*)arg)->m_value;
4895 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4900 * mono_runtime_invoke_array:
4901 * @method: method to invoke
4902 * @obJ: object instance
4903 * @params: arguments to the method
4904 * @exc: exception information.
4906 * Invokes the method represented by @method on the object @obj.
4908 * obj is the 'this' pointer, it should be NULL for static
4909 * methods, a MonoObject* for object instances and a pointer to
4910 * the value type for value types.
4912 * The params array contains the arguments to the method with the
4913 * same convention: MonoObject* pointers for object instances and
4914 * pointers to the value type otherwise. The _invoke_array
4915 * variant takes a C# object[] as the params argument (MonoArray
4916 * *params): in this case the value types are boxed inside the
4917 * respective reference representation.
4919 * From unmanaged code you'll usually use the
4920 * mono_runtime_invoke_checked() variant.
4922 * Note that this function doesn't handle virtual methods for
4923 * you, it will exec the exact method you pass: we still need to
4924 * expose a function to lookup the derived class implementation
4925 * of a virtual method (there are examples of this in the code,
4928 * You can pass NULL as the exc argument if you don't want to
4929 * catch exceptions, otherwise, *exc will be set to the exception
4930 * thrown, if any. if an exception is thrown, you can't use the
4931 * MonoObject* result from the function.
4933 * If the method returns a value type, it is boxed in an object
4937 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4942 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4944 mono_error_cleanup (&error);
4947 if (!is_ok (&error))
4948 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4952 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4953 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4959 * mono_runtime_invoke_array_checked:
4960 * @method: method to invoke
4961 * @obJ: object instance
4962 * @params: arguments to the method
4963 * @error: set on failure.
4965 * Invokes the method represented by @method on the object @obj.
4967 * obj is the 'this' pointer, it should be NULL for static
4968 * methods, a MonoObject* for object instances and a pointer to
4969 * the value type for value types.
4971 * The params array contains the arguments to the method with the
4972 * same convention: MonoObject* pointers for object instances and
4973 * pointers to the value type otherwise. The _invoke_array
4974 * variant takes a C# object[] as the params argument (MonoArray
4975 * *params): in this case the value types are boxed inside the
4976 * respective reference representation.
4978 * From unmanaged code you'll usually use the
4979 * mono_runtime_invoke_checked() variant.
4981 * Note that this function doesn't handle virtual methods for
4982 * you, it will exec the exact method you pass: we still need to
4983 * expose a function to lookup the derived class implementation
4984 * of a virtual method (there are examples of this in the code,
4987 * On failure or exception, @error will be set. In that case, you
4988 * can't use the MonoObject* result from the function.
4990 * If the method returns a value type, it is boxed in an object
4994 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4997 mono_error_init (error);
4998 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5002 * mono_runtime_try_invoke_array:
5003 * @method: method to invoke
5004 * @obJ: object instance
5005 * @params: arguments to the method
5006 * @exc: exception information.
5007 * @error: set on failure.
5009 * Invokes the method represented by @method on the object @obj.
5011 * obj is the 'this' pointer, it should be NULL for static
5012 * methods, a MonoObject* for object instances and a pointer to
5013 * the value type for value types.
5015 * The params array contains the arguments to the method with the
5016 * same convention: MonoObject* pointers for object instances and
5017 * pointers to the value type otherwise. The _invoke_array
5018 * variant takes a C# object[] as the params argument (MonoArray
5019 * *params): in this case the value types are boxed inside the
5020 * respective reference representation.
5022 * From unmanaged code you'll usually use the
5023 * mono_runtime_invoke_checked() variant.
5025 * Note that this function doesn't handle virtual methods for
5026 * you, it will exec the exact method you pass: we still need to
5027 * expose a function to lookup the derived class implementation
5028 * of a virtual method (there are examples of this in the code,
5031 * You can pass NULL as the exc argument if you don't want to catch
5032 * exceptions, otherwise, *exc will be set to the exception thrown, if
5033 * any. On other failures, @error will be set. If an exception is
5034 * thrown or there's an error, you can't use the MonoObject* result
5035 * from the function.
5037 * If the method returns a value type, it is boxed in an object
5041 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5042 MonoObject **exc, MonoError *error)
5044 MONO_REQ_GC_UNSAFE_MODE;
5046 mono_error_init (error);
5048 MonoMethodSignature *sig = mono_method_signature (method);
5049 gpointer *pa = NULL;
5052 gboolean has_byref_nullables = FALSE;
5054 if (NULL != params) {
5055 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5056 for (i = 0; i < mono_array_length (params); i++) {
5057 MonoType *t = sig->params [i];
5058 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5059 return_val_if_nok (error, NULL);
5063 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5066 if (mono_class_is_nullable (method->klass)) {
5067 /* Need to create a boxed vtype instead */
5073 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5078 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5079 mono_error_assert_ok (error);
5080 g_assert (obj); /*maybe we should raise a TLE instead?*/
5081 #ifndef DISABLE_REMOTING
5082 if (mono_object_is_transparent_proxy (obj)) {
5083 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5086 if (method->klass->valuetype)
5087 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5090 } else if (method->klass->valuetype) {
5091 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5092 return_val_if_nok (error, NULL);
5096 mono_runtime_try_invoke (method, o, pa, exc, error);
5098 mono_runtime_invoke_checked (method, o, pa, error);
5101 return (MonoObject *)obj;
5103 if (mono_class_is_nullable (method->klass)) {
5104 MonoObject *nullable;
5106 /* Convert the unboxed vtype into a Nullable structure */
5107 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5108 return_val_if_nok (error, NULL);
5110 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5111 return_val_if_nok (error, NULL);
5112 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5113 obj = mono_object_unbox (nullable);
5116 /* obj must be already unboxed if needed */
5118 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5120 res = mono_runtime_invoke_checked (method, obj, pa, error);
5122 return_val_if_nok (error, NULL);
5124 if (sig->ret->type == MONO_TYPE_PTR) {
5125 MonoClass *pointer_class;
5126 static MonoMethod *box_method;
5128 MonoObject *box_exc;
5131 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5132 * convert it to a Pointer object.
5134 pointer_class = mono_class_get_pointer_class ();
5136 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5138 g_assert (res->vtable->klass == mono_defaults.int_class);
5139 box_args [0] = ((MonoIntPtr*)res)->m_value;
5140 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5141 return_val_if_nok (error, NULL);
5143 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5144 g_assert (box_exc == NULL);
5145 mono_error_assert_ok (error);
5148 if (has_byref_nullables) {
5150 * The runtime invoke wrapper already converted byref nullables back,
5151 * and stored them in pa, we just need to copy them back to the
5154 for (i = 0; i < mono_array_length (params); i++) {
5155 MonoType *t = sig->params [i];
5157 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5158 mono_array_setref (params, i, pa [i]);
5168 * @klass: the class of the object that we want to create
5170 * Returns: a newly created object whose definition is
5171 * looked up using @klass. This will not invoke any constructors,
5172 * so the consumer of this routine has to invoke any constructors on
5173 * its own to initialize the object.
5175 * It returns NULL on failure.
5178 mono_object_new (MonoDomain *domain, MonoClass *klass)
5180 MONO_REQ_GC_UNSAFE_MODE;
5184 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5186 mono_error_cleanup (&error);
5191 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5193 MONO_REQ_GC_UNSAFE_MODE;
5197 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5199 mono_error_set_pending_exception (&error);
5204 * mono_object_new_checked:
5205 * @klass: the class of the object that we want to create
5206 * @error: set on error
5208 * Returns: a newly created object whose definition is
5209 * looked up using @klass. This will not invoke any constructors,
5210 * so the consumer of this routine has to invoke any constructors on
5211 * its own to initialize the object.
5213 * It returns NULL on failure and sets @error.
5216 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5218 MONO_REQ_GC_UNSAFE_MODE;
5222 vtable = mono_class_vtable (domain, klass);
5223 g_assert (vtable); /* FIXME don't swallow the error */
5225 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5230 * mono_object_new_pinned:
5232 * Same as mono_object_new, but the returned object will be pinned.
5233 * For SGEN, these objects will only be freed at appdomain unload.
5236 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5238 MONO_REQ_GC_UNSAFE_MODE;
5242 mono_error_init (error);
5244 vtable = mono_class_vtable (domain, klass);
5245 g_assert (vtable); /* FIXME don't swallow the error */
5247 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5249 if (G_UNLIKELY (!o))
5250 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5251 else if (G_UNLIKELY (vtable->klass->has_finalize))
5252 mono_object_register_finalizer (o);
5258 * mono_object_new_specific:
5259 * @vtable: the vtable of the object that we want to create
5261 * Returns: A newly created object with class and domain specified
5265 mono_object_new_specific (MonoVTable *vtable)
5268 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5269 mono_error_cleanup (&error);
5275 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5277 MONO_REQ_GC_UNSAFE_MODE;
5281 mono_error_init (error);
5283 /* check for is_com_object for COM Interop */
5284 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5287 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5290 MonoClass *klass = mono_class_get_activation_services_class ();
5293 mono_class_init (klass);
5295 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5297 mono_error_set_not_supported (error, "Linked away.");
5300 vtable->domain->create_proxy_for_type_method = im;
5303 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5304 if (!mono_error_ok (error))
5307 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5308 if (!mono_error_ok (error))
5315 return mono_object_new_alloc_specific_checked (vtable, error);
5319 ves_icall_object_new_specific (MonoVTable *vtable)
5322 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5323 mono_error_set_pending_exception (&error);
5329 * mono_object_new_alloc_specific:
5330 * @vtable: virtual table for the object.
5332 * This function allocates a new `MonoObject` with the type derived
5333 * from the @vtable information. If the class of this object has a
5334 * finalizer, then the object will be tracked for finalization.
5336 * This method might raise an exception on errors. Use the
5337 * `mono_object_new_fast_checked` method if you want to manually raise
5340 * Returns: the allocated object.
5343 mono_object_new_alloc_specific (MonoVTable *vtable)
5346 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5347 mono_error_cleanup (&error);
5353 * mono_object_new_alloc_specific_checked:
5354 * @vtable: virtual table for the object.
5355 * @error: holds the error return value.
5357 * This function allocates a new `MonoObject` with the type derived
5358 * from the @vtable information. If the class of this object has a
5359 * finalizer, then the object will be tracked for finalization.
5361 * If there is not enough memory, the @error parameter will be set
5362 * and will contain a user-visible message with the amount of bytes
5363 * that were requested.
5365 * Returns: the allocated object, or NULL if there is not enough memory
5369 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5371 MONO_REQ_GC_UNSAFE_MODE;
5375 mono_error_init (error);
5377 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5379 if (G_UNLIKELY (!o))
5380 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5381 else if (G_UNLIKELY (vtable->klass->has_finalize))
5382 mono_object_register_finalizer (o);
5388 * mono_object_new_fast:
5389 * @vtable: virtual table for the object.
5391 * This function allocates a new `MonoObject` with the type derived
5392 * from the @vtable information. The returned object is not tracked
5393 * for finalization. If your object implements a finalizer, you should
5394 * use `mono_object_new_alloc_specific` instead.
5396 * This method might raise an exception on errors. Use the
5397 * `mono_object_new_fast_checked` method if you want to manually raise
5400 * Returns: the allocated object.
5403 mono_object_new_fast (MonoVTable *vtable)
5406 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5407 mono_error_cleanup (&error);
5413 * mono_object_new_fast_checked:
5414 * @vtable: virtual table for the object.
5415 * @error: holds the error return value.
5417 * This function allocates a new `MonoObject` with the type derived
5418 * from the @vtable information. The returned object is not tracked
5419 * for finalization. If your object implements a finalizer, you should
5420 * use `mono_object_new_alloc_specific_checked` instead.
5422 * If there is not enough memory, the @error parameter will be set
5423 * and will contain a user-visible message with the amount of bytes
5424 * that were requested.
5426 * Returns: the allocated object, or NULL if there is not enough memory
5430 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5432 MONO_REQ_GC_UNSAFE_MODE;
5436 mono_error_init (error);
5438 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5440 if (G_UNLIKELY (!o))
5441 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5447 ves_icall_object_new_fast (MonoVTable *vtable)
5450 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5451 mono_error_set_pending_exception (&error);
5457 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5459 MONO_REQ_GC_UNSAFE_MODE;
5463 mono_error_init (error);
5465 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5467 if (G_UNLIKELY (!o))
5468 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5469 else if (G_UNLIKELY (vtable->klass->has_finalize))
5470 mono_object_register_finalizer (o);
5476 * mono_class_get_allocation_ftn:
5478 * @for_box: the object will be used for boxing
5479 * @pass_size_in_words:
5481 * Return the allocation function appropriate for the given class.
5485 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5487 MONO_REQ_GC_NEUTRAL_MODE;
5489 *pass_size_in_words = FALSE;
5491 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
5492 return ves_icall_object_new_specific;
5494 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5496 return ves_icall_object_new_fast;
5499 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5500 * of the overhead of parameter passing.
5503 *pass_size_in_words = TRUE;
5504 #ifdef GC_REDIRECT_TO_LOCAL
5505 return GC_local_gcj_fast_malloc;
5507 return GC_gcj_fast_malloc;
5512 return ves_icall_object_new_specific;
5516 * mono_object_new_from_token:
5517 * @image: Context where the type_token is hosted
5518 * @token: a token of the type that we want to create
5520 * Returns: A newly created object whose definition is
5521 * looked up using @token in the @image image
5524 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5526 MONO_REQ_GC_UNSAFE_MODE;
5532 klass = mono_class_get_checked (image, token, &error);
5533 mono_error_assert_ok (&error);
5535 result = mono_object_new_checked (domain, klass, &error);
5537 mono_error_cleanup (&error);
5544 * mono_object_clone:
5545 * @obj: the object to clone
5547 * Returns: A newly created object who is a shallow copy of @obj
5550 mono_object_clone (MonoObject *obj)
5553 MonoObject *o = mono_object_clone_checked (obj, &error);
5554 mono_error_cleanup (&error);
5560 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5562 MONO_REQ_GC_UNSAFE_MODE;
5567 mono_error_init (error);
5569 size = obj->vtable->klass->instance_size;
5571 if (obj->vtable->klass->rank)
5572 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5574 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5576 if (G_UNLIKELY (!o)) {
5577 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5581 /* If the object doesn't contain references this will do a simple memmove. */
5582 mono_gc_wbarrier_object_copy (o, obj);
5584 if (obj->vtable->klass->has_finalize)
5585 mono_object_register_finalizer (o);
5590 * mono_array_full_copy:
5591 * @src: source array to copy
5592 * @dest: destination array
5594 * Copies the content of one array to another with exactly the same type and size.
5597 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5599 MONO_REQ_GC_UNSAFE_MODE;
5602 MonoClass *klass = src->obj.vtable->klass;
5604 g_assert (klass == dest->obj.vtable->klass);
5606 size = mono_array_length (src);
5607 g_assert (size == mono_array_length (dest));
5608 size *= mono_array_element_size (klass);
5610 array_full_copy_unchecked_size (src, dest, klass, size);
5614 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5617 if (klass->element_class->valuetype) {
5618 if (klass->element_class->has_references)
5619 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5621 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5623 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5626 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5631 * mono_array_clone_in_domain:
5632 * @domain: the domain in which the array will be cloned into
5633 * @array: the array to clone
5634 * @error: set on error
5636 * This routine returns a copy of the array that is hosted on the
5637 * specified MonoDomain. On failure returns NULL and sets @error.
5640 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5642 MONO_REQ_GC_UNSAFE_MODE;
5644 MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5646 MonoClass *klass = mono_handle_class (array_handle);
5648 mono_error_init (error);
5650 /* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5651 uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5653 MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5655 if (array_bounds == NULL) {
5656 size = mono_array_handle_length (array_handle);
5657 o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5660 size *= mono_array_element_size (klass);
5662 uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5663 intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5664 size = mono_array_element_size (klass);
5665 for (int i = 0; i < klass->rank; ++i) {
5666 sizes [i] = array_bounds [i].length;
5667 size *= array_bounds [i].length;
5668 lower_bounds [i] = array_bounds [i].lower_bound;
5670 o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5675 uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5676 array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5677 mono_gchandle_free (dst_handle);
5679 MONO_HANDLE_ASSIGN (result, o);
5682 mono_gchandle_free (src_handle);
5688 * @array: the array to clone
5690 * Returns: A newly created array who is a shallow copy of @array
5693 mono_array_clone (MonoArray *array)
5695 MONO_REQ_GC_UNSAFE_MODE;
5698 MonoArray *result = mono_array_clone_checked (array, &error);
5699 mono_error_cleanup (&error);
5704 * mono_array_clone_checked:
5705 * @array: the array to clone
5706 * @error: set on error
5708 * Returns: A newly created array who is a shallow copy of @array. On
5709 * failure returns NULL and sets @error.
5712 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5714 MONO_REQ_GC_UNSAFE_MODE;
5715 HANDLE_FUNCTION_ENTER ();
5716 /* FIXME: callers of mono_array_clone_checked should use handles */
5717 mono_error_init (error);
5718 MONO_HANDLE_DCL (MonoArray, array);
5719 MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5720 HANDLE_FUNCTION_RETURN_OBJ (result);
5723 /* helper macros to check for overflow when calculating the size of arrays */
5724 #ifdef MONO_BIG_ARRAYS
5725 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5726 #define MYGUINT_MAX MYGUINT64_MAX
5727 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5728 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5729 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5730 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5731 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5733 #define MYGUINT32_MAX 4294967295U
5734 #define MYGUINT_MAX MYGUINT32_MAX
5735 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5736 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5737 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5738 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5739 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5743 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5745 MONO_REQ_GC_NEUTRAL_MODE;
5749 byte_len = mono_array_element_size (klass);
5750 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5753 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5755 byte_len += MONO_SIZEOF_MONO_ARRAY;
5763 * mono_array_new_full:
5764 * @domain: domain where the object is created
5765 * @array_class: array class
5766 * @lengths: lengths for each dimension in the array
5767 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5769 * This routine creates a new array objects with the given dimensions,
5770 * lower bounds and type.
5773 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5776 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5777 mono_error_cleanup (&error);
5783 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5785 MONO_REQ_GC_UNSAFE_MODE;
5787 uintptr_t byte_len = 0, len, bounds_size;
5790 MonoArrayBounds *bounds;
5794 mono_error_init (error);
5796 if (!array_class->inited)
5797 mono_class_init (array_class);
5801 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5802 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5804 if (len > MONO_ARRAY_MAX_INDEX) {
5805 mono_error_set_generic_error (error, "System", "OverflowException", "");
5810 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5812 for (i = 0; i < array_class->rank; ++i) {
5813 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5814 mono_error_set_generic_error (error, "System", "OverflowException", "");
5817 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5818 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5825 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5826 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5832 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5833 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5836 byte_len = (byte_len + 3) & ~3;
5837 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5838 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5841 byte_len += bounds_size;
5844 * Following three lines almost taken from mono_object_new ():
5845 * they need to be kept in sync.
5847 vtable = mono_class_vtable_full (domain, array_class, error);
5848 return_val_if_nok (error, NULL);
5851 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5853 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5855 if (G_UNLIKELY (!o)) {
5856 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5860 array = (MonoArray*)o;
5862 bounds = array->bounds;
5865 for (i = 0; i < array_class->rank; ++i) {
5866 bounds [i].length = lengths [i];
5868 bounds [i].lower_bound = lower_bounds [i];
5877 * @domain: domain where the object is created
5878 * @eclass: element class
5879 * @n: number of array elements
5881 * This routine creates a new szarray with @n elements of type @eclass.
5884 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5886 MONO_REQ_GC_UNSAFE_MODE;
5889 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5890 mono_error_cleanup (&error);
5895 * mono_array_new_checked:
5896 * @domain: domain where the object is created
5897 * @eclass: element class
5898 * @n: number of array elements
5899 * @error: set on error
5901 * This routine creates a new szarray with @n elements of type @eclass.
5902 * On failure returns NULL and sets @error.
5905 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5909 mono_error_init (error);
5911 ac = mono_array_class_get (eclass, 1);
5914 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5915 return_val_if_nok (error, NULL);
5917 return mono_array_new_specific_checked (vtable, n, error);
5921 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5924 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5925 mono_error_set_pending_exception (&error);
5931 * mono_array_new_specific:
5932 * @vtable: a vtable in the appropriate domain for an initialized class
5933 * @n: number of array elements
5935 * This routine is a fast alternative to mono_array_new() for code which
5936 * can be sure about the domain it operates in.
5939 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5942 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5943 mono_error_cleanup (&error);
5949 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5951 MONO_REQ_GC_UNSAFE_MODE;
5956 mono_error_init (error);
5958 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5959 mono_error_set_generic_error (error, "System", "OverflowException", "");
5963 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5964 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5967 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5969 if (G_UNLIKELY (!o)) {
5970 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5974 return (MonoArray*)o;
5978 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5981 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5982 mono_error_set_pending_exception (&error);
5988 * mono_string_empty_wrapper:
5990 * Returns: The same empty string instance as the managed string.Empty
5993 mono_string_empty_wrapper (void)
5995 MonoDomain *domain = mono_domain_get ();
5996 return mono_string_empty (domain);
6000 * mono_string_empty:
6002 * Returns: The same empty string instance as the managed string.Empty
6005 mono_string_empty (MonoDomain *domain)
6008 g_assert (domain->empty_string);
6009 return domain->empty_string;
6013 * mono_string_new_utf16:
6014 * @text: a pointer to an utf16 string
6015 * @len: the length of the string
6017 * Returns: A newly created string object which contains @text.
6020 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6022 MONO_REQ_GC_UNSAFE_MODE;
6025 MonoString *res = NULL;
6026 res = mono_string_new_utf16_checked (domain, text, len, &error);
6027 mono_error_cleanup (&error);
6033 * mono_string_new_utf16_checked:
6034 * @text: a pointer to an utf16 string
6035 * @len: the length of the string
6036 * @error: written on error.
6038 * Returns: A newly created string object which contains @text.
6039 * On error, returns NULL and sets @error.
6042 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6044 MONO_REQ_GC_UNSAFE_MODE;
6048 mono_error_init (error);
6050 s = mono_string_new_size_checked (domain, len, error);
6052 memcpy (mono_string_chars (s), text, len * 2);
6058 * mono_string_new_utf16_handle:
6059 * @text: a pointer to an utf16 string
6060 * @len: the length of the string
6061 * @error: written on error.
6063 * Returns: A newly created string object which contains @text.
6064 * On error, returns NULL and sets @error.
6067 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6069 return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6073 * mono_string_new_utf32:
6074 * @text: a pointer to an utf32 string
6075 * @len: the length of the string
6076 * @error: set on failure.
6078 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6081 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6083 MONO_REQ_GC_UNSAFE_MODE;
6086 mono_unichar2 *utf16_output = NULL;
6087 gint32 utf16_len = 0;
6088 GError *gerror = NULL;
6089 glong items_written;
6091 mono_error_init (error);
6092 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6095 g_error_free (gerror);
6097 while (utf16_output [utf16_len]) utf16_len++;
6099 s = mono_string_new_size_checked (domain, utf16_len, error);
6100 return_val_if_nok (error, NULL);
6102 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6104 g_free (utf16_output);
6110 * mono_string_new_utf32:
6111 * @text: a pointer to an utf32 string
6112 * @len: the length of the string
6114 * Returns: A newly created string object which contains @text.
6117 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6120 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6121 mono_error_cleanup (&error);
6126 * mono_string_new_size:
6127 * @text: a pointer to an utf16 string
6128 * @len: the length of the string
6130 * Returns: A newly created string object of @len
6133 mono_string_new_size (MonoDomain *domain, gint32 len)
6136 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6137 mono_error_cleanup (&error);
6143 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6145 MONO_REQ_GC_UNSAFE_MODE;
6151 mono_error_init (error);
6153 /* check for overflow */
6154 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6155 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6159 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6160 g_assert (size > 0);
6162 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6165 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6167 if (G_UNLIKELY (!s)) {
6168 mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6176 * mono_string_new_len:
6177 * @text: a pointer to an utf8 string
6178 * @length: number of bytes in @text to consider
6180 * Returns: A newly created string object which contains @text.
6183 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6185 MONO_REQ_GC_UNSAFE_MODE;
6188 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6189 mono_error_cleanup (&error);
6194 * mono_string_new_len_checked:
6195 * @text: a pointer to an utf8 string
6196 * @length: number of bytes in @text to consider
6197 * @error: set on error
6199 * Returns: A newly created string object which contains @text. On
6200 * failure returns NULL and sets @error.
6203 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6205 MONO_REQ_GC_UNSAFE_MODE;
6207 mono_error_init (error);
6209 GError *eg_error = NULL;
6210 MonoString *o = NULL;
6212 glong items_written;
6214 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6217 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6219 g_error_free (eg_error);
6228 * @text: a pointer to an utf8 string
6230 * Returns: A newly created string object which contains @text.
6232 * This function asserts if it cannot allocate a new string.
6234 * @deprecated Use mono_string_new_checked in new code.
6237 mono_string_new (MonoDomain *domain, const char *text)
6240 MonoString *res = NULL;
6241 res = mono_string_new_checked (domain, text, &error);
6242 mono_error_assert_ok (&error);
6247 * mono_string_new_checked:
6248 * @text: a pointer to an utf8 string
6249 * @merror: set on error
6251 * Returns: A newly created string object which contains @text.
6252 * On error returns NULL and sets @merror.
6255 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6257 MONO_REQ_GC_UNSAFE_MODE;
6259 GError *eg_error = NULL;
6260 MonoString *o = NULL;
6262 glong items_written;
6265 mono_error_init (error);
6269 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6272 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6274 g_error_free (eg_error);
6278 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6283 MonoString *o = NULL;
6285 if (!g_utf8_validate (text, -1, &end)) {
6286 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6290 len = g_utf8_strlen (text, -1);
6291 o = mono_string_new_size_checked (domain, len, error);
6294 str = mono_string_chars (o);
6296 while (text < end) {
6297 *str++ = g_utf8_get_char (text);
6298 text = g_utf8_next_char (text);
6307 * mono_string_new_wrapper:
6308 * @text: pointer to utf8 characters.
6310 * Helper function to create a string object from @text in the current domain.
6313 mono_string_new_wrapper (const char *text)
6315 MONO_REQ_GC_UNSAFE_MODE;
6317 MonoDomain *domain = mono_domain_get ();
6320 return mono_string_new (domain, text);
6327 * @class: the class of the value
6328 * @value: a pointer to the unboxed data
6330 * Returns: A newly created object which contains @value.
6333 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6336 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6337 mono_error_cleanup (&error);
6342 * mono_value_box_checked:
6343 * @domain: the domain of the new object
6344 * @class: the class of the value
6345 * @value: a pointer to the unboxed data
6346 * @error: set on error
6348 * Returns: A newly created object which contains @value. On failure
6349 * returns NULL and sets @error.
6352 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6354 MONO_REQ_GC_UNSAFE_MODE;
6359 mono_error_init (error);
6361 g_assert (klass->valuetype);
6362 if (mono_class_is_nullable (klass))
6363 return mono_nullable_box ((guint8 *)value, klass, error);
6365 vtable = mono_class_vtable (domain, klass);
6368 size = mono_class_instance_size (klass);
6369 res = mono_object_new_alloc_specific_checked (vtable, error);
6370 return_val_if_nok (error, NULL);
6372 size = size - sizeof (MonoObject);
6375 g_assert (size == mono_class_value_size (klass, NULL));
6376 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6378 #if NO_UNALIGNED_ACCESS
6379 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6383 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6386 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6389 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6392 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6395 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6399 if (klass->has_finalize) {
6400 mono_object_register_finalizer (res);
6401 return_val_if_nok (error, NULL);
6408 * @dest: destination pointer
6409 * @src: source pointer
6410 * @klass: a valuetype class
6412 * Copy a valuetype from @src to @dest. This function must be used
6413 * when @klass contains references fields.
6416 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6418 MONO_REQ_GC_UNSAFE_MODE;
6420 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6424 * mono_value_copy_array:
6425 * @dest: destination array
6426 * @dest_idx: index in the @dest array
6427 * @src: source pointer
6428 * @count: number of items
6430 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6431 * This function must be used when @klass contains references fields.
6432 * Overlap is handled.
6435 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6437 MONO_REQ_GC_UNSAFE_MODE;
6439 int size = mono_array_element_size (dest->obj.vtable->klass);
6440 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6441 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6442 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6446 * mono_object_get_domain:
6447 * @obj: object to query
6449 * Returns: the MonoDomain where the object is hosted
6452 mono_object_get_domain (MonoObject *obj)
6454 MONO_REQ_GC_UNSAFE_MODE;
6456 return mono_object_domain (obj);
6460 * mono_object_get_class:
6461 * @obj: object to query
6463 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6465 * Returns: the MonoClass of the object.
6468 mono_object_get_class (MonoObject *obj)
6470 MONO_REQ_GC_UNSAFE_MODE;
6472 return mono_object_class (obj);
6475 * mono_object_get_size:
6476 * @o: object to query
6478 * Returns: the size, in bytes, of @o
6481 mono_object_get_size (MonoObject* o)
6483 MONO_REQ_GC_UNSAFE_MODE;
6485 MonoClass* klass = mono_object_class (o);
6486 if (klass == mono_defaults.string_class) {
6487 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6488 } else if (o->vtable->rank) {
6489 MonoArray *array = (MonoArray*)o;
6490 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6491 if (array->bounds) {
6494 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6498 return mono_class_instance_size (klass);
6503 * mono_object_unbox:
6504 * @obj: object to unbox
6506 * Returns: a pointer to the start of the valuetype boxed in this
6509 * This method will assert if the object passed is not a valuetype.
6512 mono_object_unbox (MonoObject *obj)
6514 MONO_REQ_GC_UNSAFE_MODE;
6516 /* add assert for valuetypes? */
6517 g_assert (obj->vtable->klass->valuetype);
6518 return ((char*)obj) + sizeof (MonoObject);
6522 * mono_object_isinst:
6524 * @klass: a pointer to a class
6526 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6529 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6531 MONO_REQ_GC_UNSAFE_MODE;
6533 HANDLE_FUNCTION_ENTER ();
6534 MONO_HANDLE_DCL (MonoObject, obj);
6536 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6537 mono_error_cleanup (&error);
6538 HANDLE_FUNCTION_RETURN_OBJ (result);
6543 * mono_object_isinst_checked:
6545 * @klass: a pointer to a class
6546 * @error: set on error
6548 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6549 * On failure returns NULL and sets @error.
6552 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6554 MONO_REQ_GC_UNSAFE_MODE;
6556 HANDLE_FUNCTION_ENTER ();
6557 mono_error_init (error);
6558 MONO_HANDLE_DCL (MonoObject, obj);
6559 MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6560 HANDLE_FUNCTION_RETURN_OBJ (result);
6564 * mono_object_handle_isinst:
6566 * @klass: a pointer to a class
6567 * @error: set on error
6569 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6570 * On failure returns NULL and sets @error.
6573 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6575 mono_error_init (error);
6578 mono_class_init (klass);
6580 if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6581 return mono_object_handle_isinst_mbyref (obj, klass, error);
6584 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6586 if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6587 MONO_HANDLE_ASSIGN (result, obj);
6592 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6594 MONO_REQ_GC_UNSAFE_MODE;
6596 HANDLE_FUNCTION_ENTER ();
6598 MONO_HANDLE_DCL (MonoObject, obj);
6599 MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6600 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6601 HANDLE_FUNCTION_RETURN_OBJ (result);
6605 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6607 mono_error_init (error);
6609 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6611 if (MONO_HANDLE_IS_NULL (obj))
6614 MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6616 if (mono_class_is_interface (klass)) {
6617 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6618 MONO_HANDLE_ASSIGN (result, obj);
6622 /* casting an array one of the invariant interfaces that must act as such */
6623 if (klass->is_array_special_interface) {
6624 if (mono_class_is_assignable_from (klass, vt->klass)) {
6625 MONO_HANDLE_ASSIGN (result, obj);
6630 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6631 else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6632 MONO_HANDLE_ASSIGN (result, obj);
6636 MonoClass *oklass = vt->klass;
6637 if (mono_class_is_transparent_proxy (oklass)){
6638 MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6639 oklass = remote_class->proxy_class;
6642 mono_class_setup_supertypes (klass);
6643 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6644 MONO_HANDLE_ASSIGN (result, obj);
6648 #ifndef DISABLE_REMOTING
6649 if (mono_class_is_transparent_proxy (vt->klass))
6651 MonoBoolean custom_type_info = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6652 if (!custom_type_info)
6654 MonoDomain *domain = mono_domain_get ();
6655 MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6656 MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6657 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6658 MonoMethod *im = NULL;
6661 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6663 mono_error_set_not_supported (error, "Linked away.");
6666 im = mono_object_handle_get_virtual_method (rp, im, error);
6671 MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6675 pa [0] = MONO_HANDLE_RAW (reftype);
6676 pa [1] = MONO_HANDLE_RAW (obj);
6677 MonoObject *res = mono_runtime_invoke_checked (im, rp, pa, error);
6681 if (*(MonoBoolean *) mono_object_unbox(res)) {
6682 /* Update the vtable of the remote type, so it can safely cast to this new type */
6683 mono_upgrade_remote_class (domain, obj, klass, error);
6686 MONO_HANDLE_ASSIGN (result, obj);
6689 #endif /* DISABLE_REMOTING */
6695 * mono_object_castclass_mbyref:
6697 * @klass: a pointer to a class
6699 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6702 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6704 MONO_REQ_GC_UNSAFE_MODE;
6705 HANDLE_FUNCTION_ENTER ();
6707 MONO_HANDLE_DCL (MonoObject, obj);
6708 MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6709 if (MONO_HANDLE_IS_NULL (obj))
6711 MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6712 mono_error_cleanup (&error);
6714 HANDLE_FUNCTION_RETURN_OBJ (result);
6718 MonoDomain *orig_domain;
6724 str_lookup (MonoDomain *domain, gpointer user_data)
6726 MONO_REQ_GC_UNSAFE_MODE;
6728 LDStrInfo *info = (LDStrInfo *)user_data;
6729 if (info->res || domain == info->orig_domain)
6731 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6735 mono_string_get_pinned (MonoString *str, MonoError *error)
6737 MONO_REQ_GC_UNSAFE_MODE;
6739 mono_error_init (error);
6741 /* We only need to make a pinned version of a string if this is a moving GC */
6742 if (!mono_gc_is_moving ())
6746 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6747 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6749 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6750 news->length = mono_string_length (str);
6752 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6758 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6760 MONO_REQ_GC_UNSAFE_MODE;
6762 MonoGHashTable *ldstr_table;
6763 MonoString *s, *res;
6766 mono_error_init (error);
6768 domain = ((MonoObject *)str)->vtable->domain;
6769 ldstr_table = domain->ldstr_table;
6771 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6777 /* Allocate outside the lock */
6779 s = mono_string_get_pinned (str, error);
6780 return_val_if_nok (error, NULL);
6783 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6788 mono_g_hash_table_insert (ldstr_table, s, s);
6793 LDStrInfo ldstr_info;
6794 ldstr_info.orig_domain = domain;
6795 ldstr_info.ins = str;
6796 ldstr_info.res = NULL;
6798 mono_domain_foreach (str_lookup, &ldstr_info);
6799 if (ldstr_info.res) {
6801 * the string was already interned in some other domain:
6802 * intern it in the current one as well.
6804 mono_g_hash_table_insert (ldstr_table, str, str);
6814 * mono_string_is_interned:
6815 * @o: String to probe
6817 * Returns whether the string has been interned.
6820 mono_string_is_interned (MonoString *o)
6823 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6824 /* This function does not fail. */
6825 mono_error_assert_ok (&error);
6830 * mono_string_intern:
6831 * @o: String to intern
6833 * Interns the string passed.
6834 * Returns: The interned string.
6837 mono_string_intern (MonoString *str)
6840 MonoString *result = mono_string_intern_checked (str, &error);
6841 mono_error_assert_ok (&error);
6846 * mono_string_intern_checked:
6847 * @o: String to intern
6848 * @error: set on error.
6850 * Interns the string passed.
6851 * Returns: The interned string. On failure returns NULL and sets @error
6854 mono_string_intern_checked (MonoString *str, MonoError *error)
6856 MONO_REQ_GC_UNSAFE_MODE;
6858 mono_error_init (error);
6860 return mono_string_is_interned_lookup (str, TRUE, error);
6865 * @domain: the domain where the string will be used.
6866 * @image: a metadata context
6867 * @idx: index into the user string table.
6869 * Implementation for the ldstr opcode.
6870 * Returns: a loaded string from the @image/@idx combination.
6873 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6876 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6877 mono_error_cleanup (&error);
6882 * mono_ldstr_checked:
6883 * @domain: the domain where the string will be used.
6884 * @image: a metadata context
6885 * @idx: index into the user string table.
6886 * @error: set on error.
6888 * Implementation for the ldstr opcode.
6889 * Returns: a loaded string from the @image/@idx combination.
6890 * On failure returns NULL and sets @error.
6893 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6895 MONO_REQ_GC_UNSAFE_MODE;
6896 mono_error_init (error);
6898 if (image->dynamic) {
6899 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6902 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6903 return NULL; /*FIXME we should probably be raising an exception here*/
6904 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6910 * mono_ldstr_metadata_sig
6911 * @domain: the domain for the string
6912 * @sig: the signature of a metadata string
6913 * @error: set on error
6915 * Returns: a MonoString for a string stored in the metadata. On
6916 * failure returns NULL and sets @error.
6919 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6921 MONO_REQ_GC_UNSAFE_MODE;
6923 mono_error_init (error);
6924 const char *str = sig;
6925 MonoString *o, *interned;
6928 len2 = mono_metadata_decode_blob_size (str, &str);
6931 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6932 return_val_if_nok (error, NULL);
6933 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6936 guint16 *p2 = (guint16*)mono_string_chars (o);
6937 for (i = 0; i < len2; ++i) {
6938 *p2 = GUINT16_FROM_LE (*p2);
6944 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6947 return interned; /* o will get garbage collected */
6949 o = mono_string_get_pinned (o, error);
6952 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6954 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6966 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6970 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6976 GError *gerror = NULL;
6978 mono_error_init (error);
6980 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6981 return NULL; /*FIXME we should probably be raising an exception here*/
6982 str = mono_metadata_user_string (image, idx);
6984 len2 = mono_metadata_decode_blob_size (str, &str);
6987 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
6989 mono_error_set_argument (error, "string", "%s", gerror->message);
6990 g_error_free (gerror);
6993 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6994 if (len2 > written) {
6995 /* allocate the total length and copy the part of the string that has been converted */
6996 char *as2 = (char *)g_malloc0 (len2);
6997 memcpy (as2, as, written);
7006 * mono_string_to_utf8:
7007 * @s: a System.String
7009 * Returns the UTF8 representation for @s.
7010 * The resulting buffer needs to be freed with mono_free().
7012 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7015 mono_string_to_utf8 (MonoString *s)
7017 MONO_REQ_GC_UNSAFE_MODE;
7020 char *result = mono_string_to_utf8_checked (s, &error);
7022 if (!is_ok (&error)) {
7023 mono_error_cleanup (&error);
7030 * mono_string_to_utf8_checked:
7031 * @s: a System.String
7032 * @error: a MonoError.
7034 * Converts a MonoString to its UTF8 representation. May fail; check
7035 * @error to determine whether the conversion was successful.
7036 * The resulting buffer should be freed with mono_free().
7039 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7041 MONO_REQ_GC_UNSAFE_MODE;
7045 GError *gerror = NULL;
7047 mono_error_init (error);
7053 return g_strdup ("");
7055 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7057 mono_error_set_argument (error, "string", "%s", gerror->message);
7058 g_error_free (gerror);
7061 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7062 if (s->length > written) {
7063 /* allocate the total length and copy the part of the string that has been converted */
7064 char *as2 = (char *)g_malloc0 (s->length);
7065 memcpy (as2, as, written);
7074 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7076 return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7080 * mono_string_to_utf8_ignore:
7083 * Converts a MonoString to its UTF8 representation. Will ignore
7084 * invalid surrogate pairs.
7085 * The resulting buffer should be freed with mono_free().
7089 mono_string_to_utf8_ignore (MonoString *s)
7091 MONO_REQ_GC_UNSAFE_MODE;
7100 return g_strdup ("");
7102 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7104 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7105 if (s->length > written) {
7106 /* allocate the total length and copy the part of the string that has been converted */
7107 char *as2 = (char *)g_malloc0 (s->length);
7108 memcpy (as2, as, written);
7117 * mono_string_to_utf8_image_ignore:
7118 * @s: a System.String
7120 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7123 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7125 MONO_REQ_GC_UNSAFE_MODE;
7127 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7131 * mono_string_to_utf8_mp_ignore:
7132 * @s: a System.String
7134 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7137 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7139 MONO_REQ_GC_UNSAFE_MODE;
7141 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7146 * mono_string_to_utf16:
7149 * Return an null-terminated array of the utf-16 chars
7150 * contained in @s. The result must be freed with g_free().
7151 * This is a temporary helper until our string implementation
7152 * is reworked to always include the null terminating char.
7155 mono_string_to_utf16 (MonoString *s)
7157 MONO_REQ_GC_UNSAFE_MODE;
7164 as = (char *)g_malloc ((s->length * 2) + 2);
7165 as [(s->length * 2)] = '\0';
7166 as [(s->length * 2) + 1] = '\0';
7169 return (gunichar2 *)(as);
7172 memcpy (as, mono_string_chars(s), s->length * 2);
7173 return (gunichar2 *)(as);
7177 * mono_string_to_utf32:
7180 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7181 * contained in @s. The result must be freed with g_free().
7184 mono_string_to_utf32 (MonoString *s)
7186 MONO_REQ_GC_UNSAFE_MODE;
7188 mono_unichar4 *utf32_output = NULL;
7189 GError *error = NULL;
7190 glong items_written;
7195 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7198 g_error_free (error);
7200 return utf32_output;
7204 * mono_string_from_utf16:
7205 * @data: the UTF16 string (LPWSTR) to convert
7207 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7209 * Returns: a MonoString.
7212 mono_string_from_utf16 (gunichar2 *data)
7215 MonoString *result = mono_string_from_utf16_checked (data, &error);
7216 mono_error_cleanup (&error);
7221 * mono_string_from_utf16_checked:
7222 * @data: the UTF16 string (LPWSTR) to convert
7223 * @error: set on error
7225 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7227 * Returns: a MonoString. On failure sets @error and returns NULL.
7230 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7233 MONO_REQ_GC_UNSAFE_MODE;
7235 mono_error_init (error);
7236 MonoDomain *domain = mono_domain_get ();
7242 while (data [len]) len++;
7244 return mono_string_new_utf16_checked (domain, data, len, error);
7248 * mono_string_from_utf32:
7249 * @data: the UTF32 string (LPWSTR) to convert
7251 * Converts a UTF32 (UCS-4)to a MonoString.
7253 * Returns: a MonoString.
7256 mono_string_from_utf32 (mono_unichar4 *data)
7259 MonoString *result = mono_string_from_utf32_checked (data, &error);
7260 mono_error_cleanup (&error);
7265 * mono_string_from_utf32_checked:
7266 * @data: the UTF32 string (LPWSTR) to convert
7267 * @error: set on error
7269 * Converts a UTF32 (UCS-4)to a MonoString.
7271 * Returns: a MonoString. On failure returns NULL and sets @error.
7274 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7276 MONO_REQ_GC_UNSAFE_MODE;
7278 mono_error_init (error);
7279 MonoString* result = NULL;
7280 mono_unichar2 *utf16_output = NULL;
7281 GError *gerror = NULL;
7282 glong items_written;
7288 while (data [len]) len++;
7290 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7293 g_error_free (gerror);
7295 result = mono_string_from_utf16_checked (utf16_output, error);
7296 g_free (utf16_output);
7301 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7303 MONO_REQ_GC_UNSAFE_MODE;
7310 r = mono_string_to_utf8_ignore (s);
7312 r = mono_string_to_utf8_checked (s, error);
7313 if (!mono_error_ok (error))
7320 len = strlen (r) + 1;
7322 mp_s = (char *)mono_mempool_alloc (mp, len);
7324 mp_s = (char *)mono_image_alloc (image, len);
7326 memcpy (mp_s, r, len);
7334 * mono_string_to_utf8_image:
7335 * @s: a System.String
7337 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7340 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7342 MONO_REQ_GC_UNSAFE_MODE;
7344 return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7348 * mono_string_to_utf8_mp:
7349 * @s: a System.String
7351 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7354 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7356 MONO_REQ_GC_UNSAFE_MODE;
7358 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7362 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7365 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7367 eh_callbacks = *cbs;
7370 MonoRuntimeExceptionHandlingCallbacks *
7371 mono_get_eh_callbacks (void)
7373 return &eh_callbacks;
7377 * mono_raise_exception:
7378 * @ex: exception object
7380 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7383 mono_raise_exception (MonoException *ex)
7385 MONO_REQ_GC_UNSAFE_MODE;
7388 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7389 * that will cause gcc to omit the function epilog, causing problems when
7390 * the JIT tries to walk the stack, since the return address on the stack
7391 * will point into the next function in the executable, not this one.
7393 eh_callbacks.mono_raise_exception (ex);
7397 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7399 MONO_REQ_GC_UNSAFE_MODE;
7401 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7405 * mono_wait_handle_new:
7406 * @domain: Domain where the object will be created
7407 * @handle: Handle for the wait handle
7408 * @error: set on error.
7410 * Returns: A new MonoWaitHandle created in the given domain for the
7411 * given handle. On failure returns NULL and sets @rror.
7414 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7416 MONO_REQ_GC_UNSAFE_MODE;
7418 MonoWaitHandle *res;
7419 gpointer params [1];
7420 static MonoMethod *handle_set;
7422 mono_error_init (error);
7423 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7424 return_val_if_nok (error, NULL);
7426 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7428 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7430 params [0] = &handle;
7432 mono_runtime_invoke_checked (handle_set, res, params, error);
7437 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7439 MONO_REQ_GC_UNSAFE_MODE;
7441 static MonoClassField *f_safe_handle = NULL;
7444 if (!f_safe_handle) {
7445 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7446 g_assert (f_safe_handle);
7449 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7455 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7457 MONO_REQ_GC_UNSAFE_MODE;
7459 RuntimeInvokeFunction runtime_invoke;
7461 mono_error_init (error);
7463 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7464 MonoMethod *method = mono_get_context_capture_method ();
7465 MonoMethod *wrapper;
7468 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7469 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7470 return_val_if_nok (error, NULL);
7471 domain->capture_context_method = mono_compile_method_checked (method, error);
7472 return_val_if_nok (error, NULL);
7475 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7477 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7480 * mono_async_result_new:
7481 * @domain:domain where the object will be created.
7482 * @handle: wait handle.
7483 * @state: state to pass to AsyncResult
7484 * @data: C closure data.
7485 * @error: set on error.
7487 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7488 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7489 * On failure returns NULL and sets @error.
7493 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7495 MONO_REQ_GC_UNSAFE_MODE;
7497 mono_error_init (error);
7498 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7499 return_val_if_nok (error, NULL);
7500 MonoObject *context = mono_runtime_capture_context (domain, error);
7501 return_val_if_nok (error, NULL);
7502 /* we must capture the execution context from the original thread */
7504 MONO_OBJECT_SETREF (res, execution_context, context);
7505 /* note: result may be null if the flow is suppressed */
7508 res->data = (void **)data;
7509 MONO_OBJECT_SETREF (res, object_data, object_data);
7510 MONO_OBJECT_SETREF (res, async_state, state);
7511 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7512 return_val_if_nok (error, NULL);
7514 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7516 res->sync_completed = FALSE;
7517 res->completed = FALSE;
7523 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7525 MONO_REQ_GC_UNSAFE_MODE;
7532 g_assert (ares->async_delegate);
7534 ac = (MonoAsyncCall*) ares->object_data;
7536 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7537 if (mono_error_set_pending_exception (&error))
7540 gpointer wait_event = NULL;
7542 ac->msg->exc = NULL;
7544 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7546 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7547 mono_threads_begin_abort_protected_block ();
7549 if (!ac->msg->exc) {
7550 MonoException *ex = mono_error_convert_to_exception (&error);
7551 ac->msg->exc = (MonoObject *)ex;
7553 mono_error_cleanup (&error);
7556 MONO_OBJECT_SETREF (ac, res, res);
7558 mono_monitor_enter ((MonoObject*) ares);
7559 ares->completed = 1;
7561 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7562 mono_monitor_exit ((MonoObject*) ares);
7564 if (wait_event != NULL)
7565 mono_w32event_set (wait_event);
7567 mono_error_init (&error); //the else branch would leave it in an undefined state
7569 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7571 mono_threads_end_abort_protected_block ();
7573 if (mono_error_set_pending_exception (&error))
7581 mono_message_init (MonoDomain *domain,
7582 MonoMethodMessage *this_obj,
7583 MonoReflectionMethod *method,
7584 MonoArray *out_args,
7587 MONO_REQ_GC_UNSAFE_MODE;
7589 static MonoMethod *init_message_method = NULL;
7591 if (!init_message_method) {
7592 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7593 g_assert (init_message_method != NULL);
7596 mono_error_init (error);
7597 /* FIXME set domain instead? */
7598 g_assert (domain == mono_domain_get ());
7605 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7606 return is_ok (error);
7609 #ifndef DISABLE_REMOTING
7611 * mono_remoting_invoke:
7612 * @real_proxy: pointer to a RealProxy object
7613 * @msg: The MonoMethodMessage to execute
7614 * @exc: used to store exceptions
7615 * @out_args: used to store output arguments
7617 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7618 * IMessage interface and it is not trivial to extract results from there. So
7619 * we call an helper method PrivateInvoke instead of calling
7620 * RealProxy::Invoke() directly.
7622 * Returns: the result object.
7625 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7627 MONO_REQ_GC_UNSAFE_MODE;
7630 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7635 mono_error_init (error);
7637 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7640 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7642 mono_error_set_not_supported (error, "Linked away.");
7645 real_proxy->vtable->domain->private_invoke_method = im;
7648 pa [0] = real_proxy;
7653 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7654 return_val_if_nok (error, NULL);
7661 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7662 MonoObject **exc, MonoArray **out_args, MonoError *error)
7664 MONO_REQ_GC_UNSAFE_MODE;
7666 static MonoClass *object_array_klass;
7667 mono_error_init (error);
7671 MonoMethodSignature *sig;
7673 int i, j, outarg_count = 0;
7675 #ifndef DISABLE_REMOTING
7676 if (target && mono_object_is_transparent_proxy (target)) {
7677 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7678 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7679 target = tp->rp->unwrapped_server;
7681 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7686 domain = mono_domain_get ();
7687 method = msg->method->method;
7688 sig = mono_method_signature (method);
7690 for (i = 0; i < sig->param_count; i++) {
7691 if (sig->params [i]->byref)
7695 if (!object_array_klass) {
7698 klass = mono_array_class_get (mono_defaults.object_class, 1);
7701 mono_memory_barrier ();
7702 object_array_klass = klass;
7705 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7706 return_val_if_nok (error, NULL);
7708 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7711 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7712 return_val_if_nok (error, NULL);
7714 for (i = 0, j = 0; i < sig->param_count; i++) {
7715 if (sig->params [i]->byref) {
7717 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7718 mono_array_setref (*out_args, j, arg);
7727 * prepare_to_string_method:
7729 * @target: Set to @obj or unboxed value if a valuetype
7731 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7734 prepare_to_string_method (MonoObject *obj, void **target)
7736 MONO_REQ_GC_UNSAFE_MODE;
7738 static MonoMethod *to_string = NULL;
7746 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7748 method = mono_object_get_virtual_method (obj, to_string);
7750 // Unbox value type if needed
7751 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7752 *target = mono_object_unbox (obj);
7758 * mono_object_to_string:
7760 * @exc: Any exception thrown by ToString (). May be NULL.
7762 * Returns: the result of calling ToString () on an object.
7765 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7768 MonoString *s = NULL;
7770 MonoMethod *method = prepare_to_string_method (obj, &target);
7772 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7773 if (*exc == NULL && !mono_error_ok (&error))
7774 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7776 mono_error_cleanup (&error);
7778 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7779 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7786 * mono_object_to_string_checked:
7788 * @error: Set on error.
7790 * Returns: the result of calling ToString () on an object. If the
7791 * method cannot be invoked or if it raises an exception, sets @error
7795 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7797 mono_error_init (error);
7799 MonoMethod *method = prepare_to_string_method (obj, &target);
7800 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7804 * mono_object_try_to_string:
7806 * @exc: Any exception thrown by ToString (). Must not be NULL.
7807 * @error: Set if method cannot be invoked.
7809 * Returns: the result of calling ToString () on an object. If the
7810 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7814 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7817 mono_error_init (error);
7819 MonoMethod *method = prepare_to_string_method (obj, &target);
7820 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7826 get_native_backtrace (MonoException *exc_raw)
7828 HANDLE_FUNCTION_ENTER ();
7829 MONO_HANDLE_DCL(MonoException, exc);
7830 char * trace = mono_exception_handle_get_native_backtrace (exc);
7831 HANDLE_FUNCTION_RETURN_VAL (trace);
7835 * mono_print_unhandled_exception:
7836 * @exc: The exception
7838 * Prints the unhandled exception.
7841 mono_print_unhandled_exception (MonoObject *exc)
7843 MONO_REQ_GC_UNSAFE_MODE;
7846 char *message = (char*)"";
7847 gboolean free_message = FALSE;
7850 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7851 message = g_strdup ("OutOfMemoryException");
7852 free_message = TRUE;
7853 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7854 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7855 free_message = TRUE;
7858 if (((MonoException*)exc)->native_trace_ips) {
7859 message = get_native_backtrace ((MonoException*)exc);
7860 free_message = TRUE;
7862 MonoObject *other_exc = NULL;
7863 str = mono_object_try_to_string (exc, &other_exc, &error);
7864 if (other_exc == NULL && !is_ok (&error))
7865 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7867 mono_error_cleanup (&error);
7869 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7870 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7872 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7873 original_backtrace, nested_backtrace);
7875 g_free (original_backtrace);
7876 g_free (nested_backtrace);
7877 free_message = TRUE;
7879 message = mono_string_to_utf8_checked (str, &error);
7880 if (!mono_error_ok (&error)) {
7881 mono_error_cleanup (&error);
7882 message = (char *) "";
7884 free_message = TRUE;
7891 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7892 * exc->vtable->klass->name, message);
7894 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7901 * mono_delegate_ctor_with_method:
7902 * @this: pointer to an uninitialized delegate object
7903 * @target: target object
7904 * @addr: pointer to native code
7906 * @error: set on error.
7908 * Initialize a delegate and sets a specific method, not the one
7909 * associated with addr. This is useful when sharing generic code.
7910 * In that case addr will most probably not be associated with the
7911 * correct instantiation of the method.
7912 * On failure returns FALSE and sets @error.
7915 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7917 MONO_REQ_GC_UNSAFE_MODE;
7919 mono_error_init (error);
7920 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7922 g_assert (this_obj);
7925 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7928 delegate->method = method;
7930 mono_stats.delegate_creations++;
7932 #ifndef DISABLE_REMOTING
7933 if (target && mono_object_is_transparent_proxy (target)) {
7935 method = mono_marshal_get_remoting_invoke (method);
7936 delegate->method_ptr = mono_compile_method_checked (method, error);
7937 return_val_if_nok (error, FALSE);
7938 MONO_OBJECT_SETREF (delegate, target, target);
7942 delegate->method_ptr = addr;
7943 MONO_OBJECT_SETREF (delegate, target, target);
7946 delegate->invoke_impl = callbacks.create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7947 if (callbacks.init_delegate)
7948 callbacks.init_delegate (delegate);
7953 * mono_delegate_ctor:
7954 * @this: pointer to an uninitialized delegate object
7955 * @target: target object
7956 * @addr: pointer to native code
7957 * @error: set on error.
7959 * This is used to initialize a delegate.
7960 * On failure returns FALSE and sets @error.
7963 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7965 MONO_REQ_GC_UNSAFE_MODE;
7967 mono_error_init (error);
7968 MonoDomain *domain = mono_domain_get ();
7970 MonoMethod *method = NULL;
7974 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7976 if (!ji && domain != mono_get_root_domain ())
7977 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7979 method = mono_jit_info_get_method (ji);
7980 g_assert (!mono_class_is_gtd (method->klass));
7983 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7987 * mono_method_call_message_new:
7988 * @method: method to encapsulate
7989 * @params: parameters to the method
7990 * @invoke: optional, delegate invoke.
7991 * @cb: async callback delegate.
7992 * @state: state passed to the async callback.
7993 * @error: set on error.
7995 * Translates arguments pointers into a MonoMethodMessage.
7996 * On failure returns NULL and sets @error.
7999 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
8000 MonoDelegate **cb, MonoObject **state, MonoError *error)
8002 MONO_REQ_GC_UNSAFE_MODE;
8004 mono_error_init (error);
8006 MonoDomain *domain = mono_domain_get ();
8007 MonoMethodSignature *sig = mono_method_signature (method);
8008 MonoMethodMessage *msg;
8011 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8012 return_val_if_nok (error, NULL);
8015 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8016 return_val_if_nok (error, NULL);
8017 mono_message_init (domain, msg, rm, NULL, error);
8018 return_val_if_nok (error, NULL);
8019 count = sig->param_count - 2;
8021 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8022 return_val_if_nok (error, NULL);
8023 mono_message_init (domain, msg, rm, NULL, error);
8024 return_val_if_nok (error, NULL);
8025 count = sig->param_count;
8028 for (i = 0; i < count; i++) {
8033 if (sig->params [i]->byref)
8034 vpos = *((gpointer *)params [i]);
8038 klass = mono_class_from_mono_type (sig->params [i]);
8040 if (klass->valuetype) {
8041 arg = mono_value_box_checked (domain, klass, vpos, error);
8042 return_val_if_nok (error, NULL);
8044 arg = *((MonoObject **)vpos);
8046 mono_array_setref (msg->args, i, arg);
8049 if (cb != NULL && state != NULL) {
8050 *cb = *((MonoDelegate **)params [i]);
8052 *state = *((MonoObject **)params [i]);
8059 * mono_method_return_message_restore:
8061 * Restore results from message based processing back to arguments pointers
8064 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8066 MONO_REQ_GC_UNSAFE_MODE;
8068 mono_error_init (error);
8070 MonoMethodSignature *sig = mono_method_signature (method);
8071 int i, j, type, size, out_len;
8073 if (out_args == NULL)
8075 out_len = mono_array_length (out_args);
8079 for (i = 0, j = 0; i < sig->param_count; i++) {
8080 MonoType *pt = sig->params [i];
8085 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8089 arg = (char *)mono_array_get (out_args, gpointer, j);
8092 g_assert (type != MONO_TYPE_VOID);
8094 if (MONO_TYPE_IS_REFERENCE (pt)) {
8095 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8098 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8099 size = mono_class_value_size (klass, NULL);
8100 if (klass->has_references)
8101 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8103 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8105 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8106 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8115 #ifndef DISABLE_REMOTING
8118 * mono_load_remote_field:
8119 * @this: pointer to an object
8120 * @klass: klass of the object containing @field
8121 * @field: the field to load
8122 * @res: a storage to store the result
8124 * This method is called by the runtime on attempts to load fields of
8125 * transparent proxy objects. @this points to such TP, @klass is the class of
8126 * the object containing @field. @res is a storage location which can be
8127 * used to store the result.
8129 * Returns: an address pointing to the value of field.
8132 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8135 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8136 mono_error_cleanup (&error);
8141 * mono_load_remote_field_checked:
8142 * @this: pointer to an object
8143 * @klass: klass of the object containing @field
8144 * @field: the field to load
8145 * @res: a storage to store the result
8146 * @error: set on error
8148 * This method is called by the runtime on attempts to load fields of
8149 * transparent proxy objects. @this points to such TP, @klass is the class of
8150 * the object containing @field. @res is a storage location which can be
8151 * used to store the result.
8153 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8156 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8158 MONO_REQ_GC_UNSAFE_MODE;
8160 static MonoMethod *getter = NULL;
8162 mono_error_init (error);
8164 MonoDomain *domain = mono_domain_get ();
8165 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8166 MonoClass *field_class;
8167 MonoMethodMessage *msg;
8168 MonoArray *out_args;
8172 g_assert (mono_object_is_transparent_proxy (this_obj));
8173 g_assert (res != NULL);
8175 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8176 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8181 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8183 mono_error_set_not_supported (error, "Linked away.");
8188 field_class = mono_class_from_mono_type (field->type);
8190 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8191 return_val_if_nok (error, NULL);
8192 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8193 return_val_if_nok (error, NULL);
8194 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8195 return_val_if_nok (error, NULL);
8196 mono_message_init (domain, msg, rm, out_args, error);
8197 return_val_if_nok (error, NULL);
8199 full_name = mono_type_get_full_name (klass);
8200 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8201 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8204 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8205 return_val_if_nok (error, NULL);
8208 mono_error_set_exception_instance (error, (MonoException *)exc);
8212 if (mono_array_length (out_args) == 0)
8215 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8217 if (field_class->valuetype) {
8218 return ((char *)*res) + sizeof (MonoObject);
8224 * mono_load_remote_field_new:
8229 * Missing documentation.
8232 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8236 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8237 mono_error_cleanup (&error);
8242 * mono_load_remote_field_new_checked:
8243 * @this: pointer to an object
8244 * @klass: klass of the object containing @field
8245 * @field: the field to load
8246 * @error: set on error.
8248 * This method is called by the runtime on attempts to load fields of
8249 * transparent proxy objects. @this points to such TP, @klass is the class of
8250 * the object containing @field.
8252 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8255 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8257 MONO_REQ_GC_UNSAFE_MODE;
8259 mono_error_init (error);
8261 static MonoMethod *tp_load = NULL;
8263 g_assert (mono_object_is_transparent_proxy (this_obj));
8266 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8268 mono_error_set_not_supported (error, "Linked away.");
8273 /* MonoType *type = mono_class_get_type (klass); */
8279 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8283 * mono_store_remote_field:
8284 * @this_obj: pointer to an object
8285 * @klass: klass of the object containing @field
8286 * @field: the field to load
8287 * @val: the value/object to store
8289 * This method is called by the runtime on attempts to store fields of
8290 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8291 * the object containing @field. @val is the new value to store in @field.
8294 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8297 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8298 mono_error_cleanup (&error);
8302 * mono_store_remote_field_checked:
8303 * @this_obj: pointer to an object
8304 * @klass: klass of the object containing @field
8305 * @field: the field to load
8306 * @val: the value/object to store
8307 * @error: set on error
8309 * This method is called by the runtime on attempts to store fields of
8310 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8311 * the object containing @field. @val is the new value to store in @field.
8313 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8316 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8319 MONO_REQ_GC_UNSAFE_MODE;
8321 mono_error_init (error);
8323 MonoDomain *domain = mono_domain_get ();
8324 MonoClass *field_class;
8327 g_assert (mono_object_is_transparent_proxy (this_obj));
8329 field_class = mono_class_from_mono_type (field->type);
8331 if (field_class->valuetype) {
8332 arg = mono_value_box_checked (domain, field_class, val, error);
8333 return_val_if_nok (error, FALSE);
8335 arg = *((MonoObject**)val);
8338 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8342 * mono_store_remote_field_new:
8348 * Missing documentation
8351 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8354 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8355 mono_error_cleanup (&error);
8359 * mono_store_remote_field_new_checked:
8366 * Missing documentation
8369 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8371 MONO_REQ_GC_UNSAFE_MODE;
8373 static MonoMethod *tp_store = NULL;
8375 mono_error_init (error);
8377 g_assert (mono_object_is_transparent_proxy (this_obj));
8380 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8382 mono_error_set_not_supported (error, "Linked away.");
8392 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8393 return is_ok (error);
8398 * mono_create_ftnptr:
8400 * Given a function address, create a function descriptor for it.
8401 * This is only needed on some platforms.
8404 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8406 return callbacks.create_ftnptr (domain, addr);
8410 * mono_get_addr_from_ftnptr:
8412 * Given a pointer to a function descriptor, return the function address.
8413 * This is only needed on some platforms.
8416 mono_get_addr_from_ftnptr (gpointer descr)
8418 return callbacks.get_addr_from_ftnptr (descr);
8422 * mono_string_chars:
8425 * Returns a pointer to the UCS16 characters stored in the MonoString
8428 mono_string_chars (MonoString *s)
8430 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8436 * mono_string_length:
8439 * Returns the lenght in characters of the string
8442 mono_string_length (MonoString *s)
8444 MONO_REQ_GC_UNSAFE_MODE;
8450 * mono_string_handle_length:
8453 * Returns the lenght in characters of the string
8456 mono_string_handle_length (MonoStringHandle s)
8458 MONO_REQ_GC_UNSAFE_MODE;
8460 return MONO_HANDLE_GETVAL (s, length);
8465 * mono_array_length:
8466 * @array: a MonoArray*
8468 * Returns the total number of elements in the array. This works for
8469 * both vectors and multidimensional arrays.
8472 mono_array_length (MonoArray *array)
8474 MONO_REQ_GC_UNSAFE_MODE;
8476 return array->max_length;
8480 * mono_array_addr_with_size:
8481 * @array: a MonoArray*
8482 * @size: size of the array elements
8483 * @idx: index into the array
8485 * Use this function to obtain the address for the @idx item on the
8486 * @array containing elements of size @size.
8488 * This method performs no bounds checking or type checking.
8490 * Returns the address of the @idx element in the array.
8493 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8495 MONO_REQ_GC_UNSAFE_MODE;
8497 return ((char*)(array)->vector) + size * idx;
8502 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8504 MonoDomain *domain = mono_domain_get ();
8508 mono_error_init (error);
8512 len = g_list_length (list);
8513 res = mono_array_new_checked (domain, eclass, len, error);
8514 return_val_if_nok (error, NULL);
8516 for (i = 0; list; list = list->next, i++)
8517 mono_array_set (res, gpointer, i, list->data);
8524 * The following section is purely to declare prototypes and
8525 * document the API, as these C files are processed by our
8531 * @array: array to alter
8532 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8533 * @index: index into the array
8534 * @value: value to set
8536 * Value Type version: This sets the @index's element of the @array
8537 * with elements of size sizeof(type) to the provided @value.
8539 * This macro does not attempt to perform type checking or bounds checking.
8541 * Use this to set value types in a `MonoArray`.
8543 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8548 * mono_array_setref:
8549 * @array: array to alter
8550 * @index: index into the array
8551 * @value: value to set
8553 * Reference Type version: This sets the @index's element of the
8554 * @array with elements of size sizeof(type) to the provided @value.
8556 * This macro does not attempt to perform type checking or bounds checking.
8558 * Use this to reference types in a `MonoArray`.
8560 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8566 * @array: array on which to operate on
8567 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8568 * @index: index into the array
8570 * Use this macro to retrieve the @index element of an @array and
8571 * extract the value assuming that the elements of the array match
8572 * the provided type value.
8574 * This method can be used with both arrays holding value types and
8575 * reference types. For reference types, the @type parameter should
8576 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8578 * This macro does not attempt to perform type checking or bounds checking.
8580 * Returns: The element at the @index position in the @array.
8582 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)