2 * object.c: Object creation for the Mono runtime
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
8 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
10 * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/tabledefs.h>
22 #include <mono/metadata/tokentype.h>
23 #include <mono/metadata/loader.h>
24 #include <mono/metadata/object.h>
25 #include <mono/metadata/gc-internals.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/domain-internals.h>
29 #include "mono/metadata/metadata-internals.h"
30 #include "mono/metadata/class-internals.h"
31 #include <mono/metadata/assembly.h>
32 #include <mono/metadata/marshal.h>
33 #include "mono/metadata/debug-helpers.h"
34 #include "mono/metadata/marshal.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include "mono/metadata/mono-debug-debugger.h"
41 #include <mono/metadata/gc-internals.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/reflection-internals.h>
44 #include <mono/utils/strenc.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-memory-model.h>
48 #include <mono/utils/checked-build.h>
49 #include <mono/utils/mono-threads.h>
50 #include "cominterop.h"
53 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
56 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
59 free_main_args (void);
62 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
64 /* Class lazy loading functions */
65 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
66 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
67 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
68 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
69 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
72 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
73 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
74 static mono_mutex_t ldstr_section;
77 * mono_runtime_object_init:
78 * @this_obj: the object to initialize
80 * This function calls the zero-argument constructor (which must
81 * exist) for the given object.
84 mono_runtime_object_init (MonoObject *this_obj)
87 mono_runtime_object_init_checked (this_obj, &error);
88 mono_error_assert_ok (&error);
92 * mono_runtime_object_init_checked:
93 * @this_obj: the object to initialize
94 * @error: set on error.
96 * This function calls the zero-argument constructor (which must
97 * exist) for the given object and returns TRUE on success, or FALSE
98 * on error and sets @error.
101 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
103 MONO_REQ_GC_UNSAFE_MODE;
105 MonoMethod *method = NULL;
106 MonoClass *klass = this_obj->vtable->klass;
108 mono_error_init (error);
109 method = mono_class_get_method_from_name (klass, ".ctor", 0);
111 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
113 if (method->klass->valuetype)
114 this_obj = (MonoObject *)mono_object_unbox (this_obj);
116 mono_runtime_invoke_checked (method, this_obj, NULL, error);
117 return is_ok (error);
120 /* The pseudo algorithm for type initialization from the spec
121 Note it doesn't say anything about domains - only threads.
123 2. If the type is initialized you are done.
124 2.1. If the type is not yet initialized, try to take an
126 2.2. If successful, record this thread as responsible for
127 initializing the type and proceed to step 2.3.
128 2.2.1. If not, see whether this thread or any thread
129 waiting for this thread to complete already holds the lock.
130 2.2.2. If so, return since blocking would create a deadlock. This thread
131 will now see an incompletely initialized state for the type,
132 but no deadlock will arise.
133 2.2.3 If not, block until the type is initialized then return.
134 2.3 Initialize the parent type and then all interfaces implemented
136 2.4 Execute the type initialization code for this type.
137 2.5 Mark the type as initialized, release the initialization lock,
138 awaken any threads waiting for this type to be initialized,
145 MonoNativeThreadId initializing_tid;
146 guint32 waiting_count;
148 MonoCoopMutex initialization_section;
149 } TypeInitializationLock;
151 /* for locking access to type_initialization_hash and blocked_thread_hash */
152 static MonoCoopMutex type_initialization_section;
155 mono_type_initialization_lock (void)
157 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
158 mono_coop_mutex_lock (&type_initialization_section);
162 mono_type_initialization_unlock (void)
164 mono_coop_mutex_unlock (&type_initialization_section);
168 mono_type_init_lock (TypeInitializationLock *lock)
170 MONO_REQ_GC_NEUTRAL_MODE;
172 mono_coop_mutex_lock (&lock->initialization_section);
176 mono_type_init_unlock (TypeInitializationLock *lock)
178 mono_coop_mutex_unlock (&lock->initialization_section);
181 /* from vtable to lock */
182 static GHashTable *type_initialization_hash;
184 /* from thread id to thread id being waited on */
185 static GHashTable *blocked_thread_hash;
188 static MonoThread *main_thread;
190 /* Functions supplied by the runtime */
191 static MonoRuntimeCallbacks callbacks;
194 * mono_thread_set_main:
195 * @thread: thread to set as the main thread
197 * This function can be used to instruct the runtime to treat @thread
198 * as the main thread, ie, the thread that would normally execute the Main()
199 * method. This basically means that at the end of @thread, the runtime will
200 * wait for the existing foreground threads to quit and other such details.
203 mono_thread_set_main (MonoThread *thread)
205 MONO_REQ_GC_UNSAFE_MODE;
207 static gboolean registered = FALSE;
210 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
214 main_thread = thread;
218 mono_thread_get_main (void)
220 MONO_REQ_GC_UNSAFE_MODE;
226 mono_type_initialization_init (void)
228 mono_coop_mutex_init_recursive (&type_initialization_section);
229 type_initialization_hash = g_hash_table_new (NULL, NULL);
230 blocked_thread_hash = g_hash_table_new (NULL, NULL);
231 mono_os_mutex_init_recursive (&ldstr_section);
235 mono_type_initialization_cleanup (void)
238 /* This is causing race conditions with
239 * mono_release_type_locks
241 mono_coop_mutex_destroy (&type_initialization_section);
242 g_hash_table_destroy (type_initialization_hash);
243 type_initialization_hash = NULL;
245 mono_os_mutex_destroy (&ldstr_section);
246 g_hash_table_destroy (blocked_thread_hash);
247 blocked_thread_hash = NULL;
253 * get_type_init_exception_for_vtable:
255 * Return the stored type initialization exception for VTABLE.
257 static MonoException*
258 get_type_init_exception_for_vtable (MonoVTable *vtable)
260 MONO_REQ_GC_UNSAFE_MODE;
263 MonoDomain *domain = vtable->domain;
264 MonoClass *klass = vtable->klass;
268 if (!vtable->init_failed)
269 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
272 * If the initializing thread was rudely aborted, the exception is not stored
276 mono_domain_lock (domain);
277 if (domain->type_init_exception_hash)
278 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
279 mono_domain_unlock (domain);
282 if (klass->name_space && *klass->name_space)
283 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
285 full_name = g_strdup (klass->name);
286 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
288 return_val_if_nok (&error, NULL);
295 * mono_runtime_class_init:
296 * @vtable: vtable that needs to be initialized
298 * This routine calls the class constructor for @vtable.
301 mono_runtime_class_init (MonoVTable *vtable)
303 MONO_REQ_GC_UNSAFE_MODE;
306 mono_runtime_class_init_full (vtable, &error);
307 mono_error_assert_ok (&error);
311 * mono_runtime_class_init_full:
312 * @vtable that neeeds to be initialized
313 * @error set on error
315 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
319 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
321 MONO_REQ_GC_UNSAFE_MODE;
323 MonoMethod *method = NULL;
326 MonoDomain *domain = vtable->domain;
327 TypeInitializationLock *lock;
328 MonoNativeThreadId tid;
329 int do_initialization = 0;
330 MonoDomain *last_domain = NULL;
332 mono_error_init (error);
334 if (vtable->initialized)
337 klass = vtable->klass;
339 if (!klass->image->checked_module_cctor) {
340 mono_image_check_for_module_cctor (klass->image);
341 if (klass->image->has_module_cctor) {
342 MonoClass *module_klass;
343 MonoVTable *module_vtable;
345 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
350 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
353 if (!mono_runtime_class_init_full (module_vtable, error))
357 method = mono_class_get_cctor (klass);
359 vtable->initialized = 1;
363 tid = mono_native_thread_id_get ();
365 mono_type_initialization_lock ();
366 /* double check... */
367 if (vtable->initialized) {
368 mono_type_initialization_unlock ();
371 if (vtable->init_failed) {
372 mono_type_initialization_unlock ();
374 /* The type initialization already failed once, rethrow the same exception */
375 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
378 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
380 /* This thread will get to do the initialization */
381 if (mono_domain_get () != domain) {
382 /* Transfer into the target domain */
383 last_domain = mono_domain_get ();
384 if (!mono_domain_set (domain, FALSE)) {
385 vtable->initialized = 1;
386 mono_type_initialization_unlock ();
387 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
391 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
392 mono_coop_mutex_init_recursive (&lock->initialization_section);
393 lock->initializing_tid = tid;
394 lock->waiting_count = 1;
396 /* grab the vtable lock while this thread still owns type_initialization_section */
397 /* This is why type_initialization_lock needs to enter blocking mode */
398 mono_type_init_lock (lock);
399 g_hash_table_insert (type_initialization_hash, vtable, lock);
400 do_initialization = 1;
403 TypeInitializationLock *pending_lock;
405 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
406 mono_type_initialization_unlock ();
409 /* see if the thread doing the initialization is already blocked on this thread */
410 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
411 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
412 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
413 if (!pending_lock->done) {
414 mono_type_initialization_unlock ();
417 /* the thread doing the initialization is blocked on this thread,
418 but on a lock that has already been freed. It just hasn't got
423 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
425 ++lock->waiting_count;
426 /* record the fact that we are waiting on the initializing thread */
427 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
429 mono_type_initialization_unlock ();
431 if (do_initialization) {
432 MonoException *exc = NULL;
433 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
434 if (exc != NULL && mono_error_ok (error)) {
435 mono_error_set_exception_instance (error, exc);
438 /* If the initialization failed, mark the class as unusable. */
439 /* Avoid infinite loops */
440 if (!(mono_error_ok(error) ||
441 (klass->image == mono_defaults.corlib &&
442 !strcmp (klass->name_space, "System") &&
443 !strcmp (klass->name, "TypeInitializationException")))) {
444 vtable->init_failed = 1;
446 if (klass->name_space && *klass->name_space)
447 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
449 full_name = g_strdup (klass->name);
451 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
453 return_val_if_nok (error, FALSE);
455 mono_error_set_exception_instance (error, exc_to_throw);
457 MonoException *exc_to_store = mono_error_convert_to_exception (error);
458 /* What we really want to do here is clone the error object and store one copy in the
459 * domain's exception hash and use the other one to error out here. */
460 mono_error_init (error);
461 mono_error_set_exception_instance (error, exc_to_store);
463 * Store the exception object so it could be thrown on subsequent
466 mono_domain_lock (domain);
467 if (!domain->type_init_exception_hash)
468 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");
469 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
470 mono_domain_unlock (domain);
474 mono_domain_set (last_domain, TRUE);
476 mono_type_init_unlock (lock);
478 /* this just blocks until the initializing thread is done */
479 mono_type_init_lock (lock);
480 mono_type_init_unlock (lock);
483 mono_type_initialization_lock ();
484 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
485 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
486 --lock->waiting_count;
487 if (lock->waiting_count == 0) {
488 mono_coop_mutex_destroy (&lock->initialization_section);
489 g_hash_table_remove (type_initialization_hash, vtable);
492 mono_memory_barrier ();
493 if (!vtable->init_failed)
494 vtable->initialized = 1;
495 mono_type_initialization_unlock ();
497 if (vtable->init_failed) {
498 /* Either we were the initializing thread or we waited for the initialization */
499 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
506 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
508 MONO_REQ_GC_NEUTRAL_MODE;
510 MonoVTable *vtable = (MonoVTable*)key;
512 TypeInitializationLock *lock = (TypeInitializationLock*) value;
513 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
516 * Have to set this since it cannot be set by the normal code in
517 * mono_runtime_class_init (). In this case, the exception object is not stored,
518 * and get_type_init_exception_for_class () needs to be aware of this.
520 vtable->init_failed = 1;
521 mono_type_init_unlock (lock);
522 --lock->waiting_count;
523 if (lock->waiting_count == 0) {
524 mono_coop_mutex_destroy (&lock->initialization_section);
533 mono_release_type_locks (MonoInternalThread *thread)
535 MONO_REQ_GC_UNSAFE_MODE;
537 mono_type_initialization_lock ();
538 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
539 mono_type_initialization_unlock ();
542 #ifndef DISABLE_REMOTING
545 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
547 g_error ("remoting not installed");
551 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
555 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
557 g_assert_not_reached ();
561 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
562 static MonoImtThunkBuilder imt_thunk_builder;
563 static gboolean always_build_imt_thunks;
565 #if (MONO_IMT_SIZE > 32)
566 #error "MONO_IMT_SIZE cannot be larger than 32"
570 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
572 memcpy (&callbacks, cbs, sizeof (*cbs));
575 MonoRuntimeCallbacks*
576 mono_get_runtime_callbacks (void)
581 #ifndef DISABLE_REMOTING
583 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
585 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
590 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
592 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
596 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
597 imt_thunk_builder = func;
601 mono_set_always_build_imt_thunks (gboolean value)
603 always_build_imt_thunks = value;
607 * mono_compile_method:
608 * @method: The method to compile.
610 * This JIT-compiles the method, and returns the pointer to the native code
614 mono_compile_method (MonoMethod *method)
617 gpointer result = mono_compile_method_checked (method, &error);
618 mono_error_cleanup (&error);
623 * mono_compile_method:
624 * @method: The method to compile.
625 * @error: set on error.
627 * This JIT-compiles the method, and returns the pointer to the native code
628 * produced. On failure returns NULL and sets @error.
631 mono_compile_method_checked (MonoMethod *method, MonoError *error)
635 MONO_REQ_GC_NEUTRAL_MODE
637 mono_error_init (error);
639 if (!callbacks.compile_method) {
640 g_error ("compile method called on uninitialized runtime");
643 res = callbacks.compile_method (method, error);
648 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
652 MONO_REQ_GC_NEUTRAL_MODE;
654 mono_error_init (error);
655 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
660 mono_runtime_create_delegate_trampoline (MonoClass *klass)
662 MONO_REQ_GC_NEUTRAL_MODE
664 return arch_create_delegate_trampoline (mono_domain_get (), klass);
667 static MonoFreeMethodFunc default_mono_free_method = NULL;
670 * mono_install_free_method:
671 * @func: pointer to the MonoFreeMethodFunc used to release a method
673 * This is an internal VM routine, it is used for the engines to
674 * register a handler to release the resources associated with a method.
676 * Methods are freed when no more references to the delegate that holds
680 mono_install_free_method (MonoFreeMethodFunc func)
682 default_mono_free_method = func;
686 * mono_runtime_free_method:
687 * @domain; domain where the method is hosted
688 * @method: method to release
690 * This routine is invoked to free the resources associated with
691 * a method that has been JIT compiled. This is used to discard
692 * methods that were used only temporarily (for example, used in marshalling)
696 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
698 MONO_REQ_GC_NEUTRAL_MODE
700 if (default_mono_free_method != NULL)
701 default_mono_free_method (domain, method);
703 mono_method_clear_object (domain, method);
705 mono_free_method (method);
709 * The vtables in the root appdomain are assumed to be reachable by other
710 * roots, and we don't use typed allocation in the other domains.
713 /* The sync block is no longer a GC pointer */
714 #define GC_HEADER_BITMAP (0)
716 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
719 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
721 MONO_REQ_GC_NEUTRAL_MODE;
723 MonoClassField *field;
729 max_size = mono_class_data_size (klass) / sizeof (gpointer);
731 max_size = klass->instance_size / sizeof (gpointer);
732 if (max_size > size) {
733 g_assert (offset <= 0);
734 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
739 /*An Ephemeron cannot be marked by sgen*/
740 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
742 memset (bitmap, 0, size / 8);
747 for (p = klass; p != NULL; p = p->parent) {
748 gpointer iter = NULL;
749 while ((field = mono_class_get_fields (p, &iter))) {
753 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
755 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
758 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
761 /* FIXME: should not happen, flag as type load error */
762 if (field->type->byref)
765 if (static_fields && field->offset == -1)
769 pos = field->offset / sizeof (gpointer);
772 type = mono_type_get_underlying_type (field->type);
773 switch (type->type) {
776 case MONO_TYPE_FNPTR:
778 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
783 if (klass->image != mono_defaults.corlib)
786 case MONO_TYPE_STRING:
787 case MONO_TYPE_SZARRAY:
788 case MONO_TYPE_CLASS:
789 case MONO_TYPE_OBJECT:
790 case MONO_TYPE_ARRAY:
791 g_assert ((field->offset % sizeof(gpointer)) == 0);
793 g_assert (pos < size || pos <= max_size);
794 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
795 *max_set = MAX (*max_set, pos);
797 case MONO_TYPE_GENERICINST:
798 if (!mono_type_generic_inst_is_valuetype (type)) {
799 g_assert ((field->offset % sizeof(gpointer)) == 0);
801 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
802 *max_set = MAX (*max_set, pos);
807 case MONO_TYPE_VALUETYPE: {
808 MonoClass *fclass = mono_class_from_mono_type (field->type);
809 if (fclass->has_references) {
810 /* remove the object header */
811 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
825 case MONO_TYPE_BOOLEAN:
829 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
840 * mono_class_compute_bitmap:
842 * Mono internal function to compute a bitmap of reference fields in a class.
845 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
847 MONO_REQ_GC_NEUTRAL_MODE;
849 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
854 * similar to the above, but sets the bits in the bitmap for any non-ref field
855 * and ignores static fields
858 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
860 MonoClassField *field;
865 max_size = class->instance_size / sizeof (gpointer);
866 if (max_size >= size) {
867 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
870 for (p = class; p != NULL; p = p->parent) {
871 gpointer iter = NULL;
872 while ((field = mono_class_get_fields (p, &iter))) {
875 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
877 /* FIXME: should not happen, flag as type load error */
878 if (field->type->byref)
881 pos = field->offset / sizeof (gpointer);
884 type = mono_type_get_underlying_type (field->type);
885 switch (type->type) {
886 #if SIZEOF_VOID_P == 8
890 case MONO_TYPE_FNPTR:
895 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
896 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
897 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 #if SIZEOF_VOID_P == 4
904 case MONO_TYPE_FNPTR:
909 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
910 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
911 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
917 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
918 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
919 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 case MONO_TYPE_BOOLEAN:
925 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
927 case MONO_TYPE_STRING:
928 case MONO_TYPE_SZARRAY:
929 case MONO_TYPE_CLASS:
930 case MONO_TYPE_OBJECT:
931 case MONO_TYPE_ARRAY:
933 case MONO_TYPE_GENERICINST:
934 if (!mono_type_generic_inst_is_valuetype (type)) {
939 case MONO_TYPE_VALUETYPE: {
940 MonoClass *fclass = mono_class_from_mono_type (field->type);
941 /* remove the object header */
942 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
946 g_assert_not_reached ();
955 * mono_class_insecure_overlapping:
956 * check if a class with explicit layout has references and non-references
957 * fields overlapping.
959 * Returns: TRUE if it is insecure to load the type.
962 mono_class_insecure_overlapping (MonoClass *klass)
966 gsize default_bitmap [4] = {0};
968 gsize default_nrbitmap [4] = {0};
969 int i, insecure = FALSE;
972 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
973 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
975 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
976 int idx = i % (sizeof (bitmap [0]) * 8);
977 if (bitmap [idx] & nrbitmap [idx]) {
982 if (bitmap != default_bitmap)
984 if (nrbitmap != default_nrbitmap)
987 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
995 ves_icall_string_alloc (int length)
998 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
999 mono_error_set_pending_exception (&error);
1005 mono_class_compute_gc_descriptor (MonoClass *klass)
1007 MONO_REQ_GC_NEUTRAL_MODE;
1011 gsize default_bitmap [4] = {0};
1012 static gboolean gcj_inited = FALSE;
1015 mono_loader_lock ();
1017 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1018 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1021 mono_loader_unlock ();
1025 mono_class_init (klass);
1027 if (klass->gc_descr_inited)
1030 klass->gc_descr_inited = TRUE;
1031 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1033 bitmap = default_bitmap;
1034 if (klass == mono_defaults.string_class) {
1035 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1036 } else if (klass->rank) {
1037 mono_class_compute_gc_descriptor (klass->element_class);
1038 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1040 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1041 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1042 class->name_space, class->name);*/
1044 /* remove the object header */
1045 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1046 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1047 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1048 class->name_space, class->name);*/
1049 if (bitmap != default_bitmap)
1053 /*static int count = 0;
1056 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1057 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1059 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1060 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1062 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1063 if (bitmap != default_bitmap)
1069 * field_is_special_static:
1070 * @fklass: The MonoClass to look up.
1071 * @field: The MonoClassField describing the field.
1073 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1074 * SPECIAL_STATIC_NONE otherwise.
1077 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1079 MONO_REQ_GC_NEUTRAL_MODE;
1082 MonoCustomAttrInfo *ainfo;
1084 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1085 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1088 for (i = 0; i < ainfo->num_attrs; ++i) {
1089 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1090 if (klass->image == mono_defaults.corlib) {
1091 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1092 mono_custom_attrs_free (ainfo);
1093 return SPECIAL_STATIC_THREAD;
1095 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1096 mono_custom_attrs_free (ainfo);
1097 return SPECIAL_STATIC_CONTEXT;
1101 mono_custom_attrs_free (ainfo);
1102 return SPECIAL_STATIC_NONE;
1105 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1106 #define mix(a,b,c) { \
1107 a -= c; a ^= rot(c, 4); c += b; \
1108 b -= a; b ^= rot(a, 6); a += c; \
1109 c -= b; c ^= rot(b, 8); b += a; \
1110 a -= c; a ^= rot(c,16); c += b; \
1111 b -= a; b ^= rot(a,19); a += c; \
1112 c -= b; c ^= rot(b, 4); b += a; \
1114 #define final(a,b,c) { \
1115 c ^= b; c -= rot(b,14); \
1116 a ^= c; a -= rot(c,11); \
1117 b ^= a; b -= rot(a,25); \
1118 c ^= b; c -= rot(b,16); \
1119 a ^= c; a -= rot(c,4); \
1120 b ^= a; b -= rot(a,14); \
1121 c ^= b; c -= rot(b,24); \
1125 * mono_method_get_imt_slot:
1127 * The IMT slot is embedded into AOTed code, so this must return the same value
1128 * for the same method across all executions. This means:
1129 * - pointers shouldn't be used as hash values.
1130 * - mono_metadata_str_hash () should be used for hashing strings.
1133 mono_method_get_imt_slot (MonoMethod *method)
1135 MONO_REQ_GC_NEUTRAL_MODE;
1137 MonoMethodSignature *sig;
1139 guint32 *hashes_start, *hashes;
1143 /* This can be used to stress tests the collision code */
1147 * We do this to simplify generic sharing. It will hurt
1148 * performance in cases where a class implements two different
1149 * instantiations of the same generic interface.
1150 * The code in build_imt_slots () depends on this.
1152 if (method->is_inflated)
1153 method = ((MonoMethodInflated*)method)->declaring;
1155 sig = mono_method_signature (method);
1156 hashes_count = sig->param_count + 4;
1157 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1158 hashes = hashes_start;
1160 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1161 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1162 method->klass->name_space, method->klass->name, method->name);
1165 /* Initialize hashes */
1166 hashes [0] = mono_metadata_str_hash (method->klass->name);
1167 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1168 hashes [2] = mono_metadata_str_hash (method->name);
1169 hashes [3] = mono_metadata_type_hash (sig->ret);
1170 for (i = 0; i < sig->param_count; i++) {
1171 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1174 /* Setup internal state */
1175 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1177 /* Handle most of the hashes */
1178 while (hashes_count > 3) {
1187 /* Handle the last 3 hashes (all the case statements fall through) */
1188 switch (hashes_count) {
1189 case 3 : c += hashes [2];
1190 case 2 : b += hashes [1];
1191 case 1 : a += hashes [0];
1193 case 0: /* nothing left to add */
1197 free (hashes_start);
1198 /* Report the result */
1199 return c % MONO_IMT_SIZE;
1208 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1209 MONO_REQ_GC_NEUTRAL_MODE;
1211 guint32 imt_slot = mono_method_get_imt_slot (method);
1212 MonoImtBuilderEntry *entry;
1214 if (slot_num >= 0 && imt_slot != slot_num) {
1215 /* we build just a single imt slot and this is not it */
1219 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1220 entry->key = method;
1221 entry->value.vtable_slot = vtable_slot;
1222 entry->next = imt_builder [imt_slot];
1223 if (imt_builder [imt_slot] != NULL) {
1224 entry->children = imt_builder [imt_slot]->children + 1;
1225 if (entry->children == 1) {
1226 mono_stats.imt_slots_with_collisions++;
1227 *imt_collisions_bitmap |= (1 << imt_slot);
1230 entry->children = 0;
1231 mono_stats.imt_used_slots++;
1233 imt_builder [imt_slot] = entry;
1236 char *method_name = mono_method_full_name (method, TRUE);
1237 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1238 method, method_name, imt_slot, vtable_slot, entry->children);
1239 g_free (method_name);
1246 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1248 MonoMethod *method = e->key;
1249 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1253 method->klass->name_space,
1254 method->klass->name,
1257 printf (" * %s: NULL\n", message);
1263 compare_imt_builder_entries (const void *p1, const void *p2) {
1264 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1265 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1267 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1271 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1273 MONO_REQ_GC_NEUTRAL_MODE;
1275 int count = end - start;
1276 int chunk_start = out_array->len;
1279 for (i = start; i < end; ++i) {
1280 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1281 item->key = sorted_array [i]->key;
1282 item->value = sorted_array [i]->value;
1283 item->has_target_code = sorted_array [i]->has_target_code;
1284 item->is_equals = TRUE;
1286 item->check_target_idx = out_array->len + 1;
1288 item->check_target_idx = 0;
1289 g_ptr_array_add (out_array, item);
1292 int middle = start + count / 2;
1293 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1295 item->key = sorted_array [middle]->key;
1296 item->is_equals = FALSE;
1297 g_ptr_array_add (out_array, item);
1298 imt_emit_ir (sorted_array, start, middle, out_array);
1299 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1305 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1306 MONO_REQ_GC_NEUTRAL_MODE;
1308 int number_of_entries = entries->children + 1;
1309 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1310 GPtrArray *result = g_ptr_array_new ();
1311 MonoImtBuilderEntry *current_entry;
1314 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1315 sorted_array [i] = current_entry;
1317 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1319 /*for (i = 0; i < number_of_entries; i++) {
1320 print_imt_entry (" sorted array:", sorted_array [i], i);
1323 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1325 free (sorted_array);
1330 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1332 MONO_REQ_GC_NEUTRAL_MODE;
1334 if (imt_builder_entry != NULL) {
1335 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1336 /* No collision, return the vtable slot contents */
1337 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1339 /* Collision, build the thunk */
1340 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1343 result = imt_thunk_builder (vtable, domain,
1344 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1345 for (i = 0; i < imt_ir->len; ++i)
1346 g_free (g_ptr_array_index (imt_ir, i));
1347 g_ptr_array_free (imt_ir, TRUE);
1359 static MonoImtBuilderEntry*
1360 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1363 * LOCKING: requires the loader and domain locks.
1367 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1369 MONO_REQ_GC_NEUTRAL_MODE;
1373 guint32 imt_collisions_bitmap = 0;
1374 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1375 int method_count = 0;
1376 gboolean record_method_count_for_max_collisions = FALSE;
1377 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1380 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1382 for (i = 0; i < klass->interface_offsets_count; ++i) {
1383 MonoClass *iface = klass->interfaces_packed [i];
1384 int interface_offset = klass->interface_offsets_packed [i];
1385 int method_slot_in_interface, vt_slot;
1387 if (mono_class_has_variant_generic_params (iface))
1388 has_variant_iface = TRUE;
1390 mono_class_setup_methods (iface);
1391 vt_slot = interface_offset;
1392 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1395 if (slot_num >= 0 && iface->is_inflated) {
1397 * The imt slot of the method is the same as for its declaring method,
1398 * see the comment in mono_method_get_imt_slot (), so we can
1399 * avoid inflating methods which will be discarded by
1400 * add_imt_builder_entry anyway.
1402 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1403 if (mono_method_get_imt_slot (method) != slot_num) {
1408 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1409 if (method->is_generic) {
1410 has_generic_virtual = TRUE;
1415 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1416 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1421 if (extra_interfaces) {
1422 int interface_offset = klass->vtable_size;
1424 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1425 MonoClass* iface = (MonoClass *)list_item->data;
1426 int method_slot_in_interface;
1427 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1428 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1430 if (method->is_generic)
1431 has_generic_virtual = TRUE;
1432 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1434 interface_offset += iface->method.count;
1437 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1438 /* overwrite the imt slot only if we're building all the entries or if
1439 * we're building this specific one
1441 if (slot_num < 0 || i == slot_num) {
1442 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1445 if (imt_builder [i]) {
1446 MonoImtBuilderEntry *entry;
1448 /* Link entries with imt_builder [i] */
1449 for (entry = entries; entry->next; entry = entry->next) {
1451 MonoMethod *method = (MonoMethod*)entry->key;
1452 char *method_name = mono_method_full_name (method, TRUE);
1453 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1454 g_free (method_name);
1457 entry->next = imt_builder [i];
1458 entries->children += imt_builder [i]->children + 1;
1460 imt_builder [i] = entries;
1463 if (has_generic_virtual || has_variant_iface) {
1465 * There might be collisions later when the the thunk is expanded.
1467 imt_collisions_bitmap |= (1 << i);
1470 * The IMT thunk might be called with an instance of one of the
1471 * generic virtual methods, so has to fallback to the IMT trampoline.
1473 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1475 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1478 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1482 if (imt_builder [i] != NULL) {
1483 int methods_in_slot = imt_builder [i]->children + 1;
1484 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1485 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1486 record_method_count_for_max_collisions = TRUE;
1488 method_count += methods_in_slot;
1492 mono_stats.imt_number_of_methods += method_count;
1493 if (record_method_count_for_max_collisions) {
1494 mono_stats.imt_method_count_when_max_collisions = method_count;
1497 for (i = 0; i < MONO_IMT_SIZE; i++) {
1498 MonoImtBuilderEntry* entry = imt_builder [i];
1499 while (entry != NULL) {
1500 MonoImtBuilderEntry* next = entry->next;
1506 /* we OR the bitmap since we may build just a single imt slot at a time */
1507 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1511 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1512 MONO_REQ_GC_NEUTRAL_MODE;
1514 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1518 * mono_vtable_build_imt_slot:
1519 * @vtable: virtual object table struct
1520 * @imt_slot: slot in the IMT table
1522 * Fill the given @imt_slot in the IMT table of @vtable with
1523 * a trampoline or a thunk for the case of collisions.
1524 * This is part of the internal mono API.
1526 * LOCKING: Take the domain lock.
1529 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1531 MONO_REQ_GC_NEUTRAL_MODE;
1533 gpointer *imt = (gpointer*)vtable;
1534 imt -= MONO_IMT_SIZE;
1535 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1537 /* no support for extra interfaces: the proxy objects will need
1538 * to build the complete IMT
1539 * Update and heck needs to ahppen inside the proper domain lock, as all
1540 * the changes made to a MonoVTable.
1542 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1543 mono_domain_lock (vtable->domain);
1544 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1545 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1546 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1547 mono_domain_unlock (vtable->domain);
1548 mono_loader_unlock ();
1553 * The first two free list entries both belong to the wait list: The
1554 * first entry is the pointer to the head of the list and the second
1555 * entry points to the last element. That way appending and removing
1556 * the first element are both O(1) operations.
1558 #ifdef MONO_SMALL_CONFIG
1559 #define NUM_FREE_LISTS 6
1561 #define NUM_FREE_LISTS 12
1563 #define FIRST_FREE_LIST_SIZE 64
1564 #define MAX_WAIT_LENGTH 50
1565 #define THUNK_THRESHOLD 10
1568 * LOCKING: The domain lock must be held.
1571 init_thunk_free_lists (MonoDomain *domain)
1573 MONO_REQ_GC_NEUTRAL_MODE;
1575 if (domain->thunk_free_lists)
1577 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1581 list_index_for_size (int item_size)
1584 int size = FIRST_FREE_LIST_SIZE;
1586 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1595 * mono_method_alloc_generic_virtual_thunk:
1597 * @size: size in bytes
1599 * Allocs size bytes to be used for the code of a generic virtual
1600 * thunk. It's either allocated from the domain's code manager or
1601 * reused from a previously invalidated piece.
1603 * LOCKING: The domain lock must be held.
1606 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1608 MONO_REQ_GC_NEUTRAL_MODE;
1610 static gboolean inited = FALSE;
1611 static int generic_virtual_thunks_size = 0;
1615 MonoThunkFreeList **l;
1617 init_thunk_free_lists (domain);
1619 size += sizeof (guint32);
1620 if (size < sizeof (MonoThunkFreeList))
1621 size = sizeof (MonoThunkFreeList);
1623 i = list_index_for_size (size);
1624 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1625 if ((*l)->size >= size) {
1626 MonoThunkFreeList *item = *l;
1628 return ((guint32*)item) + 1;
1632 /* no suitable item found - search lists of larger sizes */
1633 while (++i < NUM_FREE_LISTS) {
1634 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1637 g_assert (item->size > size);
1638 domain->thunk_free_lists [i] = item->next;
1639 return ((guint32*)item) + 1;
1642 /* still nothing found - allocate it */
1644 mono_counters_register ("Generic virtual thunk bytes",
1645 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1648 generic_virtual_thunks_size += size;
1650 p = (guint32 *)mono_domain_code_reserve (domain, size);
1653 mono_domain_lock (domain);
1654 if (!domain->generic_virtual_thunks)
1655 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1656 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1657 mono_domain_unlock (domain);
1663 * LOCKING: The domain lock must be held.
1666 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1668 MONO_REQ_GC_NEUTRAL_MODE;
1670 guint32 *p = (guint32 *)code;
1671 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1672 gboolean found = FALSE;
1674 mono_domain_lock (domain);
1675 if (!domain->generic_virtual_thunks)
1676 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1677 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1679 mono_domain_unlock (domain);
1682 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1684 init_thunk_free_lists (domain);
1686 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1687 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1688 int length = item->length;
1691 /* unlink the first item from the wait list */
1692 domain->thunk_free_lists [0] = item->next;
1693 domain->thunk_free_lists [0]->length = length - 1;
1695 i = list_index_for_size (item->size);
1697 /* put it in the free list */
1698 item->next = domain->thunk_free_lists [i];
1699 domain->thunk_free_lists [i] = item;
1703 if (domain->thunk_free_lists [1]) {
1704 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1705 domain->thunk_free_lists [0]->length++;
1707 g_assert (!domain->thunk_free_lists [0]);
1709 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1710 domain->thunk_free_lists [0]->length = 1;
1714 typedef struct _GenericVirtualCase {
1718 struct _GenericVirtualCase *next;
1719 } GenericVirtualCase;
1722 * get_generic_virtual_entries:
1724 * Return IMT entries for the generic virtual method instances and
1725 * variant interface methods for vtable slot
1728 static MonoImtBuilderEntry*
1729 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1731 MONO_REQ_GC_NEUTRAL_MODE;
1733 GenericVirtualCase *list;
1734 MonoImtBuilderEntry *entries;
1736 mono_domain_lock (domain);
1737 if (!domain->generic_virtual_cases)
1738 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1740 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1743 for (; list; list = list->next) {
1744 MonoImtBuilderEntry *entry;
1746 if (list->count < THUNK_THRESHOLD)
1749 entry = g_new0 (MonoImtBuilderEntry, 1);
1750 entry->key = list->method;
1751 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1752 entry->has_target_code = 1;
1754 entry->children = entries->children + 1;
1755 entry->next = entries;
1759 mono_domain_unlock (domain);
1761 /* FIXME: Leaking memory ? */
1766 * mono_method_add_generic_virtual_invocation:
1768 * @vtable_slot: pointer to the vtable slot
1769 * @method: the inflated generic virtual method
1770 * @code: the method's code
1772 * Registers a call via unmanaged code to a generic virtual method
1773 * instantiation or variant interface method. If the number of calls reaches a threshold
1774 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1775 * virtual method thunk.
1778 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1779 gpointer *vtable_slot,
1780 MonoMethod *method, gpointer code)
1782 MONO_REQ_GC_NEUTRAL_MODE;
1784 static gboolean inited = FALSE;
1785 static int num_added = 0;
1787 GenericVirtualCase *gvc, *list;
1788 MonoImtBuilderEntry *entries;
1792 mono_domain_lock (domain);
1793 if (!domain->generic_virtual_cases)
1794 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1796 /* Check whether the case was already added */
1797 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1800 if (gvc->method == method)
1805 /* If not found, make a new one */
1807 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1808 gvc->method = method;
1811 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1813 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1816 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1822 if (++gvc->count == THUNK_THRESHOLD) {
1823 gpointer *old_thunk = (void **)*vtable_slot;
1824 gpointer vtable_trampoline = NULL;
1825 gpointer imt_trampoline = NULL;
1827 if ((gpointer)vtable_slot < (gpointer)vtable) {
1828 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1829 int imt_slot = MONO_IMT_SIZE + displacement;
1831 /* Force the rebuild of the thunk at the next call */
1832 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1833 *vtable_slot = imt_trampoline;
1835 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1837 entries = get_generic_virtual_entries (domain, vtable_slot);
1839 sorted = imt_sort_slot_entries (entries);
1841 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1845 MonoImtBuilderEntry *next = entries->next;
1850 for (i = 0; i < sorted->len; ++i)
1851 g_free (g_ptr_array_index (sorted, i));
1852 g_ptr_array_free (sorted, TRUE);
1855 #ifndef __native_client__
1856 /* We don't re-use any thunks as there is a lot of overhead */
1857 /* to deleting and re-using code in Native Client. */
1858 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1859 invalidate_generic_virtual_thunk (domain, old_thunk);
1863 mono_domain_unlock (domain);
1866 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1869 * mono_class_vtable:
1870 * @domain: the application domain
1871 * @class: the class to initialize
1873 * VTables are domain specific because we create domain specific code, and
1874 * they contain the domain specific static class data.
1875 * On failure, NULL is returned, and class->exception_type is set.
1878 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1881 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1882 mono_error_cleanup (&error);
1887 * mono_class_vtable_full:
1888 * @domain: the application domain
1889 * @class: the class to initialize
1890 * @error set on failure.
1892 * VTables are domain specific because we create domain specific code, and
1893 * they contain the domain specific static class data.
1896 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1898 MONO_REQ_GC_UNSAFE_MODE;
1900 MonoClassRuntimeInfo *runtime_info;
1902 mono_error_init (error);
1906 if (mono_class_has_failure (klass)) {
1907 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1911 /* this check can be inlined in jitted code, too */
1912 runtime_info = klass->runtime_info;
1913 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1914 return runtime_info->domain_vtables [domain->domain_id];
1915 return mono_class_create_runtime_vtable (domain, klass, error);
1919 * mono_class_try_get_vtable:
1920 * @domain: the application domain
1921 * @class: the class to initialize
1923 * This function tries to get the associated vtable from @class if
1924 * it was already created.
1927 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1929 MONO_REQ_GC_NEUTRAL_MODE;
1931 MonoClassRuntimeInfo *runtime_info;
1935 runtime_info = klass->runtime_info;
1936 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1937 return runtime_info->domain_vtables [domain->domain_id];
1942 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1944 MONO_REQ_GC_NEUTRAL_MODE;
1946 size_t alloc_offset;
1949 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1950 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1951 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1953 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1954 g_assert ((imt_table_bytes & 7) == 4);
1961 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1965 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1967 MONO_REQ_GC_UNSAFE_MODE;
1970 MonoClassRuntimeInfo *runtime_info, *old_info;
1971 MonoClassField *field;
1973 int i, vtable_slots;
1974 size_t imt_table_bytes;
1976 guint32 vtable_size, class_size;
1978 gpointer *interface_offsets;
1980 mono_error_init (error);
1982 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1983 mono_domain_lock (domain);
1984 runtime_info = klass->runtime_info;
1985 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1986 mono_domain_unlock (domain);
1987 mono_loader_unlock ();
1988 return runtime_info->domain_vtables [domain->domain_id];
1990 if (!klass->inited || mono_class_has_failure (klass)) {
1991 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1992 mono_domain_unlock (domain);
1993 mono_loader_unlock ();
1994 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1999 /* Array types require that their element type be valid*/
2000 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
2001 MonoClass *element_class = klass->element_class;
2002 if (!element_class->inited)
2003 mono_class_init (element_class);
2005 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
2006 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
2007 mono_class_setup_vtable (element_class);
2009 if (mono_class_has_failure (element_class)) {
2010 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2011 if (!mono_class_has_failure (klass))
2012 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
2013 mono_domain_unlock (domain);
2014 mono_loader_unlock ();
2015 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2021 * For some classes, mono_class_init () already computed klass->vtable_size, and
2022 * that is all that is needed because of the vtable trampolines.
2024 if (!klass->vtable_size)
2025 mono_class_setup_vtable (klass);
2027 if (klass->generic_class && !klass->vtable)
2028 mono_class_check_vtable_constraints (klass, NULL);
2030 /* Initialize klass->has_finalize */
2031 mono_class_has_finalizer (klass);
2033 if (mono_class_has_failure (klass)) {
2034 mono_domain_unlock (domain);
2035 mono_loader_unlock ();
2036 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2040 vtable_slots = klass->vtable_size;
2041 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2042 class_size = mono_class_data_size (klass);
2046 if (klass->interface_offsets_count) {
2047 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2048 mono_stats.imt_number_of_tables++;
2049 mono_stats.imt_tables_size += imt_table_bytes;
2051 imt_table_bytes = 0;
2054 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2056 mono_stats.used_class_count++;
2057 mono_stats.class_vtable_size += vtable_size;
2059 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2060 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2061 g_assert (!((gsize)vt & 7));
2064 vt->rank = klass->rank;
2065 vt->domain = domain;
2067 mono_class_compute_gc_descriptor (klass);
2069 * We can't use typed allocation in the non-root domains, since the
2070 * collector needs the GC descriptor stored in the vtable even after
2071 * the mempool containing the vtable is destroyed when the domain is
2072 * unloaded. An alternative might be to allocate vtables in the GC
2073 * heap, but this does not seem to work (it leads to crashes inside
2074 * libgc). If that approach is tried, two gc descriptors need to be
2075 * allocated for each class: one for the root domain, and one for all
2076 * other domains. The second descriptor should contain a bit for the
2077 * vtable field in MonoObject, since we can no longer assume the
2078 * vtable is reachable by other roots after the appdomain is unloaded.
2080 #ifdef HAVE_BOEHM_GC
2081 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2082 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2085 vt->gc_descr = klass->gc_descr;
2087 gc_bits = mono_gc_get_vtable_bits (klass);
2088 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2090 vt->gc_bits = gc_bits;
2093 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2094 if (klass->has_static_refs) {
2095 MonoGCDescriptor statics_gc_descr;
2097 gsize default_bitmap [4] = {0};
2100 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2101 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2102 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2103 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2104 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2105 if (bitmap != default_bitmap)
2108 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2110 vt->has_static_fields = TRUE;
2111 mono_stats.class_static_data_size += class_size;
2115 while ((field = mono_class_get_fields (klass, &iter))) {
2116 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2118 if (mono_field_is_deleted (field))
2120 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2121 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2122 if (special_static != SPECIAL_STATIC_NONE) {
2123 guint32 size, offset;
2125 gsize default_bitmap [4] = {0};
2130 if (mono_type_is_reference (field->type)) {
2131 default_bitmap [0] = 1;
2133 bitmap = default_bitmap;
2134 } else if (mono_type_is_struct (field->type)) {
2135 fclass = mono_class_from_mono_type (field->type);
2136 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2137 numbits = max_set + 1;
2139 default_bitmap [0] = 0;
2141 bitmap = default_bitmap;
2143 size = mono_type_size (field->type, &align);
2144 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2145 if (!domain->special_static_fields)
2146 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2147 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2148 if (bitmap != default_bitmap)
2151 * This marks the field as special static to speed up the
2152 * checks in mono_field_static_get/set_value ().
2158 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2159 MonoClass *fklass = mono_class_from_mono_type (field->type);
2160 const char *data = mono_field_get_data (field);
2162 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2163 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2164 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2167 if (fklass->valuetype) {
2168 memcpy (t, data, mono_class_value_size (fklass, NULL));
2170 /* it's a pointer type: add check */
2171 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2178 vt->max_interface_id = klass->max_interface_id;
2179 vt->interface_bitmap = klass->interface_bitmap;
2181 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2182 // class->name, klass->interface_offsets_count);
2184 /* Initialize vtable */
2185 if (callbacks.get_vtable_trampoline) {
2186 // This also covers the AOT case
2187 for (i = 0; i < klass->vtable_size; ++i) {
2188 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2191 mono_class_setup_vtable (klass);
2193 for (i = 0; i < klass->vtable_size; ++i) {
2196 cm = klass->vtable [i];
2198 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2199 if (!is_ok (error)) {
2200 mono_domain_unlock (domain);
2201 mono_loader_unlock ();
2208 if (imt_table_bytes) {
2209 /* Now that the vtable is full, we can actually fill up the IMT */
2210 for (i = 0; i < MONO_IMT_SIZE; ++i)
2211 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2215 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2216 * re-acquire them and check if another thread has created the vtable in the meantime.
2218 /* Special case System.MonoType to avoid infinite recursion */
2219 if (klass != mono_defaults.runtimetype_class) {
2220 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2221 if (!is_ok (error)) {
2222 mono_domain_unlock (domain);
2223 mono_loader_unlock ();
2227 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2228 /* This is unregistered in
2229 unregister_vtable_reflection_type() in
2231 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2234 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2236 /* class_vtable_array keeps an array of created vtables
2238 g_ptr_array_add (domain->class_vtable_array, vt);
2239 /* klass->runtime_info is protected by the loader lock, both when
2240 * it it enlarged and when it is stored info.
2244 * Store the vtable in klass->runtime_info.
2245 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2247 mono_memory_barrier ();
2249 old_info = klass->runtime_info;
2250 if (old_info && old_info->max_domain >= domain->domain_id) {
2251 /* someone already created a large enough runtime info */
2252 old_info->domain_vtables [domain->domain_id] = vt;
2254 int new_size = domain->domain_id;
2256 new_size = MAX (new_size, old_info->max_domain);
2258 /* make the new size a power of two */
2260 while (new_size > i)
2263 /* this is a bounded memory retention issue: may want to
2264 * handle it differently when we'll have a rcu-like system.
2266 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2267 runtime_info->max_domain = new_size - 1;
2268 /* copy the stuff from the older info */
2270 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2272 runtime_info->domain_vtables [domain->domain_id] = vt;
2274 mono_memory_barrier ();
2275 klass->runtime_info = runtime_info;
2278 if (klass == mono_defaults.runtimetype_class) {
2279 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2280 if (!is_ok (error)) {
2281 mono_domain_unlock (domain);
2282 mono_loader_unlock ();
2286 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2287 /* This is unregistered in
2288 unregister_vtable_reflection_type() in
2290 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2293 mono_domain_unlock (domain);
2294 mono_loader_unlock ();
2296 /* make sure the parent is initialized */
2297 /*FIXME shouldn't this fail the current type?*/
2299 mono_class_vtable_full (domain, klass->parent, error);
2304 #ifndef DISABLE_REMOTING
2306 * mono_class_proxy_vtable:
2307 * @domain: the application domain
2308 * @remove_class: the remote class
2309 * @error: set on error
2311 * Creates a vtable for transparent proxies. It is basically
2312 * a copy of the real vtable of the class wrapped in @remote_class,
2313 * but all function pointers invoke the remoting functions, and
2314 * vtable->klass points to the transparent proxy class, and not to @class.
2316 * On failure returns NULL and sets @error
2319 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2321 MONO_REQ_GC_UNSAFE_MODE;
2323 MonoVTable *vt, *pvt;
2324 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2326 GSList *extra_interfaces = NULL;
2327 MonoClass *klass = remote_class->proxy_class;
2328 gpointer *interface_offsets;
2329 uint8_t *bitmap = NULL;
2331 size_t imt_table_bytes;
2333 #ifdef COMPRESSED_INTERFACE_BITMAP
2337 mono_error_init (error);
2339 vt = mono_class_vtable (domain, klass);
2340 g_assert (vt); /*FIXME property handle failure*/
2341 max_interface_id = vt->max_interface_id;
2343 /* Calculate vtable space for extra interfaces */
2344 for (j = 0; j < remote_class->interface_count; j++) {
2345 MonoClass* iclass = remote_class->interfaces[j];
2349 /*FIXME test for interfaces with variant generic arguments*/
2350 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2351 continue; /* interface implemented by the class */
2352 if (g_slist_find (extra_interfaces, iclass))
2355 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2357 method_count = mono_class_num_methods (iclass);
2359 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2363 for (i = 0; i < ifaces->len; ++i) {
2364 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2365 /*FIXME test for interfaces with variant generic arguments*/
2366 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2367 continue; /* interface implemented by the class */
2368 if (g_slist_find (extra_interfaces, ic))
2370 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2371 method_count += mono_class_num_methods (ic);
2373 g_ptr_array_free (ifaces, TRUE);
2377 extra_interface_vtsize += method_count * sizeof (gpointer);
2378 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2381 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2382 mono_stats.imt_number_of_tables++;
2383 mono_stats.imt_tables_size += imt_table_bytes;
2385 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2387 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2389 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2390 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2391 g_assert (!((gsize)pvt & 7));
2393 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2395 pvt->klass = mono_defaults.transparent_proxy_class;
2396 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2397 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2399 /* initialize vtable */
2400 mono_class_setup_vtable (klass);
2401 for (i = 0; i < klass->vtable_size; ++i) {
2404 if ((cm = klass->vtable [i])) {
2405 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2409 pvt->vtable [i] = NULL;
2412 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2413 /* create trampolines for abstract methods */
2414 for (k = klass; k; k = k->parent) {
2416 gpointer iter = NULL;
2417 while ((m = mono_class_get_methods (k, &iter)))
2418 if (!pvt->vtable [m->slot]) {
2419 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2426 pvt->max_interface_id = max_interface_id;
2427 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2428 #ifdef COMPRESSED_INTERFACE_BITMAP
2429 bitmap = (uint8_t *)g_malloc0 (bsize);
2431 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2434 for (i = 0; i < klass->interface_offsets_count; ++i) {
2435 int interface_id = klass->interfaces_packed [i]->interface_id;
2436 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2439 if (extra_interfaces) {
2440 int slot = klass->vtable_size;
2446 /* Create trampolines for the methods of the interfaces */
2447 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2448 interf = (MonoClass *)list_item->data;
2450 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2454 while ((cm = mono_class_get_methods (interf, &iter))) {
2455 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2460 slot += mono_class_num_methods (interf);
2464 /* Now that the vtable is full, we can actually fill up the IMT */
2465 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2466 if (extra_interfaces) {
2467 g_slist_free (extra_interfaces);
2470 #ifdef COMPRESSED_INTERFACE_BITMAP
2471 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2472 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2473 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2476 pvt->interface_bitmap = bitmap;
2480 if (extra_interfaces)
2481 g_slist_free (extra_interfaces);
2482 #ifdef COMPRESSED_INTERFACE_BITMAP
2488 #endif /* DISABLE_REMOTING */
2491 * mono_class_field_is_special_static:
2493 * Returns whether @field is a thread/context static field.
2496 mono_class_field_is_special_static (MonoClassField *field)
2498 MONO_REQ_GC_NEUTRAL_MODE
2500 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2502 if (mono_field_is_deleted (field))
2504 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2505 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2512 * mono_class_field_get_special_static_type:
2513 * @field: The MonoClassField describing the field.
2515 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2516 * SPECIAL_STATIC_NONE otherwise.
2519 mono_class_field_get_special_static_type (MonoClassField *field)
2521 MONO_REQ_GC_NEUTRAL_MODE
2523 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2524 return SPECIAL_STATIC_NONE;
2525 if (mono_field_is_deleted (field))
2526 return SPECIAL_STATIC_NONE;
2527 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2528 return field_is_special_static (field->parent, field);
2529 return SPECIAL_STATIC_NONE;
2533 * mono_class_has_special_static_fields:
2535 * Returns whenever @klass has any thread/context static fields.
2538 mono_class_has_special_static_fields (MonoClass *klass)
2540 MONO_REQ_GC_NEUTRAL_MODE
2542 MonoClassField *field;
2546 while ((field = mono_class_get_fields (klass, &iter))) {
2547 g_assert (field->parent == klass);
2548 if (mono_class_field_is_special_static (field))
2555 #ifndef DISABLE_REMOTING
2557 * create_remote_class_key:
2558 * Creates an array of pointers that can be used as a hash key for a remote class.
2559 * The first element of the array is the number of pointers.
2562 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2564 MONO_REQ_GC_NEUTRAL_MODE;
2569 if (remote_class == NULL) {
2570 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2571 key = (void **)g_malloc (sizeof(gpointer) * 3);
2572 key [0] = GINT_TO_POINTER (2);
2573 key [1] = mono_defaults.marshalbyrefobject_class;
2574 key [2] = extra_class;
2576 key = (void **)g_malloc (sizeof(gpointer) * 2);
2577 key [0] = GINT_TO_POINTER (1);
2578 key [1] = extra_class;
2581 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2582 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2583 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2584 key [1] = remote_class->proxy_class;
2586 // Keep the list of interfaces sorted
2587 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2588 if (extra_class && remote_class->interfaces [i] > extra_class) {
2589 key [j++] = extra_class;
2592 key [j] = remote_class->interfaces [i];
2595 key [j] = extra_class;
2597 // Replace the old class. The interface list is the same
2598 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2599 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2600 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2601 for (i = 0; i < remote_class->interface_count; i++)
2602 key [2 + i] = remote_class->interfaces [i];
2610 * copy_remote_class_key:
2612 * Make a copy of KEY in the domain and return the copy.
2615 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2617 MONO_REQ_GC_NEUTRAL_MODE
2619 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2620 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2622 memcpy (mp_key, key, key_size);
2628 * mono_remote_class:
2629 * @domain: the application domain
2630 * @class_name: name of the remote class
2631 * @error: set on error
2633 * Creates and initializes a MonoRemoteClass object for a remote type.
2635 * On failure returns NULL and sets @error
2638 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2640 MONO_REQ_GC_UNSAFE_MODE;
2642 MonoRemoteClass *rc;
2643 gpointer* key, *mp_key;
2646 mono_error_init (error);
2648 key = create_remote_class_key (NULL, proxy_class);
2650 mono_domain_lock (domain);
2651 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2655 mono_domain_unlock (domain);
2659 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2660 if (!is_ok (error)) {
2662 mono_domain_unlock (domain);
2666 mp_key = copy_remote_class_key (domain, key);
2670 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2671 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2672 rc->interface_count = 1;
2673 rc->interfaces [0] = proxy_class;
2674 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2676 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2677 rc->interface_count = 0;
2678 rc->proxy_class = proxy_class;
2681 rc->default_vtable = NULL;
2682 rc->xdomain_vtable = NULL;
2683 rc->proxy_class_name = name;
2684 #ifndef DISABLE_PERFCOUNTERS
2685 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2688 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2690 mono_domain_unlock (domain);
2695 * clone_remote_class:
2696 * Creates a copy of the remote_class, adding the provided class or interface
2698 static MonoRemoteClass*
2699 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2701 MONO_REQ_GC_NEUTRAL_MODE;
2703 MonoRemoteClass *rc;
2704 gpointer* key, *mp_key;
2706 key = create_remote_class_key (remote_class, extra_class);
2707 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2713 mp_key = copy_remote_class_key (domain, key);
2717 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2719 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2720 rc->proxy_class = remote_class->proxy_class;
2721 rc->interface_count = remote_class->interface_count + 1;
2723 // Keep the list of interfaces sorted, since the hash key of
2724 // the remote class depends on this
2725 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2726 if (remote_class->interfaces [i] > extra_class && i == j)
2727 rc->interfaces [j++] = extra_class;
2728 rc->interfaces [j] = remote_class->interfaces [i];
2731 rc->interfaces [j] = extra_class;
2733 // Replace the old class. The interface array is the same
2734 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2735 rc->proxy_class = extra_class;
2736 rc->interface_count = remote_class->interface_count;
2737 if (rc->interface_count > 0)
2738 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2741 rc->default_vtable = NULL;
2742 rc->xdomain_vtable = NULL;
2743 rc->proxy_class_name = remote_class->proxy_class_name;
2745 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2751 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2753 MONO_REQ_GC_UNSAFE_MODE;
2755 mono_error_init (error);
2757 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2758 mono_domain_lock (domain);
2759 if (rp->target_domain_id != -1) {
2760 if (remote_class->xdomain_vtable == NULL)
2761 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2762 mono_domain_unlock (domain);
2763 mono_loader_unlock ();
2764 return_val_if_nok (error, NULL);
2765 return remote_class->xdomain_vtable;
2767 if (remote_class->default_vtable == NULL) {
2770 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2771 klass = mono_class_from_mono_type (type);
2773 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)))
2774 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2777 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2778 /* N.B. both branches of the if modify error */
2779 if (!is_ok (error)) {
2780 mono_domain_unlock (domain);
2781 mono_loader_unlock ();
2786 mono_domain_unlock (domain);
2787 mono_loader_unlock ();
2788 return remote_class->default_vtable;
2792 * mono_upgrade_remote_class:
2793 * @domain: the application domain
2794 * @tproxy: the proxy whose remote class has to be upgraded.
2795 * @klass: class to which the remote class can be casted.
2796 * @error: set on error
2798 * Updates the vtable of the remote class by adding the necessary method slots
2799 * and interface offsets so it can be safely casted to klass. klass can be a
2800 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2803 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2805 MONO_REQ_GC_UNSAFE_MODE;
2807 MonoTransparentProxy *tproxy;
2808 MonoRemoteClass *remote_class;
2809 gboolean redo_vtable;
2811 mono_error_init (error);
2812 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2813 mono_domain_lock (domain);
2815 tproxy = (MonoTransparentProxy*) proxy_object;
2816 remote_class = tproxy->remote_class;
2818 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2821 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2822 if (remote_class->interfaces [i] == klass)
2823 redo_vtable = FALSE;
2826 redo_vtable = (remote_class->proxy_class != klass);
2830 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2831 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2837 mono_domain_unlock (domain);
2838 mono_loader_unlock ();
2839 return is_ok (error);
2841 #endif /* DISABLE_REMOTING */
2845 * mono_object_get_virtual_method:
2846 * @obj: object to operate on.
2849 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2850 * the instance of a callvirt of method.
2853 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2855 MONO_REQ_GC_UNSAFE_MODE;
2858 MonoMethod **vtable;
2859 gboolean is_proxy = FALSE;
2860 MonoMethod *res = NULL;
2862 klass = mono_object_class (obj);
2863 #ifndef DISABLE_REMOTING
2864 if (klass == mono_defaults.transparent_proxy_class) {
2865 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2870 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2873 mono_class_setup_vtable (klass);
2874 vtable = klass->vtable;
2876 if (method->slot == -1) {
2877 /* method->slot might not be set for instances of generic methods */
2878 if (method->is_inflated) {
2879 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2880 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2883 g_assert_not_reached ();
2887 /* check method->slot is a valid index: perform isinstance? */
2888 if (method->slot != -1) {
2889 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2891 gboolean variance_used = FALSE;
2892 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2893 g_assert (iface_offset > 0);
2894 res = vtable [iface_offset + method->slot];
2897 res = vtable [method->slot];
2901 #ifndef DISABLE_REMOTING
2903 /* It may be an interface, abstract class method or generic method */
2904 if (!res || mono_method_signature (res)->generic_param_count)
2907 /* generic methods demand invoke_with_check */
2908 if (mono_method_signature (res)->generic_param_count)
2909 res = mono_marshal_get_remoting_invoke_with_check (res);
2912 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2913 res = mono_cominterop_get_invoke (res);
2916 res = mono_marshal_get_remoting_invoke (res);
2921 if (method->is_inflated) {
2923 /* Have to inflate the result */
2924 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2925 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2935 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2937 MONO_REQ_GC_UNSAFE_MODE;
2939 MonoObject *result = NULL;
2941 g_assert (callbacks.runtime_invoke);
2943 mono_error_init (error);
2945 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2946 mono_profiler_method_start_invoke (method);
2948 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2950 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2951 mono_profiler_method_end_invoke (method);
2953 if (!mono_error_ok (error))
2960 * mono_runtime_invoke:
2961 * @method: method to invoke
2962 * @obJ: object instance
2963 * @params: arguments to the method
2964 * @exc: exception information.
2966 * Invokes the method represented by @method on the object @obj.
2968 * obj is the 'this' pointer, it should be NULL for static
2969 * methods, a MonoObject* for object instances and a pointer to
2970 * the value type for value types.
2972 * The params array contains the arguments to the method with the
2973 * same convention: MonoObject* pointers for object instances and
2974 * pointers to the value type otherwise.
2976 * From unmanaged code you'll usually use the
2977 * mono_runtime_invoke() variant.
2979 * Note that this function doesn't handle virtual methods for
2980 * you, it will exec the exact method you pass: we still need to
2981 * expose a function to lookup the derived class implementation
2982 * of a virtual method (there are examples of this in the code,
2985 * You can pass NULL as the exc argument if you don't want to
2986 * catch exceptions, otherwise, *exc will be set to the exception
2987 * thrown, if any. if an exception is thrown, you can't use the
2988 * MonoObject* result from the function.
2990 * If the method returns a value type, it is boxed in an object
2994 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2999 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
3000 if (*exc == NULL && !mono_error_ok(&error)) {
3001 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3003 mono_error_cleanup (&error);
3005 res = mono_runtime_invoke_checked (method, obj, params, &error);
3006 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3012 * mono_runtime_try_invoke:
3013 * @method: method to invoke
3014 * @obJ: object instance
3015 * @params: arguments to the method
3016 * @exc: exception information.
3017 * @error: set on error
3019 * Invokes the method represented by @method on the object @obj.
3021 * obj is the 'this' pointer, it should be NULL for static
3022 * methods, a MonoObject* for object instances and a pointer to
3023 * the value type for value types.
3025 * The params array contains the arguments to the method with the
3026 * same convention: MonoObject* pointers for object instances and
3027 * pointers to the value type otherwise.
3029 * From unmanaged code you'll usually use the
3030 * mono_runtime_invoke() variant.
3032 * Note that this function doesn't handle virtual methods for
3033 * you, it will exec the exact method you pass: we still need to
3034 * expose a function to lookup the derived class implementation
3035 * of a virtual method (there are examples of this in the code,
3038 * For this function, you must not pass NULL as the exc argument if
3039 * you don't want to catch exceptions, use
3040 * mono_runtime_invoke_checked(). If an exception is thrown, you
3041 * can't use the MonoObject* result from the function.
3043 * If this method cannot be invoked, @error will be set and @exc and
3044 * the return value must not be used.
3046 * If the method returns a value type, it is boxed in an object
3050 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3052 MONO_REQ_GC_UNSAFE_MODE;
3054 g_assert (exc != NULL);
3056 if (mono_runtime_get_no_exec ())
3057 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3059 return do_runtime_invoke (method, obj, params, exc, error);
3063 * mono_runtime_invoke_checked:
3064 * @method: method to invoke
3065 * @obJ: object instance
3066 * @params: arguments to the method
3067 * @error: set on error
3069 * Invokes the method represented by @method on the object @obj.
3071 * obj is the 'this' pointer, it should be NULL for static
3072 * methods, a MonoObject* for object instances and a pointer to
3073 * the value type for value types.
3075 * The params array contains the arguments to the method with the
3076 * same convention: MonoObject* pointers for object instances and
3077 * pointers to the value type otherwise.
3079 * From unmanaged code you'll usually use the
3080 * mono_runtime_invoke() variant.
3082 * Note that this function doesn't handle virtual methods for
3083 * you, it will exec the exact method you pass: we still need to
3084 * expose a function to lookup the derived class implementation
3085 * of a virtual method (there are examples of this in the code,
3088 * If an exception is thrown, you can't use the MonoObject* result
3089 * from the function.
3091 * If this method cannot be invoked, @error will be set. If the
3092 * method throws an exception (and we're in coop mode) the exception
3093 * will be set in @error.
3095 * If the method returns a value type, it is boxed in an object
3099 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3101 MONO_REQ_GC_UNSAFE_MODE;
3103 if (mono_runtime_get_no_exec ())
3104 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3106 return do_runtime_invoke (method, obj, params, NULL, error);
3110 * mono_method_get_unmanaged_thunk:
3111 * @method: method to generate a thunk for.
3113 * Returns an unmanaged->managed thunk that can be used to call
3114 * a managed method directly from C.
3116 * The thunk's C signature closely matches the managed signature:
3118 * C#: public bool Equals (object obj);
3119 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3120 * MonoObject*, MonoException**);
3122 * The 1st ("this") parameter must not be used with static methods:
3124 * C#: public static bool ReferenceEquals (object a, object b);
3125 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3128 * The last argument must be a non-null pointer of a MonoException* pointer.
3129 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3130 * exception has been thrown in managed code. Otherwise it will point
3131 * to the MonoException* caught by the thunk. In this case, the result of
3132 * the thunk is undefined:
3134 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3135 * MonoException *ex = NULL;
3136 * Equals func = mono_method_get_unmanaged_thunk (method);
3137 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3139 * // handle exception
3142 * The calling convention of the thunk matches the platform's default
3143 * convention. This means that under Windows, C declarations must
3144 * contain the __stdcall attribute:
3146 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3147 * MonoObject*, MonoException**);
3151 * Value type arguments and return values are treated as they were objects:
3153 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3154 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3156 * Arguments must be properly boxed upon trunk's invocation, while return
3157 * values must be unboxed.
3160 mono_method_get_unmanaged_thunk (MonoMethod *method)
3162 MONO_REQ_GC_NEUTRAL_MODE;
3163 MONO_REQ_API_ENTRYPOINT;
3168 g_assert (!mono_threads_is_coop_enabled ());
3170 MONO_ENTER_GC_UNSAFE;
3171 method = mono_marshal_get_thunk_invoke_wrapper (method);
3172 res = mono_compile_method_checked (method, &error);
3173 mono_error_cleanup (&error);
3174 MONO_EXIT_GC_UNSAFE;
3180 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3182 MONO_REQ_GC_UNSAFE_MODE;
3186 /* object fields cannot be byref, so we don't need a
3188 gpointer *p = (gpointer*)dest;
3195 case MONO_TYPE_BOOLEAN:
3197 case MONO_TYPE_U1: {
3198 guint8 *p = (guint8*)dest;
3199 *p = value ? *(guint8*)value : 0;
3204 case MONO_TYPE_CHAR: {
3205 guint16 *p = (guint16*)dest;
3206 *p = value ? *(guint16*)value : 0;
3209 #if SIZEOF_VOID_P == 4
3214 case MONO_TYPE_U4: {
3215 gint32 *p = (gint32*)dest;
3216 *p = value ? *(gint32*)value : 0;
3219 #if SIZEOF_VOID_P == 8
3224 case MONO_TYPE_U8: {
3225 gint64 *p = (gint64*)dest;
3226 *p = value ? *(gint64*)value : 0;
3229 case MONO_TYPE_R4: {
3230 float *p = (float*)dest;
3231 *p = value ? *(float*)value : 0;
3234 case MONO_TYPE_R8: {
3235 double *p = (double*)dest;
3236 *p = value ? *(double*)value : 0;
3239 case MONO_TYPE_STRING:
3240 case MONO_TYPE_SZARRAY:
3241 case MONO_TYPE_CLASS:
3242 case MONO_TYPE_OBJECT:
3243 case MONO_TYPE_ARRAY:
3244 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3246 case MONO_TYPE_FNPTR:
3247 case MONO_TYPE_PTR: {
3248 gpointer *p = (gpointer*)dest;
3249 *p = deref_pointer? *(gpointer*)value: value;
3252 case MONO_TYPE_VALUETYPE:
3253 /* note that 't' and 'type->type' can be different */
3254 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3255 t = mono_class_enum_basetype (type->data.klass)->type;
3258 MonoClass *klass = mono_class_from_mono_type (type);
3259 int size = mono_class_value_size (klass, NULL);
3261 mono_gc_bzero_atomic (dest, size);
3263 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3266 case MONO_TYPE_GENERICINST:
3267 t = type->data.generic_class->container_class->byval_arg.type;
3270 g_error ("got type %x", type->type);
3275 * mono_field_set_value:
3276 * @obj: Instance object
3277 * @field: MonoClassField describing the field to set
3278 * @value: The value to be set
3280 * Sets the value of the field described by @field in the object instance @obj
3281 * to the value passed in @value. This method should only be used for instance
3282 * fields. For static fields, use mono_field_static_set_value.
3284 * The value must be on the native format of the field type.
3287 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3289 MONO_REQ_GC_UNSAFE_MODE;
3293 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3295 dest = (char*)obj + field->offset;
3296 mono_copy_value (field->type, dest, value, FALSE);
3300 * mono_field_static_set_value:
3301 * @field: MonoClassField describing the field to set
3302 * @value: The value to be set
3304 * Sets the value of the static field described by @field
3305 * to the value passed in @value.
3307 * The value must be on the native format of the field type.
3310 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3312 MONO_REQ_GC_UNSAFE_MODE;
3316 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3317 /* you cant set a constant! */
3318 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3320 if (field->offset == -1) {
3321 /* Special static */
3324 mono_domain_lock (vt->domain);
3325 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3326 mono_domain_unlock (vt->domain);
3327 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3329 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3331 mono_copy_value (field->type, dest, value, FALSE);
3335 * mono_vtable_get_static_field_data:
3337 * Internal use function: return a pointer to the memory holding the static fields
3338 * for a class or NULL if there are no static fields.
3339 * This is exported only for use by the debugger.
3342 mono_vtable_get_static_field_data (MonoVTable *vt)
3344 MONO_REQ_GC_NEUTRAL_MODE
3346 if (!vt->has_static_fields)
3348 return vt->vtable [vt->klass->vtable_size];
3352 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3354 MONO_REQ_GC_UNSAFE_MODE;
3358 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3359 if (field->offset == -1) {
3360 /* Special static */
3363 mono_domain_lock (vt->domain);
3364 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3365 mono_domain_unlock (vt->domain);
3366 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3368 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3371 src = (guint8*)obj + field->offset;
3378 * mono_field_get_value:
3379 * @obj: Object instance
3380 * @field: MonoClassField describing the field to fetch information from
3381 * @value: pointer to the location where the value will be stored
3383 * Use this routine to get the value of the field @field in the object
3386 * The pointer provided by value must be of the field type, for reference
3387 * types this is a MonoObject*, for value types its the actual pointer to
3392 * mono_field_get_value (obj, int_field, &i);
3395 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3397 MONO_REQ_GC_UNSAFE_MODE;
3403 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3405 src = (char*)obj + field->offset;
3406 mono_copy_value (field->type, value, src, TRUE);
3410 * mono_field_get_value_object:
3411 * @domain: domain where the object will be created (if boxing)
3412 * @field: MonoClassField describing the field to fetch information from
3413 * @obj: The object instance for the field.
3415 * Returns: a new MonoObject with the value from the given field. If the
3416 * field represents a value type, the value is boxed.
3420 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3423 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3424 mono_error_assert_ok (&error);
3429 * mono_field_get_value_object_checked:
3430 * @domain: domain where the object will be created (if boxing)
3431 * @field: MonoClassField describing the field to fetch information from
3432 * @obj: The object instance for the field.
3433 * @error: Set on error.
3435 * Returns: a new MonoObject with the value from the given field. If the
3436 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3440 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3442 MONO_REQ_GC_UNSAFE_MODE;
3444 mono_error_init (error);
3448 MonoVTable *vtable = NULL;
3450 gboolean is_static = FALSE;
3451 gboolean is_ref = FALSE;
3452 gboolean is_literal = FALSE;
3453 gboolean is_ptr = FALSE;
3454 MonoType *type = mono_field_get_type_checked (field, error);
3456 return_val_if_nok (error, NULL);
3458 switch (type->type) {
3459 case MONO_TYPE_STRING:
3460 case MONO_TYPE_OBJECT:
3461 case MONO_TYPE_CLASS:
3462 case MONO_TYPE_ARRAY:
3463 case MONO_TYPE_SZARRAY:
3468 case MONO_TYPE_BOOLEAN:
3471 case MONO_TYPE_CHAR:
3480 case MONO_TYPE_VALUETYPE:
3481 is_ref = type->byref;
3483 case MONO_TYPE_GENERICINST:
3484 is_ref = !mono_type_generic_inst_is_valuetype (type);
3490 g_error ("type 0x%x not handled in "
3491 "mono_field_get_value_object", type->type);
3495 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3498 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3502 vtable = mono_class_vtable_full (domain, field->parent, error);
3503 return_val_if_nok (error, NULL);
3505 if (!vtable->initialized) {
3506 mono_runtime_class_init_full (vtable, error);
3507 return_val_if_nok (error, NULL);
3516 get_default_field_value (domain, field, &o, error);
3517 return_val_if_nok (error, NULL);
3518 } else if (is_static) {
3519 mono_field_static_get_value_checked (vtable, field, &o, error);
3520 return_val_if_nok (error, NULL);
3522 mono_field_get_value (obj, field, &o);
3528 static MonoMethod *m;
3534 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3535 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3541 get_default_field_value (domain, field, v, error);
3542 return_val_if_nok (error, NULL);
3543 } else if (is_static) {
3544 mono_field_static_get_value_checked (vtable, field, v, error);
3545 return_val_if_nok (error, NULL);
3547 mono_field_get_value (obj, field, v);
3550 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3551 args [0] = ptr ? *ptr : NULL;
3552 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3553 return_val_if_nok (error, NULL);
3555 o = mono_runtime_invoke_checked (m, NULL, args, error);
3556 return_val_if_nok (error, NULL);
3561 /* boxed value type */
3562 klass = mono_class_from_mono_type (type);
3564 if (mono_class_is_nullable (klass))
3565 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3567 o = mono_object_new_checked (domain, klass, error);
3568 return_val_if_nok (error, NULL);
3569 v = ((gchar *) o) + sizeof (MonoObject);
3572 get_default_field_value (domain, field, v, error);
3573 return_val_if_nok (error, NULL);
3574 } else if (is_static) {
3575 mono_field_static_get_value_checked (vtable, field, v, error);
3576 return_val_if_nok (error, NULL);
3578 mono_field_get_value (obj, field, v);
3585 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3587 MONO_REQ_GC_UNSAFE_MODE;
3589 mono_error_init (error);
3591 const char *p = blob;
3592 mono_metadata_decode_blob_size (p, &p);
3595 case MONO_TYPE_BOOLEAN:
3598 *(guint8 *) value = *p;
3600 case MONO_TYPE_CHAR:
3603 *(guint16*) value = read16 (p);
3607 *(guint32*) value = read32 (p);
3611 *(guint64*) value = read64 (p);
3614 readr4 (p, (float*) value);
3617 readr8 (p, (double*) value);
3619 case MONO_TYPE_STRING:
3620 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3622 case MONO_TYPE_CLASS:
3623 *(gpointer*) value = NULL;
3627 g_warning ("type 0x%02x should not be in constant table", type);
3633 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3635 MONO_REQ_GC_NEUTRAL_MODE;
3637 MonoTypeEnum def_type;
3640 mono_error_init (error);
3642 data = mono_class_get_field_default_value (field, &def_type);
3643 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3647 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3649 MONO_REQ_GC_UNSAFE_MODE;
3653 mono_error_init (error);
3655 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3657 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3658 get_default_field_value (vt->domain, field, value, error);
3662 if (field->offset == -1) {
3663 /* Special static */
3664 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3665 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3667 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3669 mono_copy_value (field->type, value, src, TRUE);
3673 * mono_field_static_get_value:
3674 * @vt: vtable to the object
3675 * @field: MonoClassField describing the field to fetch information from
3676 * @value: where the value is returned
3678 * Use this routine to get the value of the static field @field value.
3680 * The pointer provided by value must be of the field type, for reference
3681 * types this is a MonoObject*, for value types its the actual pointer to
3686 * mono_field_static_get_value (vt, int_field, &i);
3689 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3691 MONO_REQ_GC_NEUTRAL_MODE;
3694 mono_field_static_get_value_checked (vt, field, value, &error);
3695 mono_error_cleanup (&error);
3699 * mono_field_static_get_value_checked:
3700 * @vt: vtable to the object
3701 * @field: MonoClassField describing the field to fetch information from
3702 * @value: where the value is returned
3703 * @error: set on error
3705 * Use this routine to get the value of the static field @field value.
3707 * The pointer provided by value must be of the field type, for reference
3708 * types this is a MonoObject*, for value types its the actual pointer to
3713 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3714 * if (!is_ok (error)) { ... }
3716 * On failure sets @error.
3719 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3721 MONO_REQ_GC_NEUTRAL_MODE;
3723 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3727 * mono_property_set_value:
3728 * @prop: MonoProperty to set
3729 * @obj: instance object on which to act
3730 * @params: parameters to pass to the propery
3731 * @exc: optional exception
3733 * Invokes the property's set method with the given arguments on the
3734 * object instance obj (or NULL for static properties).
3736 * You can pass NULL as the exc argument if you don't want to
3737 * catch exceptions, otherwise, *exc will be set to the exception
3738 * thrown, if any. if an exception is thrown, you can't use the
3739 * MonoObject* result from the function.
3742 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3744 MONO_REQ_GC_UNSAFE_MODE;
3747 do_runtime_invoke (prop->set, obj, params, exc, &error);
3748 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3749 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3751 mono_error_cleanup (&error);
3756 * mono_property_set_value_checked:
3757 * @prop: MonoProperty to set
3758 * @obj: instance object on which to act
3759 * @params: parameters to pass to the propery
3760 * @error: set on error
3762 * Invokes the property's set method with the given arguments on the
3763 * object instance obj (or NULL for static properties).
3765 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3766 * If an exception is thrown, it will be caught and returned via @error.
3769 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3771 MONO_REQ_GC_UNSAFE_MODE;
3775 mono_error_init (error);
3776 do_runtime_invoke (prop->set, obj, params, &exc, error);
3777 if (exc != NULL && is_ok (error))
3778 mono_error_set_exception_instance (error, (MonoException*)exc);
3779 return is_ok (error);
3783 * mono_property_get_value:
3784 * @prop: MonoProperty to fetch
3785 * @obj: instance object on which to act
3786 * @params: parameters to pass to the propery
3787 * @exc: optional exception
3789 * Invokes the property's get method with the given arguments on the
3790 * object instance obj (or NULL for static properties).
3792 * You can pass NULL as the exc argument if you don't want to
3793 * catch exceptions, otherwise, *exc will be set to the exception
3794 * thrown, if any. if an exception is thrown, you can't use the
3795 * MonoObject* result from the function.
3797 * Returns: the value from invoking the get method on the property.
3800 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3802 MONO_REQ_GC_UNSAFE_MODE;
3805 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3806 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3807 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3809 mono_error_cleanup (&error); /* FIXME don't raise here */
3816 * mono_property_get_value_checked:
3817 * @prop: MonoProperty to fetch
3818 * @obj: instance object on which to act
3819 * @params: parameters to pass to the propery
3820 * @error: set on error
3822 * Invokes the property's get method with the given arguments on the
3823 * object instance obj (or NULL for static properties).
3825 * If an exception is thrown, you can't use the
3826 * MonoObject* result from the function. The exception will be propagated via @error.
3828 * Returns: the value from invoking the get method on the property. On
3829 * failure returns NULL and sets @error.
3832 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3834 MONO_REQ_GC_UNSAFE_MODE;
3837 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3838 if (exc != NULL && !is_ok (error))
3839 mono_error_set_exception_instance (error, (MonoException*) exc);
3847 * mono_nullable_init:
3848 * @buf: The nullable structure to initialize.
3849 * @value: the value to initialize from
3850 * @klass: the type for the object
3852 * Initialize the nullable structure pointed to by @buf from @value which
3853 * should be a boxed value type. The size of @buf should be able to hold
3854 * as much data as the @klass->instance_size (which is the number of bytes
3855 * that will be copies).
3857 * Since Nullables have variable structure, we can not define a C
3858 * structure for them.
3861 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3863 MONO_REQ_GC_UNSAFE_MODE;
3865 MonoClass *param_class = klass->cast_class;
3867 mono_class_setup_fields_locking (klass);
3868 g_assert (klass->fields_inited);
3870 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3871 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3873 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3875 if (param_class->has_references)
3876 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3878 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3880 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3885 * mono_nullable_box:
3886 * @buf: The buffer representing the data to be boxed
3887 * @klass: the type to box it as.
3888 * @error: set on oerr
3890 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3891 * @buf. On failure returns NULL and sets @error
3894 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3896 MONO_REQ_GC_UNSAFE_MODE;
3898 mono_error_init (error);
3899 MonoClass *param_class = klass->cast_class;
3901 mono_class_setup_fields_locking (klass);
3902 g_assert (klass->fields_inited);
3904 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3905 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3907 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3908 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3909 return_val_if_nok (error, NULL);
3910 if (param_class->has_references)
3911 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3913 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3921 * mono_get_delegate_invoke:
3922 * @klass: The delegate class
3924 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3927 mono_get_delegate_invoke (MonoClass *klass)
3929 MONO_REQ_GC_NEUTRAL_MODE;
3933 /* This is called at runtime, so avoid the slower search in metadata */
3934 mono_class_setup_methods (klass);
3935 if (mono_class_has_failure (klass))
3937 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3942 * mono_get_delegate_begin_invoke:
3943 * @klass: The delegate class
3945 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3948 mono_get_delegate_begin_invoke (MonoClass *klass)
3950 MONO_REQ_GC_NEUTRAL_MODE;
3954 /* This is called at runtime, so avoid the slower search in metadata */
3955 mono_class_setup_methods (klass);
3956 if (mono_class_has_failure (klass))
3958 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3963 * mono_get_delegate_end_invoke:
3964 * @klass: The delegate class
3966 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3969 mono_get_delegate_end_invoke (MonoClass *klass)
3971 MONO_REQ_GC_NEUTRAL_MODE;
3975 /* This is called at runtime, so avoid the slower search in metadata */
3976 mono_class_setup_methods (klass);
3977 if (mono_class_has_failure (klass))
3979 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3984 * mono_runtime_delegate_invoke:
3985 * @delegate: pointer to a delegate object.
3986 * @params: parameters for the delegate.
3987 * @exc: Pointer to the exception result.
3989 * Invokes the delegate method @delegate with the parameters provided.
3991 * You can pass NULL as the exc argument if you don't want to
3992 * catch exceptions, otherwise, *exc will be set to the exception
3993 * thrown, if any. if an exception is thrown, you can't use the
3994 * MonoObject* result from the function.
3997 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3999 MONO_REQ_GC_UNSAFE_MODE;
4003 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
4005 mono_error_cleanup (&error);
4008 if (!is_ok (&error))
4009 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4013 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
4014 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4020 * mono_runtime_delegate_try_invoke:
4021 * @delegate: pointer to a delegate object.
4022 * @params: parameters for the delegate.
4023 * @exc: Pointer to the exception result.
4024 * @error: set on error
4026 * Invokes the delegate method @delegate with the parameters provided.
4028 * You can pass NULL as the exc argument if you don't want to
4029 * catch exceptions, otherwise, *exc will be set to the exception
4030 * thrown, if any. On failure to execute, @error will be set.
4031 * if an exception is thrown, you can't use the
4032 * MonoObject* result from the function.
4035 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4037 MONO_REQ_GC_UNSAFE_MODE;
4039 mono_error_init (error);
4041 MonoClass *klass = delegate->vtable->klass;
4044 im = mono_get_delegate_invoke (klass);
4046 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4049 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4051 o = mono_runtime_invoke_checked (im, delegate, params, error);
4058 * mono_runtime_delegate_invoke_checked:
4059 * @delegate: pointer to a delegate object.
4060 * @params: parameters for the delegate.
4061 * @error: set on error
4063 * Invokes the delegate method @delegate with the parameters provided.
4065 * On failure @error will be set and you can't use the MonoObject*
4066 * result from the function.
4069 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4071 mono_error_init (error);
4072 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4075 static char **main_args = NULL;
4076 static int num_main_args = 0;
4079 * mono_runtime_get_main_args:
4081 * Returns: a MonoArray with the arguments passed to the main program
4084 mono_runtime_get_main_args (void)
4086 MONO_REQ_GC_UNSAFE_MODE;
4088 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4089 mono_error_assert_ok (&error);
4094 * mono_runtime_get_main_args:
4095 * @error: set on error
4097 * Returns: a MonoArray with the arguments passed to the main
4098 * program. On failure returns NULL and sets @error.
4101 mono_runtime_get_main_args_checked (MonoError *error)
4105 MonoDomain *domain = mono_domain_get ();
4107 mono_error_init (error);
4109 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4110 return_val_if_nok (error, NULL);
4112 for (i = 0; i < num_main_args; ++i)
4113 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4119 free_main_args (void)
4121 MONO_REQ_GC_NEUTRAL_MODE;
4125 for (i = 0; i < num_main_args; ++i)
4126 g_free (main_args [i]);
4133 * mono_runtime_set_main_args:
4134 * @argc: number of arguments from the command line
4135 * @argv: array of strings from the command line
4137 * Set the command line arguments from an embedding application that doesn't otherwise call
4138 * mono_runtime_run_main ().
4141 mono_runtime_set_main_args (int argc, char* argv[])
4143 MONO_REQ_GC_NEUTRAL_MODE;
4148 main_args = g_new0 (char*, argc);
4149 num_main_args = argc;
4151 for (i = 0; i < argc; ++i) {
4154 utf8_arg = mono_utf8_from_external (argv[i]);
4155 if (utf8_arg == NULL) {
4156 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4157 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4161 main_args [i] = utf8_arg;
4168 * mono_runtime_run_main:
4169 * @method: the method to start the application with (usually Main)
4170 * @argc: number of arguments from the command line
4171 * @argv: array of strings from the command line
4172 * @exc: excetption results
4174 * Execute a standard Main() method (argc/argv contains the
4175 * executable name). This method also sets the command line argument value
4176 * needed by System.Environment.
4181 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4184 MONO_REQ_GC_UNSAFE_MODE;
4188 MonoArray *args = NULL;
4189 MonoDomain *domain = mono_domain_get ();
4190 gchar *utf8_fullpath;
4191 MonoMethodSignature *sig;
4193 g_assert (method != NULL);
4195 mono_thread_set_main (mono_thread_current ());
4197 main_args = g_new0 (char*, argc);
4198 num_main_args = argc;
4200 if (!g_path_is_absolute (argv [0])) {
4201 gchar *basename = g_path_get_basename (argv [0]);
4202 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4206 utf8_fullpath = mono_utf8_from_external (fullpath);
4207 if(utf8_fullpath == NULL) {
4208 /* Printing the arg text will cause glib to
4209 * whinge about "Invalid UTF-8", but at least
4210 * its relevant, and shows the problem text
4213 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4214 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4221 utf8_fullpath = mono_utf8_from_external (argv[0]);
4222 if(utf8_fullpath == NULL) {
4223 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4224 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4229 main_args [0] = utf8_fullpath;
4231 for (i = 1; i < argc; ++i) {
4234 utf8_arg=mono_utf8_from_external (argv[i]);
4235 if(utf8_arg==NULL) {
4236 /* Ditto the comment about Invalid UTF-8 here */
4237 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4238 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4242 main_args [i] = utf8_arg;
4247 sig = mono_method_signature (method);
4249 g_print ("Unable to load Main method.\n");
4253 if (sig->param_count) {
4254 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4255 mono_error_assert_ok (&error);
4256 for (i = 0; i < argc; ++i) {
4257 /* The encodings should all work, given that
4258 * we've checked all these args for the
4261 gchar *str = mono_utf8_from_external (argv [i]);
4262 MonoString *arg = mono_string_new (domain, str);
4263 mono_array_setref (args, i, arg);
4267 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4268 mono_error_assert_ok (&error);
4271 mono_assembly_set_main (method->klass->image->assembly);
4273 return mono_runtime_exec_main (method, args, exc);
4277 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4279 static MonoMethod *serialize_method;
4285 if (!serialize_method) {
4286 MonoClass *klass = mono_class_get_remoting_services_class ();
4287 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4290 if (!serialize_method) {
4295 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4300 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4301 if (*exc == NULL && !mono_error_ok (&error))
4302 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4304 mono_error_cleanup (&error);
4313 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4315 MONO_REQ_GC_UNSAFE_MODE;
4317 static MonoMethod *deserialize_method;
4323 if (!deserialize_method) {
4324 MonoClass *klass = mono_class_get_remoting_services_class ();
4325 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4327 if (!deserialize_method) {
4335 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4336 if (*exc == NULL && !mono_error_ok (&error))
4337 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4339 mono_error_cleanup (&error);
4347 #ifndef DISABLE_REMOTING
4349 make_transparent_proxy (MonoObject *obj, MonoError *error)
4351 MONO_REQ_GC_UNSAFE_MODE;
4353 static MonoMethod *get_proxy_method;
4355 MonoDomain *domain = mono_domain_get ();
4356 MonoRealProxy *real_proxy;
4357 MonoReflectionType *reflection_type;
4358 MonoTransparentProxy *transparent_proxy;
4360 mono_error_init (error);
4362 if (!get_proxy_method)
4363 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4365 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4367 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4368 return_val_if_nok (error, NULL);
4369 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4370 return_val_if_nok (error, NULL);
4372 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4373 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4375 MonoObject *exc = NULL;
4377 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4378 if (exc != NULL && is_ok (error))
4379 mono_error_set_exception_instance (error, (MonoException*)exc);
4381 return (MonoObject*) transparent_proxy;
4383 #endif /* DISABLE_REMOTING */
4386 * mono_object_xdomain_representation
4388 * @target_domain: a domain
4389 * @error: set on error.
4391 * Creates a representation of obj in the domain target_domain. This
4392 * is either a copy of obj arrived through via serialization and
4393 * deserialization or a proxy, depending on whether the object is
4394 * serializable or marshal by ref. obj must not be in target_domain.
4396 * If the object cannot be represented in target_domain, NULL is
4397 * returned and @error is set appropriately.
4400 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4402 MONO_REQ_GC_UNSAFE_MODE;
4404 mono_error_init (error);
4405 MonoObject *deserialized = NULL;
4407 #ifndef DISABLE_REMOTING
4408 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4409 deserialized = make_transparent_proxy (obj, error);
4414 gboolean failure = FALSE;
4415 MonoDomain *domain = mono_domain_get ();
4416 MonoObject *serialized;
4417 MonoObject *exc = NULL;
4419 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4420 serialized = serialize_object (obj, &failure, &exc);
4421 mono_domain_set_internal_with_options (target_domain, FALSE);
4423 deserialized = deserialize_object (serialized, &failure, &exc);
4424 if (domain != target_domain)
4425 mono_domain_set_internal_with_options (domain, FALSE);
4427 mono_error_set_exception_instance (error, (MonoException*)exc);
4430 return deserialized;
4433 /* Used in call_unhandled_exception_delegate */
4435 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4437 MONO_REQ_GC_UNSAFE_MODE;
4439 mono_error_init (error);
4442 MonoMethod *method = NULL;
4443 MonoBoolean is_terminating = TRUE;
4446 klass = mono_class_get_unhandled_exception_event_args_class ();
4447 mono_class_init (klass);
4449 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4450 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4454 args [1] = &is_terminating;
4456 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4457 return_val_if_nok (error, NULL);
4459 mono_runtime_invoke_checked (method, obj, args, error);
4460 return_val_if_nok (error, NULL);
4465 /* Used in mono_unhandled_exception */
4467 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4468 MONO_REQ_GC_UNSAFE_MODE;
4471 MonoObject *e = NULL;
4473 MonoDomain *current_domain = mono_domain_get ();
4475 if (domain != current_domain)
4476 mono_domain_set_internal_with_options (domain, FALSE);
4478 g_assert (domain == mono_object_domain (domain->domain));
4480 if (mono_object_domain (exc) != domain) {
4482 exc = mono_object_xdomain_representation (exc, domain, &error);
4484 if (!is_ok (&error)) {
4485 MonoError inner_error;
4486 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4487 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4488 mono_error_assert_ok (&inner_error);
4490 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4491 "System.Runtime.Serialization", "SerializationException",
4492 "Could not serialize unhandled exception.");
4496 g_assert (mono_object_domain (exc) == domain);
4498 pa [0] = domain->domain;
4499 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4500 mono_error_assert_ok (&error);
4501 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4502 if (!is_ok (&error)) {
4504 e = (MonoObject*)mono_error_convert_to_exception (&error);
4506 mono_error_cleanup (&error);
4509 if (domain != current_domain)
4510 mono_domain_set_internal_with_options (current_domain, FALSE);
4513 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4514 if (!mono_error_ok (&error)) {
4515 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4516 mono_error_cleanup (&error);
4518 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4524 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4527 * mono_runtime_unhandled_exception_policy_set:
4528 * @policy: the new policy
4530 * This is a VM internal routine.
4532 * Sets the runtime policy for handling unhandled exceptions.
4535 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4536 runtime_unhandled_exception_policy = policy;
4540 * mono_runtime_unhandled_exception_policy_get:
4542 * This is a VM internal routine.
4544 * Gets the runtime policy for handling unhandled exceptions.
4546 MonoRuntimeUnhandledExceptionPolicy
4547 mono_runtime_unhandled_exception_policy_get (void) {
4548 return runtime_unhandled_exception_policy;
4552 * mono_unhandled_exception:
4553 * @exc: exception thrown
4555 * This is a VM internal routine.
4557 * We call this function when we detect an unhandled exception
4558 * in the default domain.
4560 * It invokes the * UnhandledException event in AppDomain or prints
4561 * a warning to the console
4564 mono_unhandled_exception (MonoObject *exc)
4566 MONO_REQ_GC_UNSAFE_MODE;
4569 MonoClassField *field;
4570 MonoDomain *current_domain, *root_domain;
4571 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4573 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4576 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4579 current_domain = mono_domain_get ();
4580 root_domain = mono_get_root_domain ();
4582 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4583 mono_error_assert_ok (&error);
4584 if (current_domain != root_domain) {
4585 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4586 mono_error_assert_ok (&error);
4589 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4590 mono_print_unhandled_exception (exc);
4592 if (root_appdomain_delegate)
4593 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4594 if (current_appdomain_delegate)
4595 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4598 /* set exitcode only if we will abort the process */
4599 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4600 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4602 mono_environment_exitcode_set (1);
4607 * mono_runtime_exec_managed_code:
4608 * @domain: Application domain
4609 * @main_func: function to invoke from the execution thread
4610 * @main_args: parameter to the main_func
4612 * Launch a new thread to execute a function
4614 * main_func is called back from the thread with main_args as the
4615 * parameter. The callback function is expected to start Main()
4616 * eventually. This function then waits for all managed threads to
4618 * It is not necesseray anymore to execute managed code in a subthread,
4619 * so this function should not be used anymore by default: just
4620 * execute the code and then call mono_thread_manage ().
4623 mono_runtime_exec_managed_code (MonoDomain *domain,
4624 MonoMainThreadFunc main_func,
4628 mono_thread_create_checked (domain, main_func, main_args, &error);
4629 mono_error_assert_ok (&error);
4631 mono_thread_manage ();
4635 * Execute a standard Main() method (args doesn't contain the
4639 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4641 MONO_REQ_GC_UNSAFE_MODE;
4647 MonoCustomAttrInfo* cinfo;
4648 gboolean has_stathread_attribute;
4649 MonoInternalThread* thread = mono_thread_internal_current ();
4655 domain = mono_object_domain (args);
4656 if (!domain->entry_assembly) {
4658 MonoAssembly *assembly;
4660 assembly = method->klass->image->assembly;
4661 domain->entry_assembly = assembly;
4662 /* Domains created from another domain already have application_base and configuration_file set */
4663 if (domain->setup->application_base == NULL) {
4664 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4667 if (domain->setup->configuration_file == NULL) {
4668 str = g_strconcat (assembly->image->name, ".config", NULL);
4669 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4671 mono_domain_set_options_from_config (domain);
4675 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4676 mono_error_cleanup (&error); /* FIXME warn here? */
4678 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4680 mono_custom_attrs_free (cinfo);
4682 has_stathread_attribute = FALSE;
4684 if (has_stathread_attribute) {
4685 thread->apartment_state = ThreadApartmentState_STA;
4687 thread->apartment_state = ThreadApartmentState_MTA;
4689 mono_thread_init_apartment_state ();
4691 /* FIXME: check signature of method */
4692 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4695 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4696 if (*exc == NULL && !mono_error_ok (&error))
4697 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4699 mono_error_cleanup (&error);
4701 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4702 mono_error_raise_exception (&error); /* FIXME don't raise here */
4706 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4710 mono_environment_exitcode_set (rval);
4713 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4714 if (*exc == NULL && !mono_error_ok (&error))
4715 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4717 mono_error_cleanup (&error);
4719 mono_runtime_invoke_checked (method, NULL, pa, &error);
4720 mono_error_raise_exception (&error); /* FIXME don't raise here */
4726 /* If the return type of Main is void, only
4727 * set the exitcode if an exception was thrown
4728 * (we don't want to blow away an
4729 * explicitly-set exit code)
4732 mono_environment_exitcode_set (rval);
4739 /** invoke_array_extract_argument:
4740 * @params: array of arguments to the method.
4741 * @i: the index of the argument to extract.
4742 * @t: ith type from the method signature.
4743 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4744 * @error: set on error.
4746 * Given an array of method arguments, return the ith one using the corresponding type
4747 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4749 * On failure sets @error and returns NULL.
4752 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4754 MonoType *t_orig = t;
4755 gpointer result = NULL;
4756 mono_error_init (error);
4761 case MONO_TYPE_BOOLEAN:
4764 case MONO_TYPE_CHAR:
4773 case MONO_TYPE_VALUETYPE:
4774 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4775 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4776 result = mono_array_get (params, MonoObject*, i);
4778 *has_byref_nullables = TRUE;
4780 /* MS seems to create the objects if a null is passed in */
4781 if (!mono_array_get (params, MonoObject*, i)) {
4782 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4783 return_val_if_nok (error, NULL);
4784 mono_array_setref (params, i, o);
4789 * We can't pass the unboxed vtype byref to the callee, since
4790 * that would mean the callee would be able to modify boxed
4791 * primitive types. So we (and MS) make a copy of the boxed
4792 * object, pass that to the callee, and replace the original
4793 * boxed object in the arg array with the copy.
4795 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4796 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4797 return_val_if_nok (error, NULL);
4798 mono_array_setref (params, i, copy);
4801 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4804 case MONO_TYPE_STRING:
4805 case MONO_TYPE_OBJECT:
4806 case MONO_TYPE_CLASS:
4807 case MONO_TYPE_ARRAY:
4808 case MONO_TYPE_SZARRAY:
4810 result = mono_array_addr (params, MonoObject*, i);
4811 // FIXME: I need to check this code path
4813 result = mono_array_get (params, MonoObject*, i);
4815 case MONO_TYPE_GENERICINST:
4817 t = &t->data.generic_class->container_class->this_arg;
4819 t = &t->data.generic_class->container_class->byval_arg;
4821 case MONO_TYPE_PTR: {
4824 /* The argument should be an IntPtr */
4825 arg = mono_array_get (params, MonoObject*, i);
4829 g_assert (arg->vtable->klass == mono_defaults.int_class);
4830 result = ((MonoIntPtr*)arg)->m_value;
4835 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4840 * mono_runtime_invoke_array:
4841 * @method: method to invoke
4842 * @obJ: object instance
4843 * @params: arguments to the method
4844 * @exc: exception information.
4846 * Invokes the method represented by @method on the object @obj.
4848 * obj is the 'this' pointer, it should be NULL for static
4849 * methods, a MonoObject* for object instances and a pointer to
4850 * the value type for value types.
4852 * The params array contains the arguments to the method with the
4853 * same convention: MonoObject* pointers for object instances and
4854 * pointers to the value type otherwise. The _invoke_array
4855 * variant takes a C# object[] as the params argument (MonoArray
4856 * *params): in this case the value types are boxed inside the
4857 * respective reference representation.
4859 * From unmanaged code you'll usually use the
4860 * mono_runtime_invoke_checked() variant.
4862 * Note that this function doesn't handle virtual methods for
4863 * you, it will exec the exact method you pass: we still need to
4864 * expose a function to lookup the derived class implementation
4865 * of a virtual method (there are examples of this in the code,
4868 * You can pass NULL as the exc argument if you don't want to
4869 * catch exceptions, otherwise, *exc will be set to the exception
4870 * thrown, if any. if an exception is thrown, you can't use the
4871 * MonoObject* result from the function.
4873 * If the method returns a value type, it is boxed in an object
4877 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4882 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4884 mono_error_cleanup (&error);
4887 if (!is_ok (&error))
4888 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4892 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4893 mono_error_raise_exception (&error); /* FIXME don't raise here */
4899 * mono_runtime_invoke_array_checked:
4900 * @method: method to invoke
4901 * @obJ: object instance
4902 * @params: arguments to the method
4903 * @error: set on failure.
4905 * Invokes the method represented by @method on the object @obj.
4907 * obj is the 'this' pointer, it should be NULL for static
4908 * methods, a MonoObject* for object instances and a pointer to
4909 * the value type for value types.
4911 * The params array contains the arguments to the method with the
4912 * same convention: MonoObject* pointers for object instances and
4913 * pointers to the value type otherwise. The _invoke_array
4914 * variant takes a C# object[] as the params argument (MonoArray
4915 * *params): in this case the value types are boxed inside the
4916 * respective reference representation.
4918 * From unmanaged code you'll usually use the
4919 * mono_runtime_invoke_checked() variant.
4921 * Note that this function doesn't handle virtual methods for
4922 * you, it will exec the exact method you pass: we still need to
4923 * expose a function to lookup the derived class implementation
4924 * of a virtual method (there are examples of this in the code,
4927 * On failure or exception, @error will be set. In that case, you
4928 * can't use the MonoObject* result from the function.
4930 * If the method returns a value type, it is boxed in an object
4934 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4937 mono_error_init (error);
4938 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4942 * mono_runtime_try_invoke_array:
4943 * @method: method to invoke
4944 * @obJ: object instance
4945 * @params: arguments to the method
4946 * @exc: exception information.
4947 * @error: set on failure.
4949 * Invokes the method represented by @method on the object @obj.
4951 * obj is the 'this' pointer, it should be NULL for static
4952 * methods, a MonoObject* for object instances and a pointer to
4953 * the value type for value types.
4955 * The params array contains the arguments to the method with the
4956 * same convention: MonoObject* pointers for object instances and
4957 * pointers to the value type otherwise. The _invoke_array
4958 * variant takes a C# object[] as the params argument (MonoArray
4959 * *params): in this case the value types are boxed inside the
4960 * respective reference representation.
4962 * From unmanaged code you'll usually use the
4963 * mono_runtime_invoke_checked() variant.
4965 * Note that this function doesn't handle virtual methods for
4966 * you, it will exec the exact method you pass: we still need to
4967 * expose a function to lookup the derived class implementation
4968 * of a virtual method (there are examples of this in the code,
4971 * You can pass NULL as the exc argument if you don't want to catch
4972 * exceptions, otherwise, *exc will be set to the exception thrown, if
4973 * any. On other failures, @error will be set. If an exception is
4974 * thrown or there's an error, you can't use the MonoObject* result
4975 * from the function.
4977 * If the method returns a value type, it is boxed in an object
4981 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4982 MonoObject **exc, MonoError *error)
4984 MONO_REQ_GC_UNSAFE_MODE;
4986 mono_error_init (error);
4988 MonoMethodSignature *sig = mono_method_signature (method);
4989 gpointer *pa = NULL;
4992 gboolean has_byref_nullables = FALSE;
4994 if (NULL != params) {
4995 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4996 for (i = 0; i < mono_array_length (params); i++) {
4997 MonoType *t = sig->params [i];
4998 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
4999 return_val_if_nok (error, NULL);
5003 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5006 if (mono_class_is_nullable (method->klass)) {
5007 /* Need to create a boxed vtype instead */
5013 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5018 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5019 mono_error_assert_ok (error);
5020 g_assert (obj); /*maybe we should raise a TLE instead?*/
5021 #ifndef DISABLE_REMOTING
5022 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5023 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5026 if (method->klass->valuetype)
5027 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5030 } else if (method->klass->valuetype) {
5031 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5032 return_val_if_nok (error, NULL);
5036 mono_runtime_try_invoke (method, o, pa, exc, error);
5038 mono_runtime_invoke_checked (method, o, pa, error);
5041 return (MonoObject *)obj;
5043 if (mono_class_is_nullable (method->klass)) {
5044 MonoObject *nullable;
5046 /* Convert the unboxed vtype into a Nullable structure */
5047 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5048 return_val_if_nok (error, NULL);
5050 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5051 return_val_if_nok (error, NULL);
5052 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5053 obj = mono_object_unbox (nullable);
5056 /* obj must be already unboxed if needed */
5058 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5060 res = mono_runtime_invoke_checked (method, obj, pa, error);
5062 return_val_if_nok (error, NULL);
5064 if (sig->ret->type == MONO_TYPE_PTR) {
5065 MonoClass *pointer_class;
5066 static MonoMethod *box_method;
5068 MonoObject *box_exc;
5071 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5072 * convert it to a Pointer object.
5074 pointer_class = mono_class_get_pointer_class ();
5076 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5078 g_assert (res->vtable->klass == mono_defaults.int_class);
5079 box_args [0] = ((MonoIntPtr*)res)->m_value;
5080 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5081 return_val_if_nok (error, NULL);
5083 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5084 g_assert (box_exc == NULL);
5085 mono_error_assert_ok (error);
5088 if (has_byref_nullables) {
5090 * The runtime invoke wrapper already converted byref nullables back,
5091 * and stored them in pa, we just need to copy them back to the
5094 for (i = 0; i < mono_array_length (params); i++) {
5095 MonoType *t = sig->params [i];
5097 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5098 mono_array_setref (params, i, pa [i]);
5108 * @klass: the class of the object that we want to create
5110 * Returns: a newly created object whose definition is
5111 * looked up using @klass. This will not invoke any constructors,
5112 * so the consumer of this routine has to invoke any constructors on
5113 * its own to initialize the object.
5115 * It returns NULL on failure.
5118 mono_object_new (MonoDomain *domain, MonoClass *klass)
5120 MONO_REQ_GC_UNSAFE_MODE;
5124 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5126 mono_error_cleanup (&error);
5131 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5133 MONO_REQ_GC_UNSAFE_MODE;
5137 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5139 mono_error_set_pending_exception (&error);
5144 * mono_object_new_checked:
5145 * @klass: the class of the object that we want to create
5146 * @error: set on error
5148 * Returns: a newly created object whose definition is
5149 * looked up using @klass. This will not invoke any constructors,
5150 * so the consumer of this routine has to invoke any constructors on
5151 * its own to initialize the object.
5153 * It returns NULL on failure and sets @error.
5156 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5158 MONO_REQ_GC_UNSAFE_MODE;
5162 vtable = mono_class_vtable (domain, klass);
5163 g_assert (vtable); /* FIXME don't swallow the error */
5165 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5170 * mono_object_new_pinned:
5172 * Same as mono_object_new, but the returned object will be pinned.
5173 * For SGEN, these objects will only be freed at appdomain unload.
5176 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5178 MONO_REQ_GC_UNSAFE_MODE;
5182 mono_error_init (error);
5184 vtable = mono_class_vtable (domain, klass);
5185 g_assert (vtable); /* FIXME don't swallow the error */
5187 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5189 if (G_UNLIKELY (!o))
5190 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5191 else if (G_UNLIKELY (vtable->klass->has_finalize))
5192 mono_object_register_finalizer (o);
5198 * mono_object_new_specific:
5199 * @vtable: the vtable of the object that we want to create
5201 * Returns: A newly created object with class and domain specified
5205 mono_object_new_specific (MonoVTable *vtable)
5208 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5209 mono_error_cleanup (&error);
5215 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5217 MONO_REQ_GC_UNSAFE_MODE;
5221 mono_error_init (error);
5223 /* check for is_com_object for COM Interop */
5224 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5227 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5230 MonoClass *klass = mono_class_get_activation_services_class ();
5233 mono_class_init (klass);
5235 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5237 mono_error_set_not_supported (error, "Linked away.");
5240 vtable->domain->create_proxy_for_type_method = im;
5243 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5244 if (!mono_error_ok (error))
5247 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5248 if (!mono_error_ok (error))
5255 return mono_object_new_alloc_specific_checked (vtable, error);
5259 ves_icall_object_new_specific (MonoVTable *vtable)
5262 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5263 mono_error_set_pending_exception (&error);
5269 * mono_object_new_alloc_specific:
5270 * @vtable: virtual table for the object.
5272 * This function allocates a new `MonoObject` with the type derived
5273 * from the @vtable information. If the class of this object has a
5274 * finalizer, then the object will be tracked for finalization.
5276 * This method might raise an exception on errors. Use the
5277 * `mono_object_new_fast_checked` method if you want to manually raise
5280 * Returns: the allocated object.
5283 mono_object_new_alloc_specific (MonoVTable *vtable)
5286 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5287 mono_error_cleanup (&error);
5293 * mono_object_new_alloc_specific_checked:
5294 * @vtable: virtual table for the object.
5295 * @error: holds the error return value.
5297 * This function allocates a new `MonoObject` with the type derived
5298 * from the @vtable information. If the class of this object has a
5299 * finalizer, then the object will be tracked for finalization.
5301 * If there is not enough memory, the @error parameter will be set
5302 * and will contain a user-visible message with the amount of bytes
5303 * that were requested.
5305 * Returns: the allocated object, or NULL if there is not enough memory
5309 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5311 MONO_REQ_GC_UNSAFE_MODE;
5315 mono_error_init (error);
5317 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5319 if (G_UNLIKELY (!o))
5320 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5321 else if (G_UNLIKELY (vtable->klass->has_finalize))
5322 mono_object_register_finalizer (o);
5328 * mono_object_new_fast:
5329 * @vtable: virtual table for the object.
5331 * This function allocates a new `MonoObject` with the type derived
5332 * from the @vtable information. The returned object is not tracked
5333 * for finalization. If your object implements a finalizer, you should
5334 * use `mono_object_new_alloc_specific` instead.
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_fast (MonoVTable *vtable)
5346 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5347 mono_error_cleanup (&error);
5353 * mono_object_new_fast_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. The returned object is not tracked
5359 * for finalization. If your object implements a finalizer, you should
5360 * use `mono_object_new_alloc_specific_checked` instead.
5362 * If there is not enough memory, the @error parameter will be set
5363 * and will contain a user-visible message with the amount of bytes
5364 * that were requested.
5366 * Returns: the allocated object, or NULL if there is not enough memory
5370 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5372 MONO_REQ_GC_UNSAFE_MODE;
5376 mono_error_init (error);
5378 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5380 if (G_UNLIKELY (!o))
5381 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5387 ves_icall_object_new_fast (MonoVTable *vtable)
5390 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5391 mono_error_set_pending_exception (&error);
5397 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5399 MONO_REQ_GC_UNSAFE_MODE;
5403 mono_error_init (error);
5405 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5407 if (G_UNLIKELY (!o))
5408 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5409 else if (G_UNLIKELY (vtable->klass->has_finalize))
5410 mono_object_register_finalizer (o);
5416 * mono_class_get_allocation_ftn:
5418 * @for_box: the object will be used for boxing
5419 * @pass_size_in_words:
5421 * Return the allocation function appropriate for the given class.
5425 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5427 MONO_REQ_GC_NEUTRAL_MODE;
5429 *pass_size_in_words = FALSE;
5431 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5432 return ves_icall_object_new_specific;
5434 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5436 return ves_icall_object_new_fast;
5439 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5440 * of the overhead of parameter passing.
5443 *pass_size_in_words = TRUE;
5444 #ifdef GC_REDIRECT_TO_LOCAL
5445 return GC_local_gcj_fast_malloc;
5447 return GC_gcj_fast_malloc;
5452 return ves_icall_object_new_specific;
5456 * mono_object_new_from_token:
5457 * @image: Context where the type_token is hosted
5458 * @token: a token of the type that we want to create
5460 * Returns: A newly created object whose definition is
5461 * looked up using @token in the @image image
5464 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5466 MONO_REQ_GC_UNSAFE_MODE;
5472 klass = mono_class_get_checked (image, token, &error);
5473 mono_error_assert_ok (&error);
5475 result = mono_object_new_checked (domain, klass, &error);
5477 mono_error_cleanup (&error);
5484 * mono_object_clone:
5485 * @obj: the object to clone
5487 * Returns: A newly created object who is a shallow copy of @obj
5490 mono_object_clone (MonoObject *obj)
5493 MonoObject *o = mono_object_clone_checked (obj, &error);
5494 mono_error_cleanup (&error);
5500 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5502 MONO_REQ_GC_UNSAFE_MODE;
5507 mono_error_init (error);
5509 size = obj->vtable->klass->instance_size;
5511 if (obj->vtable->klass->rank)
5512 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5514 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5516 if (G_UNLIKELY (!o)) {
5517 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5521 /* If the object doesn't contain references this will do a simple memmove. */
5522 mono_gc_wbarrier_object_copy (o, obj);
5524 if (obj->vtable->klass->has_finalize)
5525 mono_object_register_finalizer (o);
5530 * mono_array_full_copy:
5531 * @src: source array to copy
5532 * @dest: destination array
5534 * Copies the content of one array to another with exactly the same type and size.
5537 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5539 MONO_REQ_GC_UNSAFE_MODE;
5542 MonoClass *klass = src->obj.vtable->klass;
5544 g_assert (klass == dest->obj.vtable->klass);
5546 size = mono_array_length (src);
5547 g_assert (size == mono_array_length (dest));
5548 size *= mono_array_element_size (klass);
5550 if (klass->element_class->valuetype) {
5551 if (klass->element_class->has_references)
5552 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5554 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5556 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5559 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5564 * mono_array_clone_in_domain:
5565 * @domain: the domain in which the array will be cloned into
5566 * @array: the array to clone
5567 * @error: set on error
5569 * This routine returns a copy of the array that is hosted on the
5570 * specified MonoDomain. On failure returns NULL and sets @error.
5573 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5575 MONO_REQ_GC_UNSAFE_MODE;
5580 MonoClass *klass = array->obj.vtable->klass;
5582 mono_error_init (error);
5584 if (array->bounds == NULL) {
5585 size = mono_array_length (array);
5586 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5587 return_val_if_nok (error, NULL);
5589 size *= mono_array_element_size (klass);
5591 if (klass->element_class->valuetype) {
5592 if (klass->element_class->has_references)
5593 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5595 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5597 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5600 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5605 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5606 size = mono_array_element_size (klass);
5607 for (i = 0; i < klass->rank; ++i) {
5608 sizes [i] = array->bounds [i].length;
5609 size *= array->bounds [i].length;
5610 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5612 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5613 return_val_if_nok (error, NULL);
5615 if (klass->element_class->valuetype) {
5616 if (klass->element_class->has_references)
5617 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5619 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5621 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5624 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5632 * @array: the array to clone
5634 * Returns: A newly created array who is a shallow copy of @array
5637 mono_array_clone (MonoArray *array)
5639 MONO_REQ_GC_UNSAFE_MODE;
5642 MonoArray *result = mono_array_clone_checked (array, &error);
5643 mono_error_cleanup (&error);
5648 * mono_array_clone_checked:
5649 * @array: the array to clone
5650 * @error: set on error
5652 * Returns: A newly created array who is a shallow copy of @array. On
5653 * failure returns NULL and sets @error.
5656 mono_array_clone_checked (MonoArray *array, MonoError *error)
5659 MONO_REQ_GC_UNSAFE_MODE;
5660 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5663 /* helper macros to check for overflow when calculating the size of arrays */
5664 #ifdef MONO_BIG_ARRAYS
5665 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5666 #define MYGUINT_MAX MYGUINT64_MAX
5667 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5668 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5669 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5670 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5671 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5673 #define MYGUINT32_MAX 4294967295U
5674 #define MYGUINT_MAX MYGUINT32_MAX
5675 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5676 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5677 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5678 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5679 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5683 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5685 MONO_REQ_GC_NEUTRAL_MODE;
5689 byte_len = mono_array_element_size (klass);
5690 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5693 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5695 byte_len += MONO_SIZEOF_MONO_ARRAY;
5703 * mono_array_new_full:
5704 * @domain: domain where the object is created
5705 * @array_class: array class
5706 * @lengths: lengths for each dimension in the array
5707 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5709 * This routine creates a new array objects with the given dimensions,
5710 * lower bounds and type.
5713 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5716 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5717 mono_error_cleanup (&error);
5723 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5725 MONO_REQ_GC_UNSAFE_MODE;
5727 uintptr_t byte_len = 0, len, bounds_size;
5730 MonoArrayBounds *bounds;
5734 mono_error_init (error);
5736 if (!array_class->inited)
5737 mono_class_init (array_class);
5741 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5742 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5744 if (len > MONO_ARRAY_MAX_INDEX) {
5745 mono_error_set_generic_error (error, "System", "OverflowException", "");
5750 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5752 for (i = 0; i < array_class->rank; ++i) {
5753 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5754 mono_error_set_generic_error (error, "System", "OverflowException", "");
5757 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5758 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5765 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5766 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5772 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5773 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5776 byte_len = (byte_len + 3) & ~3;
5777 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5778 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5781 byte_len += bounds_size;
5784 * Following three lines almost taken from mono_object_new ():
5785 * they need to be kept in sync.
5787 vtable = mono_class_vtable_full (domain, array_class, error);
5788 return_val_if_nok (error, NULL);
5791 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5793 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5795 if (G_UNLIKELY (!o)) {
5796 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5800 array = (MonoArray*)o;
5802 bounds = array->bounds;
5805 for (i = 0; i < array_class->rank; ++i) {
5806 bounds [i].length = lengths [i];
5808 bounds [i].lower_bound = lower_bounds [i];
5817 * @domain: domain where the object is created
5818 * @eclass: element class
5819 * @n: number of array elements
5821 * This routine creates a new szarray with @n elements of type @eclass.
5824 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5826 MONO_REQ_GC_UNSAFE_MODE;
5829 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5830 mono_error_cleanup (&error);
5835 * mono_array_new_checked:
5836 * @domain: domain where the object is created
5837 * @eclass: element class
5838 * @n: number of array elements
5839 * @error: set on error
5841 * This routine creates a new szarray with @n elements of type @eclass.
5842 * On failure returns NULL and sets @error.
5845 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5849 mono_error_init (error);
5851 ac = mono_array_class_get (eclass, 1);
5854 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5855 return_val_if_nok (error, NULL);
5857 return mono_array_new_specific_checked (vtable, n, error);
5861 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5864 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5865 mono_error_set_pending_exception (&error);
5871 * mono_array_new_specific:
5872 * @vtable: a vtable in the appropriate domain for an initialized class
5873 * @n: number of array elements
5875 * This routine is a fast alternative to mono_array_new() for code which
5876 * can be sure about the domain it operates in.
5879 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5882 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5883 mono_error_cleanup (&error);
5889 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5891 MONO_REQ_GC_UNSAFE_MODE;
5896 mono_error_init (error);
5898 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5899 mono_error_set_generic_error (error, "System", "OverflowException", "");
5903 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5904 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5907 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5909 if (G_UNLIKELY (!o)) {
5910 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5914 return (MonoArray*)o;
5918 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5921 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5922 mono_error_set_pending_exception (&error);
5928 * mono_string_new_utf16:
5929 * @text: a pointer to an utf16 string
5930 * @len: the length of the string
5932 * Returns: A newly created string object which contains @text.
5935 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5937 MONO_REQ_GC_UNSAFE_MODE;
5940 MonoString *res = NULL;
5941 res = mono_string_new_utf16_checked (domain, text, len, &error);
5942 mono_error_cleanup (&error);
5948 * mono_string_new_utf16_checked:
5949 * @text: a pointer to an utf16 string
5950 * @len: the length of the string
5951 * @error: written on error.
5953 * Returns: A newly created string object which contains @text.
5954 * On error, returns NULL and sets @error.
5957 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5959 MONO_REQ_GC_UNSAFE_MODE;
5963 mono_error_init (error);
5965 s = mono_string_new_size_checked (domain, len, error);
5967 memcpy (mono_string_chars (s), text, len * 2);
5973 * mono_string_new_utf32:
5974 * @text: a pointer to an utf32 string
5975 * @len: the length of the string
5976 * @error: set on failure.
5978 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5981 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5983 MONO_REQ_GC_UNSAFE_MODE;
5986 mono_unichar2 *utf16_output = NULL;
5987 gint32 utf16_len = 0;
5988 GError *gerror = NULL;
5989 glong items_written;
5991 mono_error_init (error);
5992 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5995 g_error_free (gerror);
5997 while (utf16_output [utf16_len]) utf16_len++;
5999 s = mono_string_new_size_checked (domain, utf16_len, error);
6000 return_val_if_nok (error, NULL);
6002 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6004 g_free (utf16_output);
6010 * mono_string_new_utf32:
6011 * @text: a pointer to an utf32 string
6012 * @len: the length of the string
6014 * Returns: A newly created string object which contains @text.
6017 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6020 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6021 mono_error_cleanup (&error);
6026 * mono_string_new_size:
6027 * @text: a pointer to an utf16 string
6028 * @len: the length of the string
6030 * Returns: A newly created string object of @len
6033 mono_string_new_size (MonoDomain *domain, gint32 len)
6036 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6037 mono_error_cleanup (&error);
6043 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6045 MONO_REQ_GC_UNSAFE_MODE;
6051 mono_error_init (error);
6053 /* check for overflow */
6054 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6055 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6059 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6060 g_assert (size > 0);
6062 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6065 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6067 if (G_UNLIKELY (!s)) {
6068 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6076 * mono_string_new_len:
6077 * @text: a pointer to an utf8 string
6078 * @length: number of bytes in @text to consider
6080 * Returns: A newly created string object which contains @text.
6083 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6085 MONO_REQ_GC_UNSAFE_MODE;
6088 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6089 mono_error_cleanup (&error);
6094 * mono_string_new_len_checked:
6095 * @text: a pointer to an utf8 string
6096 * @length: number of bytes in @text to consider
6097 * @error: set on error
6099 * Returns: A newly created string object which contains @text. On
6100 * failure returns NULL and sets @error.
6103 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6105 MONO_REQ_GC_UNSAFE_MODE;
6107 mono_error_init (error);
6109 GError *eg_error = NULL;
6110 MonoString *o = NULL;
6112 glong items_written;
6114 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6117 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6119 g_error_free (eg_error);
6128 * @text: a pointer to an utf8 string
6130 * Returns: A newly created string object which contains @text.
6132 * This function asserts if it cannot allocate a new string.
6134 * @deprecated Use mono_string_new_checked in new code.
6137 mono_string_new (MonoDomain *domain, const char *text)
6140 MonoString *res = NULL;
6141 res = mono_string_new_checked (domain, text, &error);
6142 mono_error_assert_ok (&error);
6147 * mono_string_new_checked:
6148 * @text: a pointer to an utf8 string
6149 * @merror: set on error
6151 * Returns: A newly created string object which contains @text.
6152 * On error returns NULL and sets @merror.
6155 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6157 MONO_REQ_GC_UNSAFE_MODE;
6159 GError *eg_error = NULL;
6160 MonoString *o = NULL;
6162 glong items_written;
6165 mono_error_init (error);
6169 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6172 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6174 g_error_free (eg_error);
6178 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6183 MonoString *o = NULL;
6185 if (!g_utf8_validate (text, -1, &end)) {
6186 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6190 len = g_utf8_strlen (text, -1);
6191 o = mono_string_new_size_checked (domain, len, error);
6194 str = mono_string_chars (o);
6196 while (text < end) {
6197 *str++ = g_utf8_get_char (text);
6198 text = g_utf8_next_char (text);
6207 * mono_string_new_wrapper:
6208 * @text: pointer to utf8 characters.
6210 * Helper function to create a string object from @text in the current domain.
6213 mono_string_new_wrapper (const char *text)
6215 MONO_REQ_GC_UNSAFE_MODE;
6217 MonoDomain *domain = mono_domain_get ();
6220 return mono_string_new (domain, text);
6227 * @class: the class of the value
6228 * @value: a pointer to the unboxed data
6230 * Returns: A newly created object which contains @value.
6233 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6236 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6237 mono_error_cleanup (&error);
6242 * mono_value_box_checked:
6243 * @domain: the domain of the new object
6244 * @class: the class of the value
6245 * @value: a pointer to the unboxed data
6246 * @error: set on error
6248 * Returns: A newly created object which contains @value. On failure
6249 * returns NULL and sets @error.
6252 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6254 MONO_REQ_GC_UNSAFE_MODE;
6259 mono_error_init (error);
6261 g_assert (klass->valuetype);
6262 if (mono_class_is_nullable (klass))
6263 return mono_nullable_box ((guint8 *)value, klass, error);
6265 vtable = mono_class_vtable (domain, klass);
6268 size = mono_class_instance_size (klass);
6269 res = mono_object_new_alloc_specific_checked (vtable, error);
6270 return_val_if_nok (error, NULL);
6272 size = size - sizeof (MonoObject);
6275 g_assert (size == mono_class_value_size (klass, NULL));
6276 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6278 #if NO_UNALIGNED_ACCESS
6279 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6283 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6286 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6289 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6292 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6295 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6299 if (klass->has_finalize) {
6300 mono_object_register_finalizer (res);
6301 return_val_if_nok (error, NULL);
6308 * @dest: destination pointer
6309 * @src: source pointer
6310 * @klass: a valuetype class
6312 * Copy a valuetype from @src to @dest. This function must be used
6313 * when @klass contains references fields.
6316 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6318 MONO_REQ_GC_UNSAFE_MODE;
6320 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6324 * mono_value_copy_array:
6325 * @dest: destination array
6326 * @dest_idx: index in the @dest array
6327 * @src: source pointer
6328 * @count: number of items
6330 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6331 * This function must be used when @klass contains references fields.
6332 * Overlap is handled.
6335 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6337 MONO_REQ_GC_UNSAFE_MODE;
6339 int size = mono_array_element_size (dest->obj.vtable->klass);
6340 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6341 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6342 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6346 * mono_object_get_domain:
6347 * @obj: object to query
6349 * Returns: the MonoDomain where the object is hosted
6352 mono_object_get_domain (MonoObject *obj)
6354 MONO_REQ_GC_UNSAFE_MODE;
6356 return mono_object_domain (obj);
6360 * mono_object_get_class:
6361 * @obj: object to query
6363 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6365 * Returns: the MonoClass of the object.
6368 mono_object_get_class (MonoObject *obj)
6370 MONO_REQ_GC_UNSAFE_MODE;
6372 return mono_object_class (obj);
6375 * mono_object_get_size:
6376 * @o: object to query
6378 * Returns: the size, in bytes, of @o
6381 mono_object_get_size (MonoObject* o)
6383 MONO_REQ_GC_UNSAFE_MODE;
6385 MonoClass* klass = mono_object_class (o);
6386 if (klass == mono_defaults.string_class) {
6387 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6388 } else if (o->vtable->rank) {
6389 MonoArray *array = (MonoArray*)o;
6390 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6391 if (array->bounds) {
6394 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6398 return mono_class_instance_size (klass);
6403 * mono_object_unbox:
6404 * @obj: object to unbox
6406 * Returns: a pointer to the start of the valuetype boxed in this
6409 * This method will assert if the object passed is not a valuetype.
6412 mono_object_unbox (MonoObject *obj)
6414 MONO_REQ_GC_UNSAFE_MODE;
6416 /* add assert for valuetypes? */
6417 g_assert (obj->vtable->klass->valuetype);
6418 return ((char*)obj) + sizeof (MonoObject);
6422 * mono_object_isinst:
6424 * @klass: a pointer to a class
6426 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6429 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6431 MONO_REQ_GC_UNSAFE_MODE;
6434 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6435 mono_error_cleanup (&error);
6441 * mono_object_isinst_checked:
6443 * @klass: a pointer to a class
6444 * @error: set on error
6446 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6447 * On failure returns NULL and sets @error.
6450 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6452 MONO_REQ_GC_UNSAFE_MODE;
6454 mono_error_init (error);
6456 MonoObject *result = NULL;
6459 mono_class_init (klass);
6461 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6462 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6469 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6473 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6475 MONO_REQ_GC_UNSAFE_MODE;
6478 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6479 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6484 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6486 MONO_REQ_GC_UNSAFE_MODE;
6490 mono_error_init (error);
6497 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6498 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6502 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6503 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6506 MonoClass *oklass = vt->klass;
6507 if (mono_class_is_transparent_proxy (oklass))
6508 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6510 mono_class_setup_supertypes (klass);
6511 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6514 #ifndef DISABLE_REMOTING
6515 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6517 MonoDomain *domain = mono_domain_get ();
6519 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6520 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6521 MonoMethod *im = NULL;
6524 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6526 mono_error_set_not_supported (error, "Linked away.");
6529 im = mono_object_get_virtual_method (rp, im);
6532 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6533 return_val_if_nok (error, NULL);
6536 res = mono_runtime_invoke_checked (im, rp, pa, error);
6537 return_val_if_nok (error, NULL);
6539 if (*(MonoBoolean *) mono_object_unbox(res)) {
6540 /* Update the vtable of the remote type, so it can safely cast to this new type */
6541 mono_upgrade_remote_class (domain, obj, klass, error);
6542 return_val_if_nok (error, NULL);
6546 #endif /* DISABLE_REMOTING */
6551 * mono_object_castclass_mbyref:
6553 * @klass: a pointer to a class
6555 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6558 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6560 MONO_REQ_GC_UNSAFE_MODE;
6563 if (!obj) return NULL;
6564 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6565 mono_error_cleanup (&error);
6570 MonoDomain *orig_domain;
6576 str_lookup (MonoDomain *domain, gpointer user_data)
6578 MONO_REQ_GC_UNSAFE_MODE;
6580 LDStrInfo *info = (LDStrInfo *)user_data;
6581 if (info->res || domain == info->orig_domain)
6583 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6587 mono_string_get_pinned (MonoString *str, MonoError *error)
6589 MONO_REQ_GC_UNSAFE_MODE;
6591 mono_error_init (error);
6593 /* We only need to make a pinned version of a string if this is a moving GC */
6594 if (!mono_gc_is_moving ())
6598 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6599 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6601 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6602 news->length = mono_string_length (str);
6604 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6610 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6612 MONO_REQ_GC_UNSAFE_MODE;
6614 MonoGHashTable *ldstr_table;
6615 MonoString *s, *res;
6618 mono_error_init (error);
6620 domain = ((MonoObject *)str)->vtable->domain;
6621 ldstr_table = domain->ldstr_table;
6623 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6629 /* Allocate outside the lock */
6631 s = mono_string_get_pinned (str, error);
6632 return_val_if_nok (error, NULL);
6635 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6640 mono_g_hash_table_insert (ldstr_table, s, s);
6645 LDStrInfo ldstr_info;
6646 ldstr_info.orig_domain = domain;
6647 ldstr_info.ins = str;
6648 ldstr_info.res = NULL;
6650 mono_domain_foreach (str_lookup, &ldstr_info);
6651 if (ldstr_info.res) {
6653 * the string was already interned in some other domain:
6654 * intern it in the current one as well.
6656 mono_g_hash_table_insert (ldstr_table, str, str);
6666 * mono_string_is_interned:
6667 * @o: String to probe
6669 * Returns whether the string has been interned.
6672 mono_string_is_interned (MonoString *o)
6675 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6676 /* This function does not fail. */
6677 mono_error_assert_ok (&error);
6682 * mono_string_intern:
6683 * @o: String to intern
6685 * Interns the string passed.
6686 * Returns: The interned string.
6689 mono_string_intern (MonoString *str)
6692 MonoString *result = mono_string_intern_checked (str, &error);
6693 mono_error_assert_ok (&error);
6698 * mono_string_intern_checked:
6699 * @o: String to intern
6700 * @error: set on error.
6702 * Interns the string passed.
6703 * Returns: The interned string. On failure returns NULL and sets @error
6706 mono_string_intern_checked (MonoString *str, MonoError *error)
6708 MONO_REQ_GC_UNSAFE_MODE;
6710 mono_error_init (error);
6712 return mono_string_is_interned_lookup (str, TRUE, error);
6717 * @domain: the domain where the string will be used.
6718 * @image: a metadata context
6719 * @idx: index into the user string table.
6721 * Implementation for the ldstr opcode.
6722 * Returns: a loaded string from the @image/@idx combination.
6725 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6728 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6729 mono_error_cleanup (&error);
6734 * mono_ldstr_checked:
6735 * @domain: the domain where the string will be used.
6736 * @image: a metadata context
6737 * @idx: index into the user string table.
6738 * @error: set on error.
6740 * Implementation for the ldstr opcode.
6741 * Returns: a loaded string from the @image/@idx combination.
6742 * On failure returns NULL and sets @error.
6745 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6747 MONO_REQ_GC_UNSAFE_MODE;
6748 mono_error_init (error);
6750 if (image->dynamic) {
6751 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6754 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6755 return NULL; /*FIXME we should probably be raising an exception here*/
6756 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6762 * mono_ldstr_metadata_sig
6763 * @domain: the domain for the string
6764 * @sig: the signature of a metadata string
6765 * @error: set on error
6767 * Returns: a MonoString for a string stored in the metadata. On
6768 * failure returns NULL and sets @error.
6771 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6773 MONO_REQ_GC_UNSAFE_MODE;
6775 mono_error_init (error);
6776 const char *str = sig;
6777 MonoString *o, *interned;
6780 len2 = mono_metadata_decode_blob_size (str, &str);
6783 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6784 return_val_if_nok (error, NULL);
6785 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6788 guint16 *p2 = (guint16*)mono_string_chars (o);
6789 for (i = 0; i < len2; ++i) {
6790 *p2 = GUINT16_FROM_LE (*p2);
6796 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6799 return interned; /* o will get garbage collected */
6801 o = mono_string_get_pinned (o, error);
6804 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6806 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6816 * mono_string_to_utf8:
6817 * @s: a System.String
6819 * Returns the UTF8 representation for @s.
6820 * The resulting buffer needs to be freed with mono_free().
6822 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6825 mono_string_to_utf8 (MonoString *s)
6827 MONO_REQ_GC_UNSAFE_MODE;
6830 char *result = mono_string_to_utf8_checked (s, &error);
6832 if (!is_ok (&error)) {
6833 mono_error_cleanup (&error);
6840 * mono_string_to_utf8_checked:
6841 * @s: a System.String
6842 * @error: a MonoError.
6844 * Converts a MonoString to its UTF8 representation. May fail; check
6845 * @error to determine whether the conversion was successful.
6846 * The resulting buffer should be freed with mono_free().
6849 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6851 MONO_REQ_GC_UNSAFE_MODE;
6855 GError *gerror = NULL;
6857 mono_error_init (error);
6863 return g_strdup ("");
6865 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6867 mono_error_set_argument (error, "string", "%s", gerror->message);
6868 g_error_free (gerror);
6871 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6872 if (s->length > written) {
6873 /* allocate the total length and copy the part of the string that has been converted */
6874 char *as2 = (char *)g_malloc0 (s->length);
6875 memcpy (as2, as, written);
6884 * mono_string_to_utf8_ignore:
6887 * Converts a MonoString to its UTF8 representation. Will ignore
6888 * invalid surrogate pairs.
6889 * The resulting buffer should be freed with mono_free().
6893 mono_string_to_utf8_ignore (MonoString *s)
6895 MONO_REQ_GC_UNSAFE_MODE;
6904 return g_strdup ("");
6906 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6908 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6909 if (s->length > written) {
6910 /* allocate the total length and copy the part of the string that has been converted */
6911 char *as2 = (char *)g_malloc0 (s->length);
6912 memcpy (as2, as, written);
6921 * mono_string_to_utf8_image_ignore:
6922 * @s: a System.String
6924 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6927 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6929 MONO_REQ_GC_UNSAFE_MODE;
6931 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6935 * mono_string_to_utf8_mp_ignore:
6936 * @s: a System.String
6938 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6941 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6943 MONO_REQ_GC_UNSAFE_MODE;
6945 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6950 * mono_string_to_utf16:
6953 * Return an null-terminated array of the utf-16 chars
6954 * contained in @s. The result must be freed with g_free().
6955 * This is a temporary helper until our string implementation
6956 * is reworked to always include the null terminating char.
6959 mono_string_to_utf16 (MonoString *s)
6961 MONO_REQ_GC_UNSAFE_MODE;
6968 as = (char *)g_malloc ((s->length * 2) + 2);
6969 as [(s->length * 2)] = '\0';
6970 as [(s->length * 2) + 1] = '\0';
6973 return (gunichar2 *)(as);
6976 memcpy (as, mono_string_chars(s), s->length * 2);
6977 return (gunichar2 *)(as);
6981 * mono_string_to_utf32:
6984 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6985 * contained in @s. The result must be freed with g_free().
6988 mono_string_to_utf32 (MonoString *s)
6990 MONO_REQ_GC_UNSAFE_MODE;
6992 mono_unichar4 *utf32_output = NULL;
6993 GError *error = NULL;
6994 glong items_written;
6999 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7002 g_error_free (error);
7004 return utf32_output;
7008 * mono_string_from_utf16:
7009 * @data: the UTF16 string (LPWSTR) to convert
7011 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7013 * Returns: a MonoString.
7016 mono_string_from_utf16 (gunichar2 *data)
7019 MonoString *result = mono_string_from_utf16_checked (data, &error);
7020 mono_error_cleanup (&error);
7025 * mono_string_from_utf16_checked:
7026 * @data: the UTF16 string (LPWSTR) to convert
7027 * @error: set on error
7029 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7031 * Returns: a MonoString. On failure sets @error and returns NULL.
7034 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7037 MONO_REQ_GC_UNSAFE_MODE;
7039 mono_error_init (error);
7040 MonoDomain *domain = mono_domain_get ();
7046 while (data [len]) len++;
7048 return mono_string_new_utf16_checked (domain, data, len, error);
7052 * mono_string_from_utf32:
7053 * @data: the UTF32 string (LPWSTR) to convert
7055 * Converts a UTF32 (UCS-4)to a MonoString.
7057 * Returns: a MonoString.
7060 mono_string_from_utf32 (mono_unichar4 *data)
7063 MonoString *result = mono_string_from_utf32_checked (data, &error);
7064 mono_error_cleanup (&error);
7069 * mono_string_from_utf32_checked:
7070 * @data: the UTF32 string (LPWSTR) to convert
7071 * @error: set on error
7073 * Converts a UTF32 (UCS-4)to a MonoString.
7075 * Returns: a MonoString. On failure returns NULL and sets @error.
7078 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7080 MONO_REQ_GC_UNSAFE_MODE;
7082 mono_error_init (error);
7083 MonoString* result = NULL;
7084 mono_unichar2 *utf16_output = NULL;
7085 GError *gerror = NULL;
7086 glong items_written;
7092 while (data [len]) len++;
7094 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7097 g_error_free (gerror);
7099 result = mono_string_from_utf16_checked (utf16_output, error);
7100 g_free (utf16_output);
7105 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7107 MONO_REQ_GC_UNSAFE_MODE;
7114 r = mono_string_to_utf8_ignore (s);
7116 r = mono_string_to_utf8_checked (s, error);
7117 if (!mono_error_ok (error))
7124 len = strlen (r) + 1;
7126 mp_s = (char *)mono_mempool_alloc (mp, len);
7128 mp_s = (char *)mono_image_alloc (image, len);
7130 memcpy (mp_s, r, len);
7138 * mono_string_to_utf8_image:
7139 * @s: a System.String
7141 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7144 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7146 MONO_REQ_GC_UNSAFE_MODE;
7148 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7152 * mono_string_to_utf8_mp:
7153 * @s: a System.String
7155 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7158 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7160 MONO_REQ_GC_UNSAFE_MODE;
7162 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7166 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7169 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7171 eh_callbacks = *cbs;
7174 MonoRuntimeExceptionHandlingCallbacks *
7175 mono_get_eh_callbacks (void)
7177 return &eh_callbacks;
7181 * mono_raise_exception:
7182 * @ex: exception object
7184 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7187 mono_raise_exception (MonoException *ex)
7189 MONO_REQ_GC_UNSAFE_MODE;
7192 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7193 * that will cause gcc to omit the function epilog, causing problems when
7194 * the JIT tries to walk the stack, since the return address on the stack
7195 * will point into the next function in the executable, not this one.
7197 eh_callbacks.mono_raise_exception (ex);
7201 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7203 MONO_REQ_GC_UNSAFE_MODE;
7205 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7209 * mono_wait_handle_new:
7210 * @domain: Domain where the object will be created
7211 * @handle: Handle for the wait handle
7212 * @error: set on error.
7214 * Returns: A new MonoWaitHandle created in the given domain for the
7215 * given handle. On failure returns NULL and sets @rror.
7218 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7220 MONO_REQ_GC_UNSAFE_MODE;
7222 MonoWaitHandle *res;
7223 gpointer params [1];
7224 static MonoMethod *handle_set;
7226 mono_error_init (error);
7227 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7228 return_val_if_nok (error, NULL);
7230 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7232 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7234 params [0] = &handle;
7236 mono_runtime_invoke_checked (handle_set, res, params, error);
7241 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7243 MONO_REQ_GC_UNSAFE_MODE;
7245 static MonoClassField *f_safe_handle = NULL;
7248 if (!f_safe_handle) {
7249 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7250 g_assert (f_safe_handle);
7253 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7259 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7261 MONO_REQ_GC_UNSAFE_MODE;
7263 RuntimeInvokeFunction runtime_invoke;
7265 mono_error_init (error);
7267 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7268 MonoMethod *method = mono_get_context_capture_method ();
7269 MonoMethod *wrapper;
7272 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7273 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7274 return_val_if_nok (error, NULL);
7275 domain->capture_context_method = mono_compile_method_checked (method, error);
7276 return_val_if_nok (error, NULL);
7279 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7281 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7284 * mono_async_result_new:
7285 * @domain:domain where the object will be created.
7286 * @handle: wait handle.
7287 * @state: state to pass to AsyncResult
7288 * @data: C closure data.
7289 * @error: set on error.
7291 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7292 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7293 * On failure returns NULL and sets @error.
7297 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7299 MONO_REQ_GC_UNSAFE_MODE;
7301 mono_error_init (error);
7302 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7303 return_val_if_nok (error, NULL);
7304 MonoObject *context = mono_runtime_capture_context (domain, error);
7305 return_val_if_nok (error, NULL);
7306 /* we must capture the execution context from the original thread */
7308 MONO_OBJECT_SETREF (res, execution_context, context);
7309 /* note: result may be null if the flow is suppressed */
7312 res->data = (void **)data;
7313 MONO_OBJECT_SETREF (res, object_data, object_data);
7314 MONO_OBJECT_SETREF (res, async_state, state);
7315 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7316 return_val_if_nok (error, NULL);
7318 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7320 res->sync_completed = FALSE;
7321 res->completed = FALSE;
7327 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7329 MONO_REQ_GC_UNSAFE_MODE;
7336 g_assert (ares->async_delegate);
7338 ac = (MonoAsyncCall*) ares->object_data;
7340 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7341 if (mono_error_set_pending_exception (&error))
7344 gpointer wait_event = NULL;
7346 ac->msg->exc = NULL;
7347 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7348 if (mono_error_set_pending_exception (&error))
7350 MONO_OBJECT_SETREF (ac, res, res);
7352 mono_monitor_enter ((MonoObject*) ares);
7353 ares->completed = 1;
7355 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7356 mono_monitor_exit ((MonoObject*) ares);
7358 if (wait_event != NULL)
7359 SetEvent (wait_event);
7361 if (ac->cb_method) {
7362 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7363 if (mono_error_set_pending_exception (&error))
7372 mono_message_init (MonoDomain *domain,
7373 MonoMethodMessage *this_obj,
7374 MonoReflectionMethod *method,
7375 MonoArray *out_args,
7378 MONO_REQ_GC_UNSAFE_MODE;
7380 static MonoClass *object_array_klass;
7381 static MonoClass *byte_array_klass;
7382 static MonoClass *string_array_klass;
7383 mono_error_init (error);
7384 MonoMethodSignature *sig = mono_method_signature (method->method);
7391 if (!object_array_klass) {
7394 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7396 byte_array_klass = klass;
7398 klass = mono_array_class_get (mono_defaults.string_class, 1);
7400 string_array_klass = klass;
7402 klass = mono_array_class_get (mono_defaults.object_class, 1);
7405 mono_atomic_store_release (&object_array_klass, klass);
7408 MONO_OBJECT_SETREF (this_obj, method, method);
7410 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, error);
7411 return_val_if_nok (error, FALSE);
7413 MONO_OBJECT_SETREF (this_obj, args, arr);
7415 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, error);
7416 return_val_if_nok (error, FALSE);
7418 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7420 this_obj->async_result = NULL;
7421 this_obj->call_type = CallType_Sync;
7423 names = g_new (char *, sig->param_count);
7424 mono_method_get_param_names (method->method, (const char **) names);
7426 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, error);
7430 MONO_OBJECT_SETREF (this_obj, names, arr);
7432 for (i = 0; i < sig->param_count; i++) {
7433 name = mono_string_new_checked (domain, names [i], error);
7436 mono_array_setref (this_obj->names, i, name);
7440 for (i = 0, j = 0; i < sig->param_count; i++) {
7441 if (sig->params [i]->byref) {
7443 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7444 mono_array_setref (this_obj->args, i, arg);
7448 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7452 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7455 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7464 #ifndef DISABLE_REMOTING
7466 * mono_remoting_invoke:
7467 * @real_proxy: pointer to a RealProxy object
7468 * @msg: The MonoMethodMessage to execute
7469 * @exc: used to store exceptions
7470 * @out_args: used to store output arguments
7472 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7473 * IMessage interface and it is not trivial to extract results from there. So
7474 * we call an helper method PrivateInvoke instead of calling
7475 * RealProxy::Invoke() directly.
7477 * Returns: the result object.
7480 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7482 MONO_REQ_GC_UNSAFE_MODE;
7485 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7490 mono_error_init (error);
7492 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7495 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7497 mono_error_set_not_supported (error, "Linked away.");
7500 real_proxy->vtable->domain->private_invoke_method = im;
7503 pa [0] = real_proxy;
7508 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7509 return_val_if_nok (error, NULL);
7516 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7517 MonoObject **exc, MonoArray **out_args, MonoError *error)
7519 MONO_REQ_GC_UNSAFE_MODE;
7521 static MonoClass *object_array_klass;
7522 mono_error_init (error);
7526 MonoMethodSignature *sig;
7528 int i, j, outarg_count = 0;
7530 #ifndef DISABLE_REMOTING
7531 if (target && mono_object_is_transparent_proxy (target)) {
7532 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7533 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7534 target = tp->rp->unwrapped_server;
7536 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7541 domain = mono_domain_get ();
7542 method = msg->method->method;
7543 sig = mono_method_signature (method);
7545 for (i = 0; i < sig->param_count; i++) {
7546 if (sig->params [i]->byref)
7550 if (!object_array_klass) {
7553 klass = mono_array_class_get (mono_defaults.object_class, 1);
7556 mono_memory_barrier ();
7557 object_array_klass = klass;
7560 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7561 return_val_if_nok (error, NULL);
7563 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7566 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7567 return_val_if_nok (error, NULL);
7569 for (i = 0, j = 0; i < sig->param_count; i++) {
7570 if (sig->params [i]->byref) {
7572 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7573 mono_array_setref (*out_args, j, arg);
7582 * prepare_to_string_method:
7584 * @target: Set to @obj or unboxed value if a valuetype
7586 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7589 prepare_to_string_method (MonoObject *obj, void **target)
7591 MONO_REQ_GC_UNSAFE_MODE;
7593 static MonoMethod *to_string = NULL;
7601 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7603 method = mono_object_get_virtual_method (obj, to_string);
7605 // Unbox value type if needed
7606 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7607 *target = mono_object_unbox (obj);
7613 * mono_object_to_string:
7615 * @exc: Any exception thrown by ToString (). May be NULL.
7617 * Returns: the result of calling ToString () on an object.
7620 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7623 MonoString *s = NULL;
7625 MonoMethod *method = prepare_to_string_method (obj, &target);
7627 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7628 if (*exc == NULL && !mono_error_ok (&error))
7629 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7631 mono_error_cleanup (&error);
7633 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7634 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7641 * mono_object_to_string_checked:
7643 * @error: Set on error.
7645 * Returns: the result of calling ToString () on an object. If the
7646 * method cannot be invoked or if it raises an exception, sets @error
7650 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7652 mono_error_init (error);
7654 MonoMethod *method = prepare_to_string_method (obj, &target);
7655 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7659 * mono_object_try_to_string:
7661 * @exc: Any exception thrown by ToString (). Must not be NULL.
7662 * @error: Set if method cannot be invoked.
7664 * Returns: the result of calling ToString () on an object. If the
7665 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7669 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7672 mono_error_init (error);
7674 MonoMethod *method = prepare_to_string_method (obj, &target);
7675 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7681 * mono_print_unhandled_exception:
7682 * @exc: The exception
7684 * Prints the unhandled exception.
7687 mono_print_unhandled_exception (MonoObject *exc)
7689 MONO_REQ_GC_UNSAFE_MODE;
7692 char *message = (char*)"";
7693 gboolean free_message = FALSE;
7696 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7697 message = g_strdup ("OutOfMemoryException");
7698 free_message = TRUE;
7699 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7700 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7701 free_message = TRUE;
7704 if (((MonoException*)exc)->native_trace_ips) {
7705 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7706 free_message = TRUE;
7708 MonoObject *other_exc = NULL;
7709 str = mono_object_try_to_string (exc, &other_exc, &error);
7710 if (other_exc == NULL && !is_ok (&error))
7711 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7713 mono_error_cleanup (&error);
7715 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7716 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7718 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7719 original_backtrace, nested_backtrace);
7721 g_free (original_backtrace);
7722 g_free (nested_backtrace);
7723 free_message = TRUE;
7725 message = mono_string_to_utf8_checked (str, &error);
7726 if (!mono_error_ok (&error)) {
7727 mono_error_cleanup (&error);
7728 message = (char *) "";
7730 free_message = TRUE;
7737 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7738 * exc->vtable->klass->name, message);
7740 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7747 * mono_delegate_ctor_with_method:
7748 * @this: pointer to an uninitialized delegate object
7749 * @target: target object
7750 * @addr: pointer to native code
7752 * @error: set on error.
7754 * Initialize a delegate and sets a specific method, not the one
7755 * associated with addr. This is useful when sharing generic code.
7756 * In that case addr will most probably not be associated with the
7757 * correct instantiation of the method.
7758 * On failure returns FALSE and sets @error.
7761 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7763 MONO_REQ_GC_UNSAFE_MODE;
7765 mono_error_init (error);
7766 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7768 g_assert (this_obj);
7771 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7774 delegate->method = method;
7776 mono_stats.delegate_creations++;
7778 #ifndef DISABLE_REMOTING
7779 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7781 method = mono_marshal_get_remoting_invoke (method);
7782 delegate->method_ptr = mono_compile_method_checked (method, error);
7783 return_val_if_nok (error, FALSE);
7784 MONO_OBJECT_SETREF (delegate, target, target);
7788 delegate->method_ptr = addr;
7789 MONO_OBJECT_SETREF (delegate, target, target);
7792 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7793 if (callbacks.init_delegate)
7794 callbacks.init_delegate (delegate);
7799 * mono_delegate_ctor:
7800 * @this: pointer to an uninitialized delegate object
7801 * @target: target object
7802 * @addr: pointer to native code
7803 * @error: set on error.
7805 * This is used to initialize a delegate.
7806 * On failure returns FALSE and sets @error.
7809 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7811 MONO_REQ_GC_UNSAFE_MODE;
7813 mono_error_init (error);
7814 MonoDomain *domain = mono_domain_get ();
7816 MonoMethod *method = NULL;
7820 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7822 if (!ji && domain != mono_get_root_domain ())
7823 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7825 method = mono_jit_info_get_method (ji);
7826 g_assert (!method->klass->generic_container);
7829 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7833 * mono_method_call_message_new:
7834 * @method: method to encapsulate
7835 * @params: parameters to the method
7836 * @invoke: optional, delegate invoke.
7837 * @cb: async callback delegate.
7838 * @state: state passed to the async callback.
7839 * @error: set on error.
7841 * Translates arguments pointers into a MonoMethodMessage.
7842 * On failure returns NULL and sets @error.
7845 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7846 MonoDelegate **cb, MonoObject **state, MonoError *error)
7848 MONO_REQ_GC_UNSAFE_MODE;
7850 mono_error_init (error);
7852 MonoDomain *domain = mono_domain_get ();
7853 MonoMethodSignature *sig = mono_method_signature (method);
7854 MonoMethodMessage *msg;
7857 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7858 return_val_if_nok (error, NULL);
7861 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7862 return_val_if_nok (error, NULL);
7863 mono_message_init (domain, msg, rm, NULL, error);
7864 return_val_if_nok (error, NULL);
7865 count = sig->param_count - 2;
7867 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7868 return_val_if_nok (error, NULL);
7869 mono_message_init (domain, msg, rm, NULL, error);
7870 return_val_if_nok (error, NULL);
7871 count = sig->param_count;
7874 for (i = 0; i < count; i++) {
7879 if (sig->params [i]->byref)
7880 vpos = *((gpointer *)params [i]);
7884 klass = mono_class_from_mono_type (sig->params [i]);
7886 if (klass->valuetype) {
7887 arg = mono_value_box_checked (domain, klass, vpos, error);
7888 return_val_if_nok (error, NULL);
7890 arg = *((MonoObject **)vpos);
7892 mono_array_setref (msg->args, i, arg);
7895 if (cb != NULL && state != NULL) {
7896 *cb = *((MonoDelegate **)params [i]);
7898 *state = *((MonoObject **)params [i]);
7905 * mono_method_return_message_restore:
7907 * Restore results from message based processing back to arguments pointers
7910 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7912 MONO_REQ_GC_UNSAFE_MODE;
7914 mono_error_init (error);
7916 MonoMethodSignature *sig = mono_method_signature (method);
7917 int i, j, type, size, out_len;
7919 if (out_args == NULL)
7921 out_len = mono_array_length (out_args);
7925 for (i = 0, j = 0; i < sig->param_count; i++) {
7926 MonoType *pt = sig->params [i];
7931 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7935 arg = (char *)mono_array_get (out_args, gpointer, j);
7938 g_assert (type != MONO_TYPE_VOID);
7940 if (MONO_TYPE_IS_REFERENCE (pt)) {
7941 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7944 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7945 size = mono_class_value_size (klass, NULL);
7946 if (klass->has_references)
7947 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7949 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7951 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7952 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7961 #ifndef DISABLE_REMOTING
7964 * mono_load_remote_field:
7965 * @this: pointer to an object
7966 * @klass: klass of the object containing @field
7967 * @field: the field to load
7968 * @res: a storage to store the result
7970 * This method is called by the runtime on attempts to load fields of
7971 * transparent proxy objects. @this points to such TP, @klass is the class of
7972 * the object containing @field. @res is a storage location which can be
7973 * used to store the result.
7975 * Returns: an address pointing to the value of field.
7978 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7981 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7982 mono_error_cleanup (&error);
7987 * mono_load_remote_field_checked:
7988 * @this: pointer to an object
7989 * @klass: klass of the object containing @field
7990 * @field: the field to load
7991 * @res: a storage to store the result
7992 * @error: set on error
7994 * This method is called by the runtime on attempts to load fields of
7995 * transparent proxy objects. @this points to such TP, @klass is the class of
7996 * the object containing @field. @res is a storage location which can be
7997 * used to store the result.
7999 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8002 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8004 MONO_REQ_GC_UNSAFE_MODE;
8006 static MonoMethod *getter = NULL;
8008 mono_error_init (error);
8010 MonoDomain *domain = mono_domain_get ();
8011 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8012 MonoClass *field_class;
8013 MonoMethodMessage *msg;
8014 MonoArray *out_args;
8018 g_assert (mono_object_is_transparent_proxy (this_obj));
8019 g_assert (res != NULL);
8021 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8022 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8027 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8029 mono_error_set_not_supported (error, "Linked away.");
8034 field_class = mono_class_from_mono_type (field->type);
8036 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8037 return_val_if_nok (error, NULL);
8038 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8039 return_val_if_nok (error, NULL);
8040 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8041 return_val_if_nok (error, NULL);
8042 mono_message_init (domain, msg, rm, out_args, error);
8043 return_val_if_nok (error, NULL);
8045 full_name = mono_type_get_full_name (klass);
8046 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8047 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8050 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8051 return_val_if_nok (error, NULL);
8054 mono_error_set_exception_instance (error, (MonoException *)exc);
8058 if (mono_array_length (out_args) == 0)
8061 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8063 if (field_class->valuetype) {
8064 return ((char *)*res) + sizeof (MonoObject);
8070 * mono_load_remote_field_new:
8075 * Missing documentation.
8078 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8082 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8083 mono_error_cleanup (&error);
8088 * mono_load_remote_field_new_icall:
8089 * @this: pointer to an object
8090 * @klass: klass of the object containing @field
8091 * @field: the field to load
8093 * This method is called by the runtime on attempts to load fields of
8094 * transparent proxy objects. @this points to such TP, @klass is the class of
8095 * the object containing @field.
8097 * Returns: a freshly allocated object containing the value of the
8098 * field. On failure returns NULL and throws an exception.
8101 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8104 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8105 mono_error_set_pending_exception (&error);
8110 * mono_load_remote_field_new_checked:
8111 * @this: pointer to an object
8112 * @klass: klass of the object containing @field
8113 * @field: the field to load
8114 * @error: set on error.
8116 * This method is called by the runtime on attempts to load fields of
8117 * transparent proxy objects. @this points to such TP, @klass is the class of
8118 * the object containing @field.
8120 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8123 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8125 MONO_REQ_GC_UNSAFE_MODE;
8127 mono_error_init (error);
8129 static MonoMethod *getter = NULL;
8130 MonoDomain *domain = mono_domain_get ();
8131 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8132 MonoClass *field_class;
8133 MonoMethodMessage *msg;
8134 MonoArray *out_args;
8135 MonoObject *exc, *res;
8138 g_assert (mono_object_is_transparent_proxy (this_obj));
8140 field_class = mono_class_from_mono_type (field->type);
8142 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8144 if (field_class->valuetype) {
8145 res = mono_object_new_checked (domain, field_class, error);
8146 return_val_if_nok (error, NULL);
8147 val = ((gchar *) res) + sizeof (MonoObject);
8151 mono_field_get_value (tp->rp->unwrapped_server, field, val);
8156 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8158 mono_error_set_not_supported (error, "Linked away.");
8163 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8164 return_val_if_nok (error, NULL);
8165 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8166 return_val_if_nok (error, NULL);
8168 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8169 return_val_if_nok (error, NULL);
8170 mono_message_init (domain, msg, rm, out_args, error);
8171 return_val_if_nok (error, NULL);
8173 full_name = mono_type_get_full_name (klass);
8174 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8175 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8178 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8179 return_val_if_nok (error, NULL);
8182 mono_error_set_exception_instance (error, (MonoException *)exc);
8186 if (mono_array_length (out_args) == 0)
8189 res = mono_array_get (out_args, MonoObject *, 0);
8195 * mono_store_remote_field:
8196 * @this_obj: pointer to an object
8197 * @klass: klass of the object containing @field
8198 * @field: the field to load
8199 * @val: the value/object to store
8201 * This method is called by the runtime on attempts to store fields of
8202 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8203 * the object containing @field. @val is the new value to store in @field.
8206 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8209 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8210 mono_error_cleanup (&error);
8214 * mono_store_remote_field_checked:
8215 * @this_obj: pointer to an object
8216 * @klass: klass of the object containing @field
8217 * @field: the field to load
8218 * @val: the value/object to store
8219 * @error: set on error
8221 * This method is called by the runtime on attempts to store fields of
8222 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8223 * the object containing @field. @val is the new value to store in @field.
8225 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8228 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8231 MONO_REQ_GC_UNSAFE_MODE;
8233 static MonoMethod *setter = NULL;
8235 MonoDomain *domain = mono_domain_get ();
8236 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8237 MonoClass *field_class;
8238 MonoMethodMessage *msg;
8239 MonoArray *out_args;
8244 mono_error_init (error);
8246 g_assert (mono_object_is_transparent_proxy (this_obj));
8248 field_class = mono_class_from_mono_type (field->type);
8250 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8251 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
8252 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
8257 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8259 mono_error_set_not_supported (error, "Linked away.");
8264 if (field_class->valuetype) {
8265 arg = mono_value_box_checked (domain, field_class, val, error);
8266 return_val_if_nok (error, FALSE);
8268 arg = *((MonoObject **)val);
8271 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8272 return_val_if_nok (error, FALSE);
8273 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8274 return_val_if_nok (error, FALSE);
8275 mono_message_init (domain, msg, rm, NULL, error);
8276 return_val_if_nok (error, FALSE);
8278 full_name = mono_type_get_full_name (klass);
8279 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8280 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8281 mono_array_setref (msg->args, 2, arg);
8284 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8285 return_val_if_nok (error, FALSE);
8288 mono_error_set_exception_instance (error, (MonoException *)exc);
8295 * mono_store_remote_field_new:
8301 * Missing documentation
8304 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8307 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8308 mono_error_cleanup (&error);
8312 * mono_store_remote_field_new_icall:
8318 * Missing documentation
8321 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8324 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8325 mono_error_set_pending_exception (&error);
8329 * mono_store_remote_field_new_checked:
8336 * Missing documentation
8339 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8341 MONO_REQ_GC_UNSAFE_MODE;
8343 static MonoMethod *setter = NULL;
8344 MonoDomain *domain = mono_domain_get ();
8345 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8346 MonoClass *field_class;
8347 MonoMethodMessage *msg;
8348 MonoArray *out_args;
8352 mono_error_init (error);
8354 g_assert (mono_object_is_transparent_proxy (this_obj));
8356 field_class = mono_class_from_mono_type (field->type);
8358 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8359 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8360 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8365 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8367 mono_error_set_not_supported (error, "Linked away.");
8372 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8373 return_val_if_nok (error, FALSE);
8374 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8375 return_val_if_nok (error, FALSE);
8376 mono_message_init (domain, msg, rm, NULL, error);
8377 return_val_if_nok (error, FALSE);
8379 full_name = mono_type_get_full_name (klass);
8380 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8381 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8382 mono_array_setref (msg->args, 2, arg);
8385 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8386 return_val_if_nok (error, FALSE);
8389 mono_error_set_exception_instance (error, (MonoException *)exc);
8397 * mono_create_ftnptr:
8399 * Given a function address, create a function descriptor for it.
8400 * This is only needed on some platforms.
8403 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8405 return callbacks.create_ftnptr (domain, addr);
8409 * mono_get_addr_from_ftnptr:
8411 * Given a pointer to a function descriptor, return the function address.
8412 * This is only needed on some platforms.
8415 mono_get_addr_from_ftnptr (gpointer descr)
8417 return callbacks.get_addr_from_ftnptr (descr);
8421 * mono_string_chars:
8424 * Returns a pointer to the UCS16 characters stored in the MonoString
8427 mono_string_chars (MonoString *s)
8429 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8435 * mono_string_length:
8438 * Returns the lenght in characters of the string
8441 mono_string_length (MonoString *s)
8443 MONO_REQ_GC_UNSAFE_MODE;
8449 * mono_array_length:
8450 * @array: a MonoArray*
8452 * Returns the total number of elements in the array. This works for
8453 * both vectors and multidimensional arrays.
8456 mono_array_length (MonoArray *array)
8458 MONO_REQ_GC_UNSAFE_MODE;
8460 return array->max_length;
8464 * mono_array_addr_with_size:
8465 * @array: a MonoArray*
8466 * @size: size of the array elements
8467 * @idx: index into the array
8469 * Use this function to obtain the address for the @idx item on the
8470 * @array containing elements of size @size.
8472 * This method performs no bounds checking or type checking.
8474 * Returns the address of the @idx element in the array.
8477 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8479 MONO_REQ_GC_UNSAFE_MODE;
8481 return ((char*)(array)->vector) + size * idx;
8486 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8488 MonoDomain *domain = mono_domain_get ();
8492 mono_error_init (error);
8496 len = g_list_length (list);
8497 res = mono_array_new_checked (domain, eclass, len, error);
8498 return_val_if_nok (error, NULL);
8500 for (i = 0; list; list = list->next, i++)
8501 mono_array_set (res, gpointer, i, list->data);
8508 * The following section is purely to declare prototypes and
8509 * document the API, as these C files are processed by our
8515 * @array: array to alter
8516 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8517 * @index: index into the array
8518 * @value: value to set
8520 * Value Type version: This sets the @index's element of the @array
8521 * with elements of size sizeof(type) to the provided @value.
8523 * This macro does not attempt to perform type checking or bounds checking.
8525 * Use this to set value types in a `MonoArray`.
8527 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8532 * mono_array_setref:
8533 * @array: array to alter
8534 * @index: index into the array
8535 * @value: value to set
8537 * Reference Type version: This sets the @index's element of the
8538 * @array with elements of size sizeof(type) to the provided @value.
8540 * This macro does not attempt to perform type checking or bounds checking.
8542 * Use this to reference types in a `MonoArray`.
8544 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8550 * @array: array on which to operate on
8551 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8552 * @index: index into the array
8554 * Use this macro to retrieve the @index element of an @array and
8555 * extract the value assuming that the elements of the array match
8556 * the provided type value.
8558 * This method can be used with both arrays holding value types and
8559 * reference types. For reference types, the @type parameter should
8560 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8562 * This macro does not attempt to perform type checking or bounds checking.
8564 * Returns: The element at the @index position in the @array.
8566 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)