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 MONO_ENTER_GC_UNSAFE;
2950 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2952 MONO_EXIT_GC_UNSAFE;
2954 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2955 mono_profiler_method_end_invoke (method);
2957 if (!mono_error_ok (error))
2964 * mono_runtime_invoke:
2965 * @method: method to invoke
2966 * @obJ: object instance
2967 * @params: arguments to the method
2968 * @exc: exception information.
2970 * Invokes the method represented by @method on the object @obj.
2972 * obj is the 'this' pointer, it should be NULL for static
2973 * methods, a MonoObject* for object instances and a pointer to
2974 * the value type for value types.
2976 * The params array contains the arguments to the method with the
2977 * same convention: MonoObject* pointers for object instances and
2978 * pointers to the value type otherwise.
2980 * From unmanaged code you'll usually use the
2981 * mono_runtime_invoke() variant.
2983 * Note that this function doesn't handle virtual methods for
2984 * you, it will exec the exact method you pass: we still need to
2985 * expose a function to lookup the derived class implementation
2986 * of a virtual method (there are examples of this in the code,
2989 * You can pass NULL as the exc argument if you don't want to
2990 * catch exceptions, otherwise, *exc will be set to the exception
2991 * thrown, if any. if an exception is thrown, you can't use the
2992 * MonoObject* result from the function.
2994 * If the method returns a value type, it is boxed in an object
2998 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
3003 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
3004 if (*exc == NULL && !mono_error_ok(&error)) {
3005 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3007 mono_error_cleanup (&error);
3009 res = mono_runtime_invoke_checked (method, obj, params, &error);
3010 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3016 * mono_runtime_try_invoke:
3017 * @method: method to invoke
3018 * @obJ: object instance
3019 * @params: arguments to the method
3020 * @exc: exception information.
3021 * @error: set on error
3023 * Invokes the method represented by @method on the object @obj.
3025 * obj is the 'this' pointer, it should be NULL for static
3026 * methods, a MonoObject* for object instances and a pointer to
3027 * the value type for value types.
3029 * The params array contains the arguments to the method with the
3030 * same convention: MonoObject* pointers for object instances and
3031 * pointers to the value type otherwise.
3033 * From unmanaged code you'll usually use the
3034 * mono_runtime_invoke() variant.
3036 * Note that this function doesn't handle virtual methods for
3037 * you, it will exec the exact method you pass: we still need to
3038 * expose a function to lookup the derived class implementation
3039 * of a virtual method (there are examples of this in the code,
3042 * For this function, you must not pass NULL as the exc argument if
3043 * you don't want to catch exceptions, use
3044 * mono_runtime_invoke_checked(). If an exception is thrown, you
3045 * can't use the MonoObject* result from the function.
3047 * If this method cannot be invoked, @error will be set and @exc and
3048 * the return value must not be used.
3050 * If the method returns a value type, it is boxed in an object
3054 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3056 MONO_REQ_GC_UNSAFE_MODE;
3058 g_assert (exc != NULL);
3060 if (mono_runtime_get_no_exec ())
3061 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3063 return do_runtime_invoke (method, obj, params, exc, error);
3067 * mono_runtime_invoke_checked:
3068 * @method: method to invoke
3069 * @obJ: object instance
3070 * @params: arguments to the method
3071 * @error: set on error
3073 * Invokes the method represented by @method on the object @obj.
3075 * obj is the 'this' pointer, it should be NULL for static
3076 * methods, a MonoObject* for object instances and a pointer to
3077 * the value type for value types.
3079 * The params array contains the arguments to the method with the
3080 * same convention: MonoObject* pointers for object instances and
3081 * pointers to the value type otherwise.
3083 * From unmanaged code you'll usually use the
3084 * mono_runtime_invoke() variant.
3086 * Note that this function doesn't handle virtual methods for
3087 * you, it will exec the exact method you pass: we still need to
3088 * expose a function to lookup the derived class implementation
3089 * of a virtual method (there are examples of this in the code,
3092 * If an exception is thrown, you can't use the MonoObject* result
3093 * from the function.
3095 * If this method cannot be invoked, @error will be set. If the
3096 * method throws an exception (and we're in coop mode) the exception
3097 * will be set in @error.
3099 * If the method returns a value type, it is boxed in an object
3103 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3105 MONO_REQ_GC_UNSAFE_MODE;
3107 if (mono_runtime_get_no_exec ())
3108 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3110 return do_runtime_invoke (method, obj, params, NULL, error);
3114 * mono_method_get_unmanaged_thunk:
3115 * @method: method to generate a thunk for.
3117 * Returns an unmanaged->managed thunk that can be used to call
3118 * a managed method directly from C.
3120 * The thunk's C signature closely matches the managed signature:
3122 * C#: public bool Equals (object obj);
3123 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3124 * MonoObject*, MonoException**);
3126 * The 1st ("this") parameter must not be used with static methods:
3128 * C#: public static bool ReferenceEquals (object a, object b);
3129 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3132 * The last argument must be a non-null pointer of a MonoException* pointer.
3133 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3134 * exception has been thrown in managed code. Otherwise it will point
3135 * to the MonoException* caught by the thunk. In this case, the result of
3136 * the thunk is undefined:
3138 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3139 * MonoException *ex = NULL;
3140 * Equals func = mono_method_get_unmanaged_thunk (method);
3141 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3143 * // handle exception
3146 * The calling convention of the thunk matches the platform's default
3147 * convention. This means that under Windows, C declarations must
3148 * contain the __stdcall attribute:
3150 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3151 * MonoObject*, MonoException**);
3155 * Value type arguments and return values are treated as they were objects:
3157 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3158 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3160 * Arguments must be properly boxed upon trunk's invocation, while return
3161 * values must be unboxed.
3164 mono_method_get_unmanaged_thunk (MonoMethod *method)
3166 MONO_REQ_GC_NEUTRAL_MODE;
3167 MONO_REQ_API_ENTRYPOINT;
3172 g_assert (!mono_threads_is_coop_enabled ());
3174 MONO_ENTER_GC_UNSAFE;
3175 method = mono_marshal_get_thunk_invoke_wrapper (method);
3176 res = mono_compile_method_checked (method, &error);
3177 mono_error_cleanup (&error);
3178 MONO_EXIT_GC_UNSAFE;
3184 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3186 MONO_REQ_GC_UNSAFE_MODE;
3190 /* object fields cannot be byref, so we don't need a
3192 gpointer *p = (gpointer*)dest;
3199 case MONO_TYPE_BOOLEAN:
3201 case MONO_TYPE_U1: {
3202 guint8 *p = (guint8*)dest;
3203 *p = value ? *(guint8*)value : 0;
3208 case MONO_TYPE_CHAR: {
3209 guint16 *p = (guint16*)dest;
3210 *p = value ? *(guint16*)value : 0;
3213 #if SIZEOF_VOID_P == 4
3218 case MONO_TYPE_U4: {
3219 gint32 *p = (gint32*)dest;
3220 *p = value ? *(gint32*)value : 0;
3223 #if SIZEOF_VOID_P == 8
3228 case MONO_TYPE_U8: {
3229 gint64 *p = (gint64*)dest;
3230 *p = value ? *(gint64*)value : 0;
3233 case MONO_TYPE_R4: {
3234 float *p = (float*)dest;
3235 *p = value ? *(float*)value : 0;
3238 case MONO_TYPE_R8: {
3239 double *p = (double*)dest;
3240 *p = value ? *(double*)value : 0;
3243 case MONO_TYPE_STRING:
3244 case MONO_TYPE_SZARRAY:
3245 case MONO_TYPE_CLASS:
3246 case MONO_TYPE_OBJECT:
3247 case MONO_TYPE_ARRAY:
3248 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3250 case MONO_TYPE_FNPTR:
3251 case MONO_TYPE_PTR: {
3252 gpointer *p = (gpointer*)dest;
3253 *p = deref_pointer? *(gpointer*)value: value;
3256 case MONO_TYPE_VALUETYPE:
3257 /* note that 't' and 'type->type' can be different */
3258 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3259 t = mono_class_enum_basetype (type->data.klass)->type;
3262 MonoClass *klass = mono_class_from_mono_type (type);
3263 int size = mono_class_value_size (klass, NULL);
3265 mono_gc_bzero_atomic (dest, size);
3267 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3270 case MONO_TYPE_GENERICINST:
3271 t = type->data.generic_class->container_class->byval_arg.type;
3274 g_error ("got type %x", type->type);
3279 * mono_field_set_value:
3280 * @obj: Instance object
3281 * @field: MonoClassField describing the field to set
3282 * @value: The value to be set
3284 * Sets the value of the field described by @field in the object instance @obj
3285 * to the value passed in @value. This method should only be used for instance
3286 * fields. For static fields, use mono_field_static_set_value.
3288 * The value must be on the native format of the field type.
3291 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3293 MONO_REQ_GC_UNSAFE_MODE;
3297 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3299 dest = (char*)obj + field->offset;
3300 mono_copy_value (field->type, dest, value, FALSE);
3304 * mono_field_static_set_value:
3305 * @field: MonoClassField describing the field to set
3306 * @value: The value to be set
3308 * Sets the value of the static field described by @field
3309 * to the value passed in @value.
3311 * The value must be on the native format of the field type.
3314 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3316 MONO_REQ_GC_UNSAFE_MODE;
3320 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3321 /* you cant set a constant! */
3322 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3324 if (field->offset == -1) {
3325 /* Special static */
3328 mono_domain_lock (vt->domain);
3329 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3330 mono_domain_unlock (vt->domain);
3331 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3333 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3335 mono_copy_value (field->type, dest, value, FALSE);
3339 * mono_vtable_get_static_field_data:
3341 * Internal use function: return a pointer to the memory holding the static fields
3342 * for a class or NULL if there are no static fields.
3343 * This is exported only for use by the debugger.
3346 mono_vtable_get_static_field_data (MonoVTable *vt)
3348 MONO_REQ_GC_NEUTRAL_MODE
3350 if (!vt->has_static_fields)
3352 return vt->vtable [vt->klass->vtable_size];
3356 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3358 MONO_REQ_GC_UNSAFE_MODE;
3362 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3363 if (field->offset == -1) {
3364 /* Special static */
3367 mono_domain_lock (vt->domain);
3368 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3369 mono_domain_unlock (vt->domain);
3370 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3372 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3375 src = (guint8*)obj + field->offset;
3382 * mono_field_get_value:
3383 * @obj: Object instance
3384 * @field: MonoClassField describing the field to fetch information from
3385 * @value: pointer to the location where the value will be stored
3387 * Use this routine to get the value of the field @field in the object
3390 * The pointer provided by value must be of the field type, for reference
3391 * types this is a MonoObject*, for value types its the actual pointer to
3396 * mono_field_get_value (obj, int_field, &i);
3399 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3401 MONO_REQ_GC_UNSAFE_MODE;
3407 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3409 src = (char*)obj + field->offset;
3410 mono_copy_value (field->type, value, src, TRUE);
3414 * mono_field_get_value_object:
3415 * @domain: domain where the object will be created (if boxing)
3416 * @field: MonoClassField describing the field to fetch information from
3417 * @obj: The object instance for the field.
3419 * Returns: a new MonoObject with the value from the given field. If the
3420 * field represents a value type, the value is boxed.
3424 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3427 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3428 mono_error_assert_ok (&error);
3433 * mono_field_get_value_object_checked:
3434 * @domain: domain where the object will be created (if boxing)
3435 * @field: MonoClassField describing the field to fetch information from
3436 * @obj: The object instance for the field.
3437 * @error: Set on error.
3439 * Returns: a new MonoObject with the value from the given field. If the
3440 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3444 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3446 MONO_REQ_GC_UNSAFE_MODE;
3448 mono_error_init (error);
3452 MonoVTable *vtable = NULL;
3454 gboolean is_static = FALSE;
3455 gboolean is_ref = FALSE;
3456 gboolean is_literal = FALSE;
3457 gboolean is_ptr = FALSE;
3458 MonoType *type = mono_field_get_type_checked (field, error);
3460 return_val_if_nok (error, NULL);
3462 switch (type->type) {
3463 case MONO_TYPE_STRING:
3464 case MONO_TYPE_OBJECT:
3465 case MONO_TYPE_CLASS:
3466 case MONO_TYPE_ARRAY:
3467 case MONO_TYPE_SZARRAY:
3472 case MONO_TYPE_BOOLEAN:
3475 case MONO_TYPE_CHAR:
3484 case MONO_TYPE_VALUETYPE:
3485 is_ref = type->byref;
3487 case MONO_TYPE_GENERICINST:
3488 is_ref = !mono_type_generic_inst_is_valuetype (type);
3494 g_error ("type 0x%x not handled in "
3495 "mono_field_get_value_object", type->type);
3499 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3502 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3506 vtable = mono_class_vtable_full (domain, field->parent, error);
3507 return_val_if_nok (error, NULL);
3509 if (!vtable->initialized) {
3510 mono_runtime_class_init_full (vtable, error);
3511 return_val_if_nok (error, NULL);
3520 get_default_field_value (domain, field, &o, error);
3521 return_val_if_nok (error, NULL);
3522 } else if (is_static) {
3523 mono_field_static_get_value_checked (vtable, field, &o, error);
3524 return_val_if_nok (error, NULL);
3526 mono_field_get_value (obj, field, &o);
3532 static MonoMethod *m;
3538 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3539 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3545 get_default_field_value (domain, field, v, error);
3546 return_val_if_nok (error, NULL);
3547 } else if (is_static) {
3548 mono_field_static_get_value_checked (vtable, field, v, error);
3549 return_val_if_nok (error, NULL);
3551 mono_field_get_value (obj, field, v);
3554 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3555 args [0] = ptr ? *ptr : NULL;
3556 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3557 return_val_if_nok (error, NULL);
3559 o = mono_runtime_invoke_checked (m, NULL, args, error);
3560 return_val_if_nok (error, NULL);
3565 /* boxed value type */
3566 klass = mono_class_from_mono_type (type);
3568 if (mono_class_is_nullable (klass))
3569 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3571 o = mono_object_new_checked (domain, klass, error);
3572 return_val_if_nok (error, NULL);
3573 v = ((gchar *) o) + sizeof (MonoObject);
3576 get_default_field_value (domain, field, v, error);
3577 return_val_if_nok (error, NULL);
3578 } else if (is_static) {
3579 mono_field_static_get_value_checked (vtable, field, v, error);
3580 return_val_if_nok (error, NULL);
3582 mono_field_get_value (obj, field, v);
3589 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3591 MONO_REQ_GC_UNSAFE_MODE;
3593 mono_error_init (error);
3595 const char *p = blob;
3596 mono_metadata_decode_blob_size (p, &p);
3599 case MONO_TYPE_BOOLEAN:
3602 *(guint8 *) value = *p;
3604 case MONO_TYPE_CHAR:
3607 *(guint16*) value = read16 (p);
3611 *(guint32*) value = read32 (p);
3615 *(guint64*) value = read64 (p);
3618 readr4 (p, (float*) value);
3621 readr8 (p, (double*) value);
3623 case MONO_TYPE_STRING:
3624 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3626 case MONO_TYPE_CLASS:
3627 *(gpointer*) value = NULL;
3631 g_warning ("type 0x%02x should not be in constant table", type);
3637 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3639 MONO_REQ_GC_NEUTRAL_MODE;
3641 MonoTypeEnum def_type;
3644 mono_error_init (error);
3646 data = mono_class_get_field_default_value (field, &def_type);
3647 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3651 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3653 MONO_REQ_GC_UNSAFE_MODE;
3657 mono_error_init (error);
3659 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3661 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3662 get_default_field_value (vt->domain, field, value, error);
3666 if (field->offset == -1) {
3667 /* Special static */
3668 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3669 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3671 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3673 mono_copy_value (field->type, value, src, TRUE);
3677 * mono_field_static_get_value:
3678 * @vt: vtable to the object
3679 * @field: MonoClassField describing the field to fetch information from
3680 * @value: where the value is returned
3682 * Use this routine to get the value of the static field @field value.
3684 * The pointer provided by value must be of the field type, for reference
3685 * types this is a MonoObject*, for value types its the actual pointer to
3690 * mono_field_static_get_value (vt, int_field, &i);
3693 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3695 MONO_REQ_GC_NEUTRAL_MODE;
3698 mono_field_static_get_value_checked (vt, field, value, &error);
3699 mono_error_cleanup (&error);
3703 * mono_field_static_get_value_checked:
3704 * @vt: vtable to the object
3705 * @field: MonoClassField describing the field to fetch information from
3706 * @value: where the value is returned
3707 * @error: set on error
3709 * Use this routine to get the value of the static field @field value.
3711 * The pointer provided by value must be of the field type, for reference
3712 * types this is a MonoObject*, for value types its the actual pointer to
3717 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3718 * if (!is_ok (error)) { ... }
3720 * On failure sets @error.
3723 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3725 MONO_REQ_GC_NEUTRAL_MODE;
3727 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3731 * mono_property_set_value:
3732 * @prop: MonoProperty to set
3733 * @obj: instance object on which to act
3734 * @params: parameters to pass to the propery
3735 * @exc: optional exception
3737 * Invokes the property's set method with the given arguments on the
3738 * object instance obj (or NULL for static properties).
3740 * You can pass NULL as the exc argument if you don't want to
3741 * catch exceptions, otherwise, *exc will be set to the exception
3742 * thrown, if any. if an exception is thrown, you can't use the
3743 * MonoObject* result from the function.
3746 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3748 MONO_REQ_GC_UNSAFE_MODE;
3751 do_runtime_invoke (prop->set, obj, params, exc, &error);
3752 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3753 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3755 mono_error_cleanup (&error);
3760 * mono_property_set_value_checked:
3761 * @prop: MonoProperty to set
3762 * @obj: instance object on which to act
3763 * @params: parameters to pass to the propery
3764 * @error: set on error
3766 * Invokes the property's set method with the given arguments on the
3767 * object instance obj (or NULL for static properties).
3769 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3770 * If an exception is thrown, it will be caught and returned via @error.
3773 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3775 MONO_REQ_GC_UNSAFE_MODE;
3779 mono_error_init (error);
3780 do_runtime_invoke (prop->set, obj, params, &exc, error);
3781 if (exc != NULL && is_ok (error))
3782 mono_error_set_exception_instance (error, (MonoException*)exc);
3783 return is_ok (error);
3787 * mono_property_get_value:
3788 * @prop: MonoProperty to fetch
3789 * @obj: instance object on which to act
3790 * @params: parameters to pass to the propery
3791 * @exc: optional exception
3793 * Invokes the property's get method with the given arguments on the
3794 * object instance obj (or NULL for static properties).
3796 * You can pass NULL as the exc argument if you don't want to
3797 * catch exceptions, otherwise, *exc will be set to the exception
3798 * thrown, if any. if an exception is thrown, you can't use the
3799 * MonoObject* result from the function.
3801 * Returns: the value from invoking the get method on the property.
3804 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3806 MONO_REQ_GC_UNSAFE_MODE;
3809 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3810 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3811 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3813 mono_error_cleanup (&error); /* FIXME don't raise here */
3820 * mono_property_get_value_checked:
3821 * @prop: MonoProperty to fetch
3822 * @obj: instance object on which to act
3823 * @params: parameters to pass to the propery
3824 * @error: set on error
3826 * Invokes the property's get method with the given arguments on the
3827 * object instance obj (or NULL for static properties).
3829 * If an exception is thrown, you can't use the
3830 * MonoObject* result from the function. The exception will be propagated via @error.
3832 * Returns: the value from invoking the get method on the property. On
3833 * failure returns NULL and sets @error.
3836 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3838 MONO_REQ_GC_UNSAFE_MODE;
3841 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3842 if (exc != NULL && !is_ok (error))
3843 mono_error_set_exception_instance (error, (MonoException*) exc);
3851 * mono_nullable_init:
3852 * @buf: The nullable structure to initialize.
3853 * @value: the value to initialize from
3854 * @klass: the type for the object
3856 * Initialize the nullable structure pointed to by @buf from @value which
3857 * should be a boxed value type. The size of @buf should be able to hold
3858 * as much data as the @klass->instance_size (which is the number of bytes
3859 * that will be copies).
3861 * Since Nullables have variable structure, we can not define a C
3862 * structure for them.
3865 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3867 MONO_REQ_GC_UNSAFE_MODE;
3869 MonoClass *param_class = klass->cast_class;
3871 mono_class_setup_fields_locking (klass);
3872 g_assert (klass->fields_inited);
3874 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3875 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3877 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3879 if (param_class->has_references)
3880 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3882 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3884 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3889 * mono_nullable_box:
3890 * @buf: The buffer representing the data to be boxed
3891 * @klass: the type to box it as.
3892 * @error: set on oerr
3894 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3895 * @buf. On failure returns NULL and sets @error
3898 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3900 MONO_REQ_GC_UNSAFE_MODE;
3902 mono_error_init (error);
3903 MonoClass *param_class = klass->cast_class;
3905 mono_class_setup_fields_locking (klass);
3906 g_assert (klass->fields_inited);
3908 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3909 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3911 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3912 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3913 return_val_if_nok (error, NULL);
3914 if (param_class->has_references)
3915 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3917 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3925 * mono_get_delegate_invoke:
3926 * @klass: The delegate class
3928 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3931 mono_get_delegate_invoke (MonoClass *klass)
3933 MONO_REQ_GC_NEUTRAL_MODE;
3937 /* This is called at runtime, so avoid the slower search in metadata */
3938 mono_class_setup_methods (klass);
3939 if (mono_class_has_failure (klass))
3941 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3946 * mono_get_delegate_begin_invoke:
3947 * @klass: The delegate class
3949 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3952 mono_get_delegate_begin_invoke (MonoClass *klass)
3954 MONO_REQ_GC_NEUTRAL_MODE;
3958 /* This is called at runtime, so avoid the slower search in metadata */
3959 mono_class_setup_methods (klass);
3960 if (mono_class_has_failure (klass))
3962 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3967 * mono_get_delegate_end_invoke:
3968 * @klass: The delegate class
3970 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3973 mono_get_delegate_end_invoke (MonoClass *klass)
3975 MONO_REQ_GC_NEUTRAL_MODE;
3979 /* This is called at runtime, so avoid the slower search in metadata */
3980 mono_class_setup_methods (klass);
3981 if (mono_class_has_failure (klass))
3983 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3988 * mono_runtime_delegate_invoke:
3989 * @delegate: pointer to a delegate object.
3990 * @params: parameters for the delegate.
3991 * @exc: Pointer to the exception result.
3993 * Invokes the delegate method @delegate with the parameters provided.
3995 * You can pass NULL as the exc argument if you don't want to
3996 * catch exceptions, otherwise, *exc will be set to the exception
3997 * thrown, if any. if an exception is thrown, you can't use the
3998 * MonoObject* result from the function.
4001 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4003 MONO_REQ_GC_UNSAFE_MODE;
4007 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
4009 mono_error_cleanup (&error);
4012 if (!is_ok (&error))
4013 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4017 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
4018 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4024 * mono_runtime_delegate_try_invoke:
4025 * @delegate: pointer to a delegate object.
4026 * @params: parameters for the delegate.
4027 * @exc: Pointer to the exception result.
4028 * @error: set on error
4030 * Invokes the delegate method @delegate with the parameters provided.
4032 * You can pass NULL as the exc argument if you don't want to
4033 * catch exceptions, otherwise, *exc will be set to the exception
4034 * thrown, if any. On failure to execute, @error will be set.
4035 * if an exception is thrown, you can't use the
4036 * MonoObject* result from the function.
4039 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4041 MONO_REQ_GC_UNSAFE_MODE;
4043 mono_error_init (error);
4045 MonoClass *klass = delegate->vtable->klass;
4048 im = mono_get_delegate_invoke (klass);
4050 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4053 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4055 o = mono_runtime_invoke_checked (im, delegate, params, error);
4062 * mono_runtime_delegate_invoke_checked:
4063 * @delegate: pointer to a delegate object.
4064 * @params: parameters for the delegate.
4065 * @error: set on error
4067 * Invokes the delegate method @delegate with the parameters provided.
4069 * On failure @error will be set and you can't use the MonoObject*
4070 * result from the function.
4073 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4075 mono_error_init (error);
4076 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4079 static char **main_args = NULL;
4080 static int num_main_args = 0;
4083 * mono_runtime_get_main_args:
4085 * Returns: a MonoArray with the arguments passed to the main program
4088 mono_runtime_get_main_args (void)
4090 MONO_REQ_GC_UNSAFE_MODE;
4092 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4093 mono_error_assert_ok (&error);
4098 * mono_runtime_get_main_args:
4099 * @error: set on error
4101 * Returns: a MonoArray with the arguments passed to the main
4102 * program. On failure returns NULL and sets @error.
4105 mono_runtime_get_main_args_checked (MonoError *error)
4109 MonoDomain *domain = mono_domain_get ();
4111 mono_error_init (error);
4113 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4114 return_val_if_nok (error, NULL);
4116 for (i = 0; i < num_main_args; ++i)
4117 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4123 free_main_args (void)
4125 MONO_REQ_GC_NEUTRAL_MODE;
4129 for (i = 0; i < num_main_args; ++i)
4130 g_free (main_args [i]);
4137 * mono_runtime_set_main_args:
4138 * @argc: number of arguments from the command line
4139 * @argv: array of strings from the command line
4141 * Set the command line arguments from an embedding application that doesn't otherwise call
4142 * mono_runtime_run_main ().
4145 mono_runtime_set_main_args (int argc, char* argv[])
4147 MONO_REQ_GC_NEUTRAL_MODE;
4152 main_args = g_new0 (char*, argc);
4153 num_main_args = argc;
4155 for (i = 0; i < argc; ++i) {
4158 utf8_arg = mono_utf8_from_external (argv[i]);
4159 if (utf8_arg == NULL) {
4160 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4161 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4165 main_args [i] = utf8_arg;
4172 * mono_runtime_run_main:
4173 * @method: the method to start the application with (usually Main)
4174 * @argc: number of arguments from the command line
4175 * @argv: array of strings from the command line
4176 * @exc: excetption results
4178 * Execute a standard Main() method (argc/argv contains the
4179 * executable name). This method also sets the command line argument value
4180 * needed by System.Environment.
4185 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4188 MONO_REQ_GC_UNSAFE_MODE;
4192 MonoArray *args = NULL;
4193 MonoDomain *domain = mono_domain_get ();
4194 gchar *utf8_fullpath;
4195 MonoMethodSignature *sig;
4197 g_assert (method != NULL);
4199 mono_thread_set_main (mono_thread_current ());
4201 main_args = g_new0 (char*, argc);
4202 num_main_args = argc;
4204 if (!g_path_is_absolute (argv [0])) {
4205 gchar *basename = g_path_get_basename (argv [0]);
4206 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4210 utf8_fullpath = mono_utf8_from_external (fullpath);
4211 if(utf8_fullpath == NULL) {
4212 /* Printing the arg text will cause glib to
4213 * whinge about "Invalid UTF-8", but at least
4214 * its relevant, and shows the problem text
4217 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4218 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4225 utf8_fullpath = mono_utf8_from_external (argv[0]);
4226 if(utf8_fullpath == NULL) {
4227 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4228 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4233 main_args [0] = utf8_fullpath;
4235 for (i = 1; i < argc; ++i) {
4238 utf8_arg=mono_utf8_from_external (argv[i]);
4239 if(utf8_arg==NULL) {
4240 /* Ditto the comment about Invalid UTF-8 here */
4241 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4242 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4246 main_args [i] = utf8_arg;
4251 sig = mono_method_signature (method);
4253 g_print ("Unable to load Main method.\n");
4257 if (sig->param_count) {
4258 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4259 mono_error_assert_ok (&error);
4260 for (i = 0; i < argc; ++i) {
4261 /* The encodings should all work, given that
4262 * we've checked all these args for the
4265 gchar *str = mono_utf8_from_external (argv [i]);
4266 MonoString *arg = mono_string_new (domain, str);
4267 mono_array_setref (args, i, arg);
4271 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4272 mono_error_assert_ok (&error);
4275 mono_assembly_set_main (method->klass->image->assembly);
4277 return mono_runtime_exec_main (method, args, exc);
4281 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4283 static MonoMethod *serialize_method;
4289 if (!serialize_method) {
4290 MonoClass *klass = mono_class_get_remoting_services_class ();
4291 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4294 if (!serialize_method) {
4299 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4304 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4305 if (*exc == NULL && !mono_error_ok (&error))
4306 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4308 mono_error_cleanup (&error);
4317 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4319 MONO_REQ_GC_UNSAFE_MODE;
4321 static MonoMethod *deserialize_method;
4327 if (!deserialize_method) {
4328 MonoClass *klass = mono_class_get_remoting_services_class ();
4329 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4331 if (!deserialize_method) {
4339 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4340 if (*exc == NULL && !mono_error_ok (&error))
4341 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4343 mono_error_cleanup (&error);
4351 #ifndef DISABLE_REMOTING
4353 make_transparent_proxy (MonoObject *obj, MonoError *error)
4355 MONO_REQ_GC_UNSAFE_MODE;
4357 static MonoMethod *get_proxy_method;
4359 MonoDomain *domain = mono_domain_get ();
4360 MonoRealProxy *real_proxy;
4361 MonoReflectionType *reflection_type;
4362 MonoTransparentProxy *transparent_proxy;
4364 mono_error_init (error);
4366 if (!get_proxy_method)
4367 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4369 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4371 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4372 return_val_if_nok (error, NULL);
4373 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4374 return_val_if_nok (error, NULL);
4376 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4377 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4379 MonoObject *exc = NULL;
4381 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4382 if (exc != NULL && is_ok (error))
4383 mono_error_set_exception_instance (error, (MonoException*)exc);
4385 return (MonoObject*) transparent_proxy;
4387 #endif /* DISABLE_REMOTING */
4390 * mono_object_xdomain_representation
4392 * @target_domain: a domain
4393 * @error: set on error.
4395 * Creates a representation of obj in the domain target_domain. This
4396 * is either a copy of obj arrived through via serialization and
4397 * deserialization or a proxy, depending on whether the object is
4398 * serializable or marshal by ref. obj must not be in target_domain.
4400 * If the object cannot be represented in target_domain, NULL is
4401 * returned and @error is set appropriately.
4404 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4406 MONO_REQ_GC_UNSAFE_MODE;
4408 mono_error_init (error);
4409 MonoObject *deserialized = NULL;
4411 #ifndef DISABLE_REMOTING
4412 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4413 deserialized = make_transparent_proxy (obj, error);
4418 gboolean failure = FALSE;
4419 MonoDomain *domain = mono_domain_get ();
4420 MonoObject *serialized;
4421 MonoObject *exc = NULL;
4423 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4424 serialized = serialize_object (obj, &failure, &exc);
4425 mono_domain_set_internal_with_options (target_domain, FALSE);
4427 deserialized = deserialize_object (serialized, &failure, &exc);
4428 if (domain != target_domain)
4429 mono_domain_set_internal_with_options (domain, FALSE);
4431 mono_error_set_exception_instance (error, (MonoException*)exc);
4434 return deserialized;
4437 /* Used in call_unhandled_exception_delegate */
4439 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4441 MONO_REQ_GC_UNSAFE_MODE;
4443 mono_error_init (error);
4446 MonoMethod *method = NULL;
4447 MonoBoolean is_terminating = TRUE;
4450 klass = mono_class_get_unhandled_exception_event_args_class ();
4451 mono_class_init (klass);
4453 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4454 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4458 args [1] = &is_terminating;
4460 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4461 return_val_if_nok (error, NULL);
4463 mono_runtime_invoke_checked (method, obj, args, error);
4464 return_val_if_nok (error, NULL);
4469 /* Used in mono_unhandled_exception */
4471 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4472 MONO_REQ_GC_UNSAFE_MODE;
4475 MonoObject *e = NULL;
4477 MonoDomain *current_domain = mono_domain_get ();
4479 if (domain != current_domain)
4480 mono_domain_set_internal_with_options (domain, FALSE);
4482 g_assert (domain == mono_object_domain (domain->domain));
4484 if (mono_object_domain (exc) != domain) {
4486 exc = mono_object_xdomain_representation (exc, domain, &error);
4488 if (!is_ok (&error)) {
4489 MonoError inner_error;
4490 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4491 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4492 mono_error_assert_ok (&inner_error);
4494 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4495 "System.Runtime.Serialization", "SerializationException",
4496 "Could not serialize unhandled exception.");
4500 g_assert (mono_object_domain (exc) == domain);
4502 pa [0] = domain->domain;
4503 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4504 mono_error_assert_ok (&error);
4505 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4506 if (!is_ok (&error)) {
4508 e = (MonoObject*)mono_error_convert_to_exception (&error);
4510 mono_error_cleanup (&error);
4513 if (domain != current_domain)
4514 mono_domain_set_internal_with_options (current_domain, FALSE);
4517 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4518 if (!mono_error_ok (&error)) {
4519 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4520 mono_error_cleanup (&error);
4522 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4528 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4531 * mono_runtime_unhandled_exception_policy_set:
4532 * @policy: the new policy
4534 * This is a VM internal routine.
4536 * Sets the runtime policy for handling unhandled exceptions.
4539 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4540 runtime_unhandled_exception_policy = policy;
4544 * mono_runtime_unhandled_exception_policy_get:
4546 * This is a VM internal routine.
4548 * Gets the runtime policy for handling unhandled exceptions.
4550 MonoRuntimeUnhandledExceptionPolicy
4551 mono_runtime_unhandled_exception_policy_get (void) {
4552 return runtime_unhandled_exception_policy;
4556 * mono_unhandled_exception:
4557 * @exc: exception thrown
4559 * This is a VM internal routine.
4561 * We call this function when we detect an unhandled exception
4562 * in the default domain.
4564 * It invokes the * UnhandledException event in AppDomain or prints
4565 * a warning to the console
4568 mono_unhandled_exception (MonoObject *exc)
4570 MONO_REQ_GC_UNSAFE_MODE;
4573 MonoClassField *field;
4574 MonoDomain *current_domain, *root_domain;
4575 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4577 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4580 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4583 current_domain = mono_domain_get ();
4584 root_domain = mono_get_root_domain ();
4586 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4587 mono_error_assert_ok (&error);
4588 if (current_domain != root_domain) {
4589 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4590 mono_error_assert_ok (&error);
4593 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4594 mono_print_unhandled_exception (exc);
4596 if (root_appdomain_delegate)
4597 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4598 if (current_appdomain_delegate)
4599 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4602 /* set exitcode only if we will abort the process */
4603 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4604 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4606 mono_environment_exitcode_set (1);
4611 * mono_runtime_exec_managed_code:
4612 * @domain: Application domain
4613 * @main_func: function to invoke from the execution thread
4614 * @main_args: parameter to the main_func
4616 * Launch a new thread to execute a function
4618 * main_func is called back from the thread with main_args as the
4619 * parameter. The callback function is expected to start Main()
4620 * eventually. This function then waits for all managed threads to
4622 * It is not necesseray anymore to execute managed code in a subthread,
4623 * so this function should not be used anymore by default: just
4624 * execute the code and then call mono_thread_manage ().
4627 mono_runtime_exec_managed_code (MonoDomain *domain,
4628 MonoMainThreadFunc main_func,
4632 mono_thread_create_checked (domain, main_func, main_args, &error);
4633 mono_error_assert_ok (&error);
4635 mono_thread_manage ();
4639 * Execute a standard Main() method (args doesn't contain the
4643 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4645 MONO_REQ_GC_UNSAFE_MODE;
4651 MonoCustomAttrInfo* cinfo;
4652 gboolean has_stathread_attribute;
4653 MonoInternalThread* thread = mono_thread_internal_current ();
4659 domain = mono_object_domain (args);
4660 if (!domain->entry_assembly) {
4662 MonoAssembly *assembly;
4664 assembly = method->klass->image->assembly;
4665 domain->entry_assembly = assembly;
4666 /* Domains created from another domain already have application_base and configuration_file set */
4667 if (domain->setup->application_base == NULL) {
4668 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4671 if (domain->setup->configuration_file == NULL) {
4672 str = g_strconcat (assembly->image->name, ".config", NULL);
4673 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4675 mono_domain_set_options_from_config (domain);
4679 cinfo = mono_custom_attrs_from_method_checked (method, &error);
4680 mono_error_cleanup (&error); /* FIXME warn here? */
4682 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4684 mono_custom_attrs_free (cinfo);
4686 has_stathread_attribute = FALSE;
4688 if (has_stathread_attribute) {
4689 thread->apartment_state = ThreadApartmentState_STA;
4691 thread->apartment_state = ThreadApartmentState_MTA;
4693 mono_thread_init_apartment_state ();
4695 /* FIXME: check signature of method */
4696 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4699 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4700 if (*exc == NULL && !mono_error_ok (&error))
4701 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4703 mono_error_cleanup (&error);
4705 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4706 mono_error_raise_exception (&error); /* FIXME don't raise here */
4710 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4714 mono_environment_exitcode_set (rval);
4717 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4718 if (*exc == NULL && !mono_error_ok (&error))
4719 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4721 mono_error_cleanup (&error);
4723 mono_runtime_invoke_checked (method, NULL, pa, &error);
4724 mono_error_raise_exception (&error); /* FIXME don't raise here */
4730 /* If the return type of Main is void, only
4731 * set the exitcode if an exception was thrown
4732 * (we don't want to blow away an
4733 * explicitly-set exit code)
4736 mono_environment_exitcode_set (rval);
4743 /** invoke_array_extract_argument:
4744 * @params: array of arguments to the method.
4745 * @i: the index of the argument to extract.
4746 * @t: ith type from the method signature.
4747 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4748 * @error: set on error.
4750 * Given an array of method arguments, return the ith one using the corresponding type
4751 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4753 * On failure sets @error and returns NULL.
4756 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4758 MonoType *t_orig = t;
4759 gpointer result = NULL;
4760 mono_error_init (error);
4765 case MONO_TYPE_BOOLEAN:
4768 case MONO_TYPE_CHAR:
4777 case MONO_TYPE_VALUETYPE:
4778 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4779 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4780 result = mono_array_get (params, MonoObject*, i);
4782 *has_byref_nullables = TRUE;
4784 /* MS seems to create the objects if a null is passed in */
4785 if (!mono_array_get (params, MonoObject*, i)) {
4786 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4787 return_val_if_nok (error, NULL);
4788 mono_array_setref (params, i, o);
4793 * We can't pass the unboxed vtype byref to the callee, since
4794 * that would mean the callee would be able to modify boxed
4795 * primitive types. So we (and MS) make a copy of the boxed
4796 * object, pass that to the callee, and replace the original
4797 * boxed object in the arg array with the copy.
4799 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4800 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4801 return_val_if_nok (error, NULL);
4802 mono_array_setref (params, i, copy);
4805 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4808 case MONO_TYPE_STRING:
4809 case MONO_TYPE_OBJECT:
4810 case MONO_TYPE_CLASS:
4811 case MONO_TYPE_ARRAY:
4812 case MONO_TYPE_SZARRAY:
4814 result = mono_array_addr (params, MonoObject*, i);
4815 // FIXME: I need to check this code path
4817 result = mono_array_get (params, MonoObject*, i);
4819 case MONO_TYPE_GENERICINST:
4821 t = &t->data.generic_class->container_class->this_arg;
4823 t = &t->data.generic_class->container_class->byval_arg;
4825 case MONO_TYPE_PTR: {
4828 /* The argument should be an IntPtr */
4829 arg = mono_array_get (params, MonoObject*, i);
4833 g_assert (arg->vtable->klass == mono_defaults.int_class);
4834 result = ((MonoIntPtr*)arg)->m_value;
4839 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
4844 * mono_runtime_invoke_array:
4845 * @method: method to invoke
4846 * @obJ: object instance
4847 * @params: arguments to the method
4848 * @exc: exception information.
4850 * Invokes the method represented by @method on the object @obj.
4852 * obj is the 'this' pointer, it should be NULL for static
4853 * methods, a MonoObject* for object instances and a pointer to
4854 * the value type for value types.
4856 * The params array contains the arguments to the method with the
4857 * same convention: MonoObject* pointers for object instances and
4858 * pointers to the value type otherwise. The _invoke_array
4859 * variant takes a C# object[] as the params argument (MonoArray
4860 * *params): in this case the value types are boxed inside the
4861 * respective reference representation.
4863 * From unmanaged code you'll usually use the
4864 * mono_runtime_invoke_checked() variant.
4866 * Note that this function doesn't handle virtual methods for
4867 * you, it will exec the exact method you pass: we still need to
4868 * expose a function to lookup the derived class implementation
4869 * of a virtual method (there are examples of this in the code,
4872 * You can pass NULL as the exc argument if you don't want to
4873 * catch exceptions, otherwise, *exc will be set to the exception
4874 * thrown, if any. if an exception is thrown, you can't use the
4875 * MonoObject* result from the function.
4877 * If the method returns a value type, it is boxed in an object
4881 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4886 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
4888 mono_error_cleanup (&error);
4891 if (!is_ok (&error))
4892 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4896 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
4897 mono_error_raise_exception (&error); /* FIXME don't raise here */
4903 * mono_runtime_invoke_array_checked:
4904 * @method: method to invoke
4905 * @obJ: object instance
4906 * @params: arguments to the method
4907 * @error: set on failure.
4909 * Invokes the method represented by @method on the object @obj.
4911 * obj is the 'this' pointer, it should be NULL for static
4912 * methods, a MonoObject* for object instances and a pointer to
4913 * the value type for value types.
4915 * The params array contains the arguments to the method with the
4916 * same convention: MonoObject* pointers for object instances and
4917 * pointers to the value type otherwise. The _invoke_array
4918 * variant takes a C# object[] as the params argument (MonoArray
4919 * *params): in this case the value types are boxed inside the
4920 * respective reference representation.
4922 * From unmanaged code you'll usually use the
4923 * mono_runtime_invoke_checked() variant.
4925 * Note that this function doesn't handle virtual methods for
4926 * you, it will exec the exact method you pass: we still need to
4927 * expose a function to lookup the derived class implementation
4928 * of a virtual method (there are examples of this in the code,
4931 * On failure or exception, @error will be set. In that case, you
4932 * can't use the MonoObject* result from the function.
4934 * If the method returns a value type, it is boxed in an object
4938 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
4941 mono_error_init (error);
4942 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
4946 * mono_runtime_try_invoke_array:
4947 * @method: method to invoke
4948 * @obJ: object instance
4949 * @params: arguments to the method
4950 * @exc: exception information.
4951 * @error: set on failure.
4953 * Invokes the method represented by @method on the object @obj.
4955 * obj is the 'this' pointer, it should be NULL for static
4956 * methods, a MonoObject* for object instances and a pointer to
4957 * the value type for value types.
4959 * The params array contains the arguments to the method with the
4960 * same convention: MonoObject* pointers for object instances and
4961 * pointers to the value type otherwise. The _invoke_array
4962 * variant takes a C# object[] as the params argument (MonoArray
4963 * *params): in this case the value types are boxed inside the
4964 * respective reference representation.
4966 * From unmanaged code you'll usually use the
4967 * mono_runtime_invoke_checked() variant.
4969 * Note that this function doesn't handle virtual methods for
4970 * you, it will exec the exact method you pass: we still need to
4971 * expose a function to lookup the derived class implementation
4972 * of a virtual method (there are examples of this in the code,
4975 * You can pass NULL as the exc argument if you don't want to catch
4976 * exceptions, otherwise, *exc will be set to the exception thrown, if
4977 * any. On other failures, @error will be set. If an exception is
4978 * thrown or there's an error, you can't use the MonoObject* result
4979 * from the function.
4981 * If the method returns a value type, it is boxed in an object
4985 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4986 MonoObject **exc, MonoError *error)
4988 MONO_REQ_GC_UNSAFE_MODE;
4990 mono_error_init (error);
4992 MonoMethodSignature *sig = mono_method_signature (method);
4993 gpointer *pa = NULL;
4996 gboolean has_byref_nullables = FALSE;
4998 if (NULL != params) {
4999 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5000 for (i = 0; i < mono_array_length (params); i++) {
5001 MonoType *t = sig->params [i];
5002 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5003 return_val_if_nok (error, NULL);
5007 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5010 if (mono_class_is_nullable (method->klass)) {
5011 /* Need to create a boxed vtype instead */
5017 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5022 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5023 mono_error_assert_ok (error);
5024 g_assert (obj); /*maybe we should raise a TLE instead?*/
5025 #ifndef DISABLE_REMOTING
5026 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5027 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5030 if (method->klass->valuetype)
5031 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5034 } else if (method->klass->valuetype) {
5035 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5036 return_val_if_nok (error, NULL);
5040 mono_runtime_try_invoke (method, o, pa, exc, error);
5042 mono_runtime_invoke_checked (method, o, pa, error);
5045 return (MonoObject *)obj;
5047 if (mono_class_is_nullable (method->klass)) {
5048 MonoObject *nullable;
5050 /* Convert the unboxed vtype into a Nullable structure */
5051 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5052 return_val_if_nok (error, NULL);
5054 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5055 return_val_if_nok (error, NULL);
5056 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5057 obj = mono_object_unbox (nullable);
5060 /* obj must be already unboxed if needed */
5062 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5064 res = mono_runtime_invoke_checked (method, obj, pa, error);
5066 return_val_if_nok (error, NULL);
5068 if (sig->ret->type == MONO_TYPE_PTR) {
5069 MonoClass *pointer_class;
5070 static MonoMethod *box_method;
5072 MonoObject *box_exc;
5075 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5076 * convert it to a Pointer object.
5078 pointer_class = mono_class_get_pointer_class ();
5080 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5082 g_assert (res->vtable->klass == mono_defaults.int_class);
5083 box_args [0] = ((MonoIntPtr*)res)->m_value;
5084 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5085 return_val_if_nok (error, NULL);
5087 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5088 g_assert (box_exc == NULL);
5089 mono_error_assert_ok (error);
5092 if (has_byref_nullables) {
5094 * The runtime invoke wrapper already converted byref nullables back,
5095 * and stored them in pa, we just need to copy them back to the
5098 for (i = 0; i < mono_array_length (params); i++) {
5099 MonoType *t = sig->params [i];
5101 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5102 mono_array_setref (params, i, pa [i]);
5112 * @klass: the class of the object that we want to create
5114 * Returns: a newly created object whose definition is
5115 * looked up using @klass. This will not invoke any constructors,
5116 * so the consumer of this routine has to invoke any constructors on
5117 * its own to initialize the object.
5119 * It returns NULL on failure.
5122 mono_object_new (MonoDomain *domain, MonoClass *klass)
5124 MONO_REQ_GC_UNSAFE_MODE;
5128 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5130 mono_error_cleanup (&error);
5135 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5137 MONO_REQ_GC_UNSAFE_MODE;
5141 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5143 mono_error_set_pending_exception (&error);
5148 * mono_object_new_checked:
5149 * @klass: the class of the object that we want to create
5150 * @error: set on error
5152 * Returns: a newly created object whose definition is
5153 * looked up using @klass. This will not invoke any constructors,
5154 * so the consumer of this routine has to invoke any constructors on
5155 * its own to initialize the object.
5157 * It returns NULL on failure and sets @error.
5160 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5162 MONO_REQ_GC_UNSAFE_MODE;
5166 vtable = mono_class_vtable (domain, klass);
5167 g_assert (vtable); /* FIXME don't swallow the error */
5169 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5174 * mono_object_new_pinned:
5176 * Same as mono_object_new, but the returned object will be pinned.
5177 * For SGEN, these objects will only be freed at appdomain unload.
5180 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5182 MONO_REQ_GC_UNSAFE_MODE;
5186 mono_error_init (error);
5188 vtable = mono_class_vtable (domain, klass);
5189 g_assert (vtable); /* FIXME don't swallow the error */
5191 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5193 if (G_UNLIKELY (!o))
5194 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5195 else if (G_UNLIKELY (vtable->klass->has_finalize))
5196 mono_object_register_finalizer (o);
5202 * mono_object_new_specific:
5203 * @vtable: the vtable of the object that we want to create
5205 * Returns: A newly created object with class and domain specified
5209 mono_object_new_specific (MonoVTable *vtable)
5212 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5213 mono_error_cleanup (&error);
5219 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5221 MONO_REQ_GC_UNSAFE_MODE;
5225 mono_error_init (error);
5227 /* check for is_com_object for COM Interop */
5228 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5231 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5234 MonoClass *klass = mono_class_get_activation_services_class ();
5237 mono_class_init (klass);
5239 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5241 mono_error_set_not_supported (error, "Linked away.");
5244 vtable->domain->create_proxy_for_type_method = im;
5247 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5248 if (!mono_error_ok (error))
5251 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5252 if (!mono_error_ok (error))
5259 return mono_object_new_alloc_specific_checked (vtable, error);
5263 ves_icall_object_new_specific (MonoVTable *vtable)
5266 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5267 mono_error_set_pending_exception (&error);
5273 * mono_object_new_alloc_specific:
5274 * @vtable: virtual table for the object.
5276 * This function allocates a new `MonoObject` with the type derived
5277 * from the @vtable information. If the class of this object has a
5278 * finalizer, then the object will be tracked for finalization.
5280 * This method might raise an exception on errors. Use the
5281 * `mono_object_new_fast_checked` method if you want to manually raise
5284 * Returns: the allocated object.
5287 mono_object_new_alloc_specific (MonoVTable *vtable)
5290 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5291 mono_error_cleanup (&error);
5297 * mono_object_new_alloc_specific_checked:
5298 * @vtable: virtual table for the object.
5299 * @error: holds the error return value.
5301 * This function allocates a new `MonoObject` with the type derived
5302 * from the @vtable information. If the class of this object has a
5303 * finalizer, then the object will be tracked for finalization.
5305 * If there is not enough memory, the @error parameter will be set
5306 * and will contain a user-visible message with the amount of bytes
5307 * that were requested.
5309 * Returns: the allocated object, or NULL if there is not enough memory
5313 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5315 MONO_REQ_GC_UNSAFE_MODE;
5319 mono_error_init (error);
5321 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5323 if (G_UNLIKELY (!o))
5324 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5325 else if (G_UNLIKELY (vtable->klass->has_finalize))
5326 mono_object_register_finalizer (o);
5332 * mono_object_new_fast:
5333 * @vtable: virtual table for the object.
5335 * This function allocates a new `MonoObject` with the type derived
5336 * from the @vtable information. The returned object is not tracked
5337 * for finalization. If your object implements a finalizer, you should
5338 * use `mono_object_new_alloc_specific` instead.
5340 * This method might raise an exception on errors. Use the
5341 * `mono_object_new_fast_checked` method if you want to manually raise
5344 * Returns: the allocated object.
5347 mono_object_new_fast (MonoVTable *vtable)
5350 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5351 mono_error_cleanup (&error);
5357 * mono_object_new_fast_checked:
5358 * @vtable: virtual table for the object.
5359 * @error: holds the error return value.
5361 * This function allocates a new `MonoObject` with the type derived
5362 * from the @vtable information. The returned object is not tracked
5363 * for finalization. If your object implements a finalizer, you should
5364 * use `mono_object_new_alloc_specific_checked` instead.
5366 * If there is not enough memory, the @error parameter will be set
5367 * and will contain a user-visible message with the amount of bytes
5368 * that were requested.
5370 * Returns: the allocated object, or NULL if there is not enough memory
5374 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5376 MONO_REQ_GC_UNSAFE_MODE;
5380 mono_error_init (error);
5382 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5384 if (G_UNLIKELY (!o))
5385 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5391 ves_icall_object_new_fast (MonoVTable *vtable)
5394 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5395 mono_error_set_pending_exception (&error);
5401 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5403 MONO_REQ_GC_UNSAFE_MODE;
5407 mono_error_init (error);
5409 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5411 if (G_UNLIKELY (!o))
5412 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5413 else if (G_UNLIKELY (vtable->klass->has_finalize))
5414 mono_object_register_finalizer (o);
5420 * mono_class_get_allocation_ftn:
5422 * @for_box: the object will be used for boxing
5423 * @pass_size_in_words:
5425 * Return the allocation function appropriate for the given class.
5429 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5431 MONO_REQ_GC_NEUTRAL_MODE;
5433 *pass_size_in_words = FALSE;
5435 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5436 return ves_icall_object_new_specific;
5438 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5440 return ves_icall_object_new_fast;
5443 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5444 * of the overhead of parameter passing.
5447 *pass_size_in_words = TRUE;
5448 #ifdef GC_REDIRECT_TO_LOCAL
5449 return GC_local_gcj_fast_malloc;
5451 return GC_gcj_fast_malloc;
5456 return ves_icall_object_new_specific;
5460 * mono_object_new_from_token:
5461 * @image: Context where the type_token is hosted
5462 * @token: a token of the type that we want to create
5464 * Returns: A newly created object whose definition is
5465 * looked up using @token in the @image image
5468 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5470 MONO_REQ_GC_UNSAFE_MODE;
5476 klass = mono_class_get_checked (image, token, &error);
5477 mono_error_assert_ok (&error);
5479 result = mono_object_new_checked (domain, klass, &error);
5481 mono_error_cleanup (&error);
5488 * mono_object_clone:
5489 * @obj: the object to clone
5491 * Returns: A newly created object who is a shallow copy of @obj
5494 mono_object_clone (MonoObject *obj)
5497 MonoObject *o = mono_object_clone_checked (obj, &error);
5498 mono_error_cleanup (&error);
5504 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5506 MONO_REQ_GC_UNSAFE_MODE;
5511 mono_error_init (error);
5513 size = obj->vtable->klass->instance_size;
5515 if (obj->vtable->klass->rank)
5516 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5518 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5520 if (G_UNLIKELY (!o)) {
5521 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5525 /* If the object doesn't contain references this will do a simple memmove. */
5526 mono_gc_wbarrier_object_copy (o, obj);
5528 if (obj->vtable->klass->has_finalize)
5529 mono_object_register_finalizer (o);
5534 * mono_array_full_copy:
5535 * @src: source array to copy
5536 * @dest: destination array
5538 * Copies the content of one array to another with exactly the same type and size.
5541 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5543 MONO_REQ_GC_UNSAFE_MODE;
5546 MonoClass *klass = src->obj.vtable->klass;
5548 g_assert (klass == dest->obj.vtable->klass);
5550 size = mono_array_length (src);
5551 g_assert (size == mono_array_length (dest));
5552 size *= mono_array_element_size (klass);
5554 if (klass->element_class->valuetype) {
5555 if (klass->element_class->has_references)
5556 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5558 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5560 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5563 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5568 * mono_array_clone_in_domain:
5569 * @domain: the domain in which the array will be cloned into
5570 * @array: the array to clone
5571 * @error: set on error
5573 * This routine returns a copy of the array that is hosted on the
5574 * specified MonoDomain. On failure returns NULL and sets @error.
5577 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5579 MONO_REQ_GC_UNSAFE_MODE;
5584 MonoClass *klass = array->obj.vtable->klass;
5586 mono_error_init (error);
5588 if (array->bounds == NULL) {
5589 size = mono_array_length (array);
5590 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5591 return_val_if_nok (error, NULL);
5593 size *= mono_array_element_size (klass);
5595 if (klass->element_class->valuetype) {
5596 if (klass->element_class->has_references)
5597 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5599 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5601 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5604 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5609 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5610 size = mono_array_element_size (klass);
5611 for (i = 0; i < klass->rank; ++i) {
5612 sizes [i] = array->bounds [i].length;
5613 size *= array->bounds [i].length;
5614 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5616 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5617 return_val_if_nok (error, NULL);
5619 if (klass->element_class->valuetype) {
5620 if (klass->element_class->has_references)
5621 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5623 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5625 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5628 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5636 * @array: the array to clone
5638 * Returns: A newly created array who is a shallow copy of @array
5641 mono_array_clone (MonoArray *array)
5643 MONO_REQ_GC_UNSAFE_MODE;
5646 MonoArray *result = mono_array_clone_checked (array, &error);
5647 mono_error_cleanup (&error);
5652 * mono_array_clone_checked:
5653 * @array: the array to clone
5654 * @error: set on error
5656 * Returns: A newly created array who is a shallow copy of @array. On
5657 * failure returns NULL and sets @error.
5660 mono_array_clone_checked (MonoArray *array, MonoError *error)
5663 MONO_REQ_GC_UNSAFE_MODE;
5664 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5667 /* helper macros to check for overflow when calculating the size of arrays */
5668 #ifdef MONO_BIG_ARRAYS
5669 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5670 #define MYGUINT_MAX MYGUINT64_MAX
5671 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5672 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5673 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5674 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5675 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5677 #define MYGUINT32_MAX 4294967295U
5678 #define MYGUINT_MAX MYGUINT32_MAX
5679 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5680 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5681 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5682 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5683 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5687 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5689 MONO_REQ_GC_NEUTRAL_MODE;
5693 byte_len = mono_array_element_size (klass);
5694 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5697 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5699 byte_len += MONO_SIZEOF_MONO_ARRAY;
5707 * mono_array_new_full:
5708 * @domain: domain where the object is created
5709 * @array_class: array class
5710 * @lengths: lengths for each dimension in the array
5711 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5713 * This routine creates a new array objects with the given dimensions,
5714 * lower bounds and type.
5717 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5720 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5721 mono_error_cleanup (&error);
5727 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5729 MONO_REQ_GC_UNSAFE_MODE;
5731 uintptr_t byte_len = 0, len, bounds_size;
5734 MonoArrayBounds *bounds;
5738 mono_error_init (error);
5740 if (!array_class->inited)
5741 mono_class_init (array_class);
5745 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5746 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5748 if (len > MONO_ARRAY_MAX_INDEX) {
5749 mono_error_set_generic_error (error, "System", "OverflowException", "");
5754 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5756 for (i = 0; i < array_class->rank; ++i) {
5757 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5758 mono_error_set_generic_error (error, "System", "OverflowException", "");
5761 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5762 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5769 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5770 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5776 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5777 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5780 byte_len = (byte_len + 3) & ~3;
5781 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5782 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5785 byte_len += bounds_size;
5788 * Following three lines almost taken from mono_object_new ():
5789 * they need to be kept in sync.
5791 vtable = mono_class_vtable_full (domain, array_class, error);
5792 return_val_if_nok (error, NULL);
5795 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5797 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5799 if (G_UNLIKELY (!o)) {
5800 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5804 array = (MonoArray*)o;
5806 bounds = array->bounds;
5809 for (i = 0; i < array_class->rank; ++i) {
5810 bounds [i].length = lengths [i];
5812 bounds [i].lower_bound = lower_bounds [i];
5821 * @domain: domain where the object is created
5822 * @eclass: element class
5823 * @n: number of array elements
5825 * This routine creates a new szarray with @n elements of type @eclass.
5828 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5830 MONO_REQ_GC_UNSAFE_MODE;
5833 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5834 mono_error_cleanup (&error);
5839 * mono_array_new_checked:
5840 * @domain: domain where the object is created
5841 * @eclass: element class
5842 * @n: number of array elements
5843 * @error: set on error
5845 * This routine creates a new szarray with @n elements of type @eclass.
5846 * On failure returns NULL and sets @error.
5849 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5853 mono_error_init (error);
5855 ac = mono_array_class_get (eclass, 1);
5858 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5859 return_val_if_nok (error, NULL);
5861 return mono_array_new_specific_checked (vtable, n, error);
5865 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5868 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5869 mono_error_set_pending_exception (&error);
5875 * mono_array_new_specific:
5876 * @vtable: a vtable in the appropriate domain for an initialized class
5877 * @n: number of array elements
5879 * This routine is a fast alternative to mono_array_new() for code which
5880 * can be sure about the domain it operates in.
5883 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5886 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5887 mono_error_cleanup (&error);
5893 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5895 MONO_REQ_GC_UNSAFE_MODE;
5900 mono_error_init (error);
5902 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5903 mono_error_set_generic_error (error, "System", "OverflowException", "");
5907 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5908 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5911 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5913 if (G_UNLIKELY (!o)) {
5914 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5918 return (MonoArray*)o;
5922 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5925 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5926 mono_error_set_pending_exception (&error);
5932 * mono_string_new_utf16:
5933 * @text: a pointer to an utf16 string
5934 * @len: the length of the string
5936 * Returns: A newly created string object which contains @text.
5939 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5941 MONO_REQ_GC_UNSAFE_MODE;
5944 MonoString *res = NULL;
5945 res = mono_string_new_utf16_checked (domain, text, len, &error);
5946 mono_error_cleanup (&error);
5952 * mono_string_new_utf16_checked:
5953 * @text: a pointer to an utf16 string
5954 * @len: the length of the string
5955 * @error: written on error.
5957 * Returns: A newly created string object which contains @text.
5958 * On error, returns NULL and sets @error.
5961 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5963 MONO_REQ_GC_UNSAFE_MODE;
5967 mono_error_init (error);
5969 s = mono_string_new_size_checked (domain, len, error);
5971 memcpy (mono_string_chars (s), text, len * 2);
5977 * mono_string_new_utf32:
5978 * @text: a pointer to an utf32 string
5979 * @len: the length of the string
5980 * @error: set on failure.
5982 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
5985 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
5987 MONO_REQ_GC_UNSAFE_MODE;
5990 mono_unichar2 *utf16_output = NULL;
5991 gint32 utf16_len = 0;
5992 GError *gerror = NULL;
5993 glong items_written;
5995 mono_error_init (error);
5996 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5999 g_error_free (gerror);
6001 while (utf16_output [utf16_len]) utf16_len++;
6003 s = mono_string_new_size_checked (domain, utf16_len, error);
6004 return_val_if_nok (error, NULL);
6006 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6008 g_free (utf16_output);
6014 * mono_string_new_utf32:
6015 * @text: a pointer to an utf32 string
6016 * @len: the length of the string
6018 * Returns: A newly created string object which contains @text.
6021 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6024 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6025 mono_error_cleanup (&error);
6030 * mono_string_new_size:
6031 * @text: a pointer to an utf16 string
6032 * @len: the length of the string
6034 * Returns: A newly created string object of @len
6037 mono_string_new_size (MonoDomain *domain, gint32 len)
6040 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6041 mono_error_cleanup (&error);
6047 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6049 MONO_REQ_GC_UNSAFE_MODE;
6055 mono_error_init (error);
6057 /* check for overflow */
6058 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6059 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6063 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6064 g_assert (size > 0);
6066 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6069 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6071 if (G_UNLIKELY (!s)) {
6072 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6080 * mono_string_new_len:
6081 * @text: a pointer to an utf8 string
6082 * @length: number of bytes in @text to consider
6084 * Returns: A newly created string object which contains @text.
6087 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6089 MONO_REQ_GC_UNSAFE_MODE;
6092 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6093 mono_error_cleanup (&error);
6098 * mono_string_new_len_checked:
6099 * @text: a pointer to an utf8 string
6100 * @length: number of bytes in @text to consider
6101 * @error: set on error
6103 * Returns: A newly created string object which contains @text. On
6104 * failure returns NULL and sets @error.
6107 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6109 MONO_REQ_GC_UNSAFE_MODE;
6111 mono_error_init (error);
6113 GError *eg_error = NULL;
6114 MonoString *o = NULL;
6116 glong items_written;
6118 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6121 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6123 g_error_free (eg_error);
6132 * @text: a pointer to an utf8 string
6134 * Returns: A newly created string object which contains @text.
6136 * This function asserts if it cannot allocate a new string.
6138 * @deprecated Use mono_string_new_checked in new code.
6141 mono_string_new (MonoDomain *domain, const char *text)
6144 MonoString *res = NULL;
6145 res = mono_string_new_checked (domain, text, &error);
6146 mono_error_assert_ok (&error);
6151 * mono_string_new_checked:
6152 * @text: a pointer to an utf8 string
6153 * @merror: set on error
6155 * Returns: A newly created string object which contains @text.
6156 * On error returns NULL and sets @merror.
6159 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6161 MONO_REQ_GC_UNSAFE_MODE;
6163 GError *eg_error = NULL;
6164 MonoString *o = NULL;
6166 glong items_written;
6169 mono_error_init (error);
6173 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6176 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6178 g_error_free (eg_error);
6182 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6187 MonoString *o = NULL;
6189 if (!g_utf8_validate (text, -1, &end)) {
6190 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6194 len = g_utf8_strlen (text, -1);
6195 o = mono_string_new_size_checked (domain, len, error);
6198 str = mono_string_chars (o);
6200 while (text < end) {
6201 *str++ = g_utf8_get_char (text);
6202 text = g_utf8_next_char (text);
6211 * mono_string_new_wrapper:
6212 * @text: pointer to utf8 characters.
6214 * Helper function to create a string object from @text in the current domain.
6217 mono_string_new_wrapper (const char *text)
6219 MONO_REQ_GC_UNSAFE_MODE;
6221 MonoDomain *domain = mono_domain_get ();
6224 return mono_string_new (domain, text);
6231 * @class: the class of the value
6232 * @value: a pointer to the unboxed data
6234 * Returns: A newly created object which contains @value.
6237 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6240 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6241 mono_error_cleanup (&error);
6246 * mono_value_box_checked:
6247 * @domain: the domain of the new object
6248 * @class: the class of the value
6249 * @value: a pointer to the unboxed data
6250 * @error: set on error
6252 * Returns: A newly created object which contains @value. On failure
6253 * returns NULL and sets @error.
6256 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6258 MONO_REQ_GC_UNSAFE_MODE;
6263 mono_error_init (error);
6265 g_assert (klass->valuetype);
6266 if (mono_class_is_nullable (klass))
6267 return mono_nullable_box ((guint8 *)value, klass, error);
6269 vtable = mono_class_vtable (domain, klass);
6272 size = mono_class_instance_size (klass);
6273 res = mono_object_new_alloc_specific_checked (vtable, error);
6274 return_val_if_nok (error, NULL);
6276 size = size - sizeof (MonoObject);
6279 g_assert (size == mono_class_value_size (klass, NULL));
6280 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6282 #if NO_UNALIGNED_ACCESS
6283 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6287 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6290 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6293 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6296 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6299 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6303 if (klass->has_finalize) {
6304 mono_object_register_finalizer (res);
6305 return_val_if_nok (error, NULL);
6312 * @dest: destination pointer
6313 * @src: source pointer
6314 * @klass: a valuetype class
6316 * Copy a valuetype from @src to @dest. This function must be used
6317 * when @klass contains references fields.
6320 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6322 MONO_REQ_GC_UNSAFE_MODE;
6324 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6328 * mono_value_copy_array:
6329 * @dest: destination array
6330 * @dest_idx: index in the @dest array
6331 * @src: source pointer
6332 * @count: number of items
6334 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6335 * This function must be used when @klass contains references fields.
6336 * Overlap is handled.
6339 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6341 MONO_REQ_GC_UNSAFE_MODE;
6343 int size = mono_array_element_size (dest->obj.vtable->klass);
6344 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6345 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6346 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6350 * mono_object_get_domain:
6351 * @obj: object to query
6353 * Returns: the MonoDomain where the object is hosted
6356 mono_object_get_domain (MonoObject *obj)
6358 MONO_REQ_GC_UNSAFE_MODE;
6360 return mono_object_domain (obj);
6364 * mono_object_get_class:
6365 * @obj: object to query
6367 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6369 * Returns: the MonoClass of the object.
6372 mono_object_get_class (MonoObject *obj)
6374 MONO_REQ_GC_UNSAFE_MODE;
6376 return mono_object_class (obj);
6379 * mono_object_get_size:
6380 * @o: object to query
6382 * Returns: the size, in bytes, of @o
6385 mono_object_get_size (MonoObject* o)
6387 MONO_REQ_GC_UNSAFE_MODE;
6389 MonoClass* klass = mono_object_class (o);
6390 if (klass == mono_defaults.string_class) {
6391 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6392 } else if (o->vtable->rank) {
6393 MonoArray *array = (MonoArray*)o;
6394 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6395 if (array->bounds) {
6398 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6402 return mono_class_instance_size (klass);
6407 * mono_object_unbox:
6408 * @obj: object to unbox
6410 * Returns: a pointer to the start of the valuetype boxed in this
6413 * This method will assert if the object passed is not a valuetype.
6416 mono_object_unbox (MonoObject *obj)
6418 MONO_REQ_GC_UNSAFE_MODE;
6420 /* add assert for valuetypes? */
6421 g_assert (obj->vtable->klass->valuetype);
6422 return ((char*)obj) + sizeof (MonoObject);
6426 * mono_object_isinst:
6428 * @klass: a pointer to a class
6430 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6433 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6435 MONO_REQ_GC_UNSAFE_MODE;
6438 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6439 mono_error_cleanup (&error);
6445 * mono_object_isinst_checked:
6447 * @klass: a pointer to a class
6448 * @error: set on error
6450 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6451 * On failure returns NULL and sets @error.
6454 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6456 MONO_REQ_GC_UNSAFE_MODE;
6458 mono_error_init (error);
6460 MonoObject *result = NULL;
6463 mono_class_init (klass);
6465 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6466 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6473 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6477 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6479 MONO_REQ_GC_UNSAFE_MODE;
6482 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6483 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6488 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6490 MONO_REQ_GC_UNSAFE_MODE;
6494 mono_error_init (error);
6501 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6502 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6506 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6507 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6510 MonoClass *oklass = vt->klass;
6511 if (mono_class_is_transparent_proxy (oklass))
6512 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6514 mono_class_setup_supertypes (klass);
6515 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6518 #ifndef DISABLE_REMOTING
6519 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6521 MonoDomain *domain = mono_domain_get ();
6523 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6524 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6525 MonoMethod *im = NULL;
6528 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6530 mono_error_set_not_supported (error, "Linked away.");
6533 im = mono_object_get_virtual_method (rp, im);
6536 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6537 return_val_if_nok (error, NULL);
6540 res = mono_runtime_invoke_checked (im, rp, pa, error);
6541 return_val_if_nok (error, NULL);
6543 if (*(MonoBoolean *) mono_object_unbox(res)) {
6544 /* Update the vtable of the remote type, so it can safely cast to this new type */
6545 mono_upgrade_remote_class (domain, obj, klass, error);
6546 return_val_if_nok (error, NULL);
6550 #endif /* DISABLE_REMOTING */
6555 * mono_object_castclass_mbyref:
6557 * @klass: a pointer to a class
6559 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6562 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6564 MONO_REQ_GC_UNSAFE_MODE;
6567 if (!obj) return NULL;
6568 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6569 mono_error_cleanup (&error);
6574 MonoDomain *orig_domain;
6580 str_lookup (MonoDomain *domain, gpointer user_data)
6582 MONO_REQ_GC_UNSAFE_MODE;
6584 LDStrInfo *info = (LDStrInfo *)user_data;
6585 if (info->res || domain == info->orig_domain)
6587 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6591 mono_string_get_pinned (MonoString *str, MonoError *error)
6593 MONO_REQ_GC_UNSAFE_MODE;
6595 mono_error_init (error);
6597 /* We only need to make a pinned version of a string if this is a moving GC */
6598 if (!mono_gc_is_moving ())
6602 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6603 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6605 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6606 news->length = mono_string_length (str);
6608 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6614 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6616 MONO_REQ_GC_UNSAFE_MODE;
6618 MonoGHashTable *ldstr_table;
6619 MonoString *s, *res;
6622 mono_error_init (error);
6624 domain = ((MonoObject *)str)->vtable->domain;
6625 ldstr_table = domain->ldstr_table;
6627 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6633 /* Allocate outside the lock */
6635 s = mono_string_get_pinned (str, error);
6636 return_val_if_nok (error, NULL);
6639 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6644 mono_g_hash_table_insert (ldstr_table, s, s);
6649 LDStrInfo ldstr_info;
6650 ldstr_info.orig_domain = domain;
6651 ldstr_info.ins = str;
6652 ldstr_info.res = NULL;
6654 mono_domain_foreach (str_lookup, &ldstr_info);
6655 if (ldstr_info.res) {
6657 * the string was already interned in some other domain:
6658 * intern it in the current one as well.
6660 mono_g_hash_table_insert (ldstr_table, str, str);
6670 * mono_string_is_interned:
6671 * @o: String to probe
6673 * Returns whether the string has been interned.
6676 mono_string_is_interned (MonoString *o)
6679 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6680 /* This function does not fail. */
6681 mono_error_assert_ok (&error);
6686 * mono_string_intern:
6687 * @o: String to intern
6689 * Interns the string passed.
6690 * Returns: The interned string.
6693 mono_string_intern (MonoString *str)
6696 MonoString *result = mono_string_intern_checked (str, &error);
6697 mono_error_assert_ok (&error);
6702 * mono_string_intern_checked:
6703 * @o: String to intern
6704 * @error: set on error.
6706 * Interns the string passed.
6707 * Returns: The interned string. On failure returns NULL and sets @error
6710 mono_string_intern_checked (MonoString *str, MonoError *error)
6712 MONO_REQ_GC_UNSAFE_MODE;
6714 mono_error_init (error);
6716 return mono_string_is_interned_lookup (str, TRUE, error);
6721 * @domain: the domain where the string will be used.
6722 * @image: a metadata context
6723 * @idx: index into the user string table.
6725 * Implementation for the ldstr opcode.
6726 * Returns: a loaded string from the @image/@idx combination.
6729 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6732 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6733 mono_error_cleanup (&error);
6738 * mono_ldstr_checked:
6739 * @domain: the domain where the string will be used.
6740 * @image: a metadata context
6741 * @idx: index into the user string table.
6742 * @error: set on error.
6744 * Implementation for the ldstr opcode.
6745 * Returns: a loaded string from the @image/@idx combination.
6746 * On failure returns NULL and sets @error.
6749 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6751 MONO_REQ_GC_UNSAFE_MODE;
6752 mono_error_init (error);
6754 if (image->dynamic) {
6755 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6758 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6759 return NULL; /*FIXME we should probably be raising an exception here*/
6760 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6766 * mono_ldstr_metadata_sig
6767 * @domain: the domain for the string
6768 * @sig: the signature of a metadata string
6769 * @error: set on error
6771 * Returns: a MonoString for a string stored in the metadata. On
6772 * failure returns NULL and sets @error.
6775 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6777 MONO_REQ_GC_UNSAFE_MODE;
6779 mono_error_init (error);
6780 const char *str = sig;
6781 MonoString *o, *interned;
6784 len2 = mono_metadata_decode_blob_size (str, &str);
6787 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6788 return_val_if_nok (error, NULL);
6789 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6792 guint16 *p2 = (guint16*)mono_string_chars (o);
6793 for (i = 0; i < len2; ++i) {
6794 *p2 = GUINT16_FROM_LE (*p2);
6800 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6803 return interned; /* o will get garbage collected */
6805 o = mono_string_get_pinned (o, error);
6808 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6810 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6820 * mono_string_to_utf8:
6821 * @s: a System.String
6823 * Returns the UTF8 representation for @s.
6824 * The resulting buffer needs to be freed with mono_free().
6826 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6829 mono_string_to_utf8 (MonoString *s)
6831 MONO_REQ_GC_UNSAFE_MODE;
6834 char *result = mono_string_to_utf8_checked (s, &error);
6836 if (!is_ok (&error)) {
6837 mono_error_cleanup (&error);
6844 * mono_string_to_utf8_checked:
6845 * @s: a System.String
6846 * @error: a MonoError.
6848 * Converts a MonoString to its UTF8 representation. May fail; check
6849 * @error to determine whether the conversion was successful.
6850 * The resulting buffer should be freed with mono_free().
6853 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6855 MONO_REQ_GC_UNSAFE_MODE;
6859 GError *gerror = NULL;
6861 mono_error_init (error);
6867 return g_strdup ("");
6869 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6871 mono_error_set_argument (error, "string", "%s", gerror->message);
6872 g_error_free (gerror);
6875 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6876 if (s->length > written) {
6877 /* allocate the total length and copy the part of the string that has been converted */
6878 char *as2 = (char *)g_malloc0 (s->length);
6879 memcpy (as2, as, written);
6888 * mono_string_to_utf8_ignore:
6891 * Converts a MonoString to its UTF8 representation. Will ignore
6892 * invalid surrogate pairs.
6893 * The resulting buffer should be freed with mono_free().
6897 mono_string_to_utf8_ignore (MonoString *s)
6899 MONO_REQ_GC_UNSAFE_MODE;
6908 return g_strdup ("");
6910 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6912 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6913 if (s->length > written) {
6914 /* allocate the total length and copy the part of the string that has been converted */
6915 char *as2 = (char *)g_malloc0 (s->length);
6916 memcpy (as2, as, written);
6925 * mono_string_to_utf8_image_ignore:
6926 * @s: a System.String
6928 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6931 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6933 MONO_REQ_GC_UNSAFE_MODE;
6935 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6939 * mono_string_to_utf8_mp_ignore:
6940 * @s: a System.String
6942 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6945 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6947 MONO_REQ_GC_UNSAFE_MODE;
6949 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6954 * mono_string_to_utf16:
6957 * Return an null-terminated array of the utf-16 chars
6958 * contained in @s. The result must be freed with g_free().
6959 * This is a temporary helper until our string implementation
6960 * is reworked to always include the null terminating char.
6963 mono_string_to_utf16 (MonoString *s)
6965 MONO_REQ_GC_UNSAFE_MODE;
6972 as = (char *)g_malloc ((s->length * 2) + 2);
6973 as [(s->length * 2)] = '\0';
6974 as [(s->length * 2) + 1] = '\0';
6977 return (gunichar2 *)(as);
6980 memcpy (as, mono_string_chars(s), s->length * 2);
6981 return (gunichar2 *)(as);
6985 * mono_string_to_utf32:
6988 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6989 * contained in @s. The result must be freed with g_free().
6992 mono_string_to_utf32 (MonoString *s)
6994 MONO_REQ_GC_UNSAFE_MODE;
6996 mono_unichar4 *utf32_output = NULL;
6997 GError *error = NULL;
6998 glong items_written;
7003 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7006 g_error_free (error);
7008 return utf32_output;
7012 * mono_string_from_utf16:
7013 * @data: the UTF16 string (LPWSTR) to convert
7015 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7017 * Returns: a MonoString.
7020 mono_string_from_utf16 (gunichar2 *data)
7023 MonoString *result = mono_string_from_utf16_checked (data, &error);
7024 mono_error_cleanup (&error);
7029 * mono_string_from_utf16_checked:
7030 * @data: the UTF16 string (LPWSTR) to convert
7031 * @error: set on error
7033 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7035 * Returns: a MonoString. On failure sets @error and returns NULL.
7038 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7041 MONO_REQ_GC_UNSAFE_MODE;
7043 mono_error_init (error);
7044 MonoDomain *domain = mono_domain_get ();
7050 while (data [len]) len++;
7052 return mono_string_new_utf16_checked (domain, data, len, error);
7056 * mono_string_from_utf32:
7057 * @data: the UTF32 string (LPWSTR) to convert
7059 * Converts a UTF32 (UCS-4)to a MonoString.
7061 * Returns: a MonoString.
7064 mono_string_from_utf32 (mono_unichar4 *data)
7067 MonoString *result = mono_string_from_utf32_checked (data, &error);
7068 mono_error_cleanup (&error);
7073 * mono_string_from_utf32_checked:
7074 * @data: the UTF32 string (LPWSTR) to convert
7075 * @error: set on error
7077 * Converts a UTF32 (UCS-4)to a MonoString.
7079 * Returns: a MonoString. On failure returns NULL and sets @error.
7082 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7084 MONO_REQ_GC_UNSAFE_MODE;
7086 mono_error_init (error);
7087 MonoString* result = NULL;
7088 mono_unichar2 *utf16_output = NULL;
7089 GError *gerror = NULL;
7090 glong items_written;
7096 while (data [len]) len++;
7098 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7101 g_error_free (gerror);
7103 result = mono_string_from_utf16_checked (utf16_output, error);
7104 g_free (utf16_output);
7109 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7111 MONO_REQ_GC_UNSAFE_MODE;
7118 r = mono_string_to_utf8_ignore (s);
7120 r = mono_string_to_utf8_checked (s, error);
7121 if (!mono_error_ok (error))
7128 len = strlen (r) + 1;
7130 mp_s = (char *)mono_mempool_alloc (mp, len);
7132 mp_s = (char *)mono_image_alloc (image, len);
7134 memcpy (mp_s, r, len);
7142 * mono_string_to_utf8_image:
7143 * @s: a System.String
7145 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7148 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7150 MONO_REQ_GC_UNSAFE_MODE;
7152 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7156 * mono_string_to_utf8_mp:
7157 * @s: a System.String
7159 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7162 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7164 MONO_REQ_GC_UNSAFE_MODE;
7166 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7170 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7173 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7175 eh_callbacks = *cbs;
7178 MonoRuntimeExceptionHandlingCallbacks *
7179 mono_get_eh_callbacks (void)
7181 return &eh_callbacks;
7185 * mono_raise_exception:
7186 * @ex: exception object
7188 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7191 mono_raise_exception (MonoException *ex)
7193 MONO_REQ_GC_UNSAFE_MODE;
7196 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7197 * that will cause gcc to omit the function epilog, causing problems when
7198 * the JIT tries to walk the stack, since the return address on the stack
7199 * will point into the next function in the executable, not this one.
7201 eh_callbacks.mono_raise_exception (ex);
7205 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7207 MONO_REQ_GC_UNSAFE_MODE;
7209 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7213 * mono_wait_handle_new:
7214 * @domain: Domain where the object will be created
7215 * @handle: Handle for the wait handle
7216 * @error: set on error.
7218 * Returns: A new MonoWaitHandle created in the given domain for the
7219 * given handle. On failure returns NULL and sets @rror.
7222 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7224 MONO_REQ_GC_UNSAFE_MODE;
7226 MonoWaitHandle *res;
7227 gpointer params [1];
7228 static MonoMethod *handle_set;
7230 mono_error_init (error);
7231 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7232 return_val_if_nok (error, NULL);
7234 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7236 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7238 params [0] = &handle;
7240 mono_runtime_invoke_checked (handle_set, res, params, error);
7245 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7247 MONO_REQ_GC_UNSAFE_MODE;
7249 static MonoClassField *f_safe_handle = NULL;
7252 if (!f_safe_handle) {
7253 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7254 g_assert (f_safe_handle);
7257 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7263 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7265 MONO_REQ_GC_UNSAFE_MODE;
7267 RuntimeInvokeFunction runtime_invoke;
7269 mono_error_init (error);
7271 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7272 MonoMethod *method = mono_get_context_capture_method ();
7273 MonoMethod *wrapper;
7276 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7277 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7278 return_val_if_nok (error, NULL);
7279 domain->capture_context_method = mono_compile_method_checked (method, error);
7280 return_val_if_nok (error, NULL);
7283 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7285 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7288 * mono_async_result_new:
7289 * @domain:domain where the object will be created.
7290 * @handle: wait handle.
7291 * @state: state to pass to AsyncResult
7292 * @data: C closure data.
7293 * @error: set on error.
7295 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7296 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7297 * On failure returns NULL and sets @error.
7301 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7303 MONO_REQ_GC_UNSAFE_MODE;
7305 mono_error_init (error);
7306 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7307 return_val_if_nok (error, NULL);
7308 MonoObject *context = mono_runtime_capture_context (domain, error);
7309 return_val_if_nok (error, NULL);
7310 /* we must capture the execution context from the original thread */
7312 MONO_OBJECT_SETREF (res, execution_context, context);
7313 /* note: result may be null if the flow is suppressed */
7316 res->data = (void **)data;
7317 MONO_OBJECT_SETREF (res, object_data, object_data);
7318 MONO_OBJECT_SETREF (res, async_state, state);
7319 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7320 return_val_if_nok (error, NULL);
7322 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7324 res->sync_completed = FALSE;
7325 res->completed = FALSE;
7331 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7333 MONO_REQ_GC_UNSAFE_MODE;
7340 g_assert (ares->async_delegate);
7342 ac = (MonoAsyncCall*) ares->object_data;
7344 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7345 if (mono_error_set_pending_exception (&error))
7348 gpointer wait_event = NULL;
7350 ac->msg->exc = NULL;
7351 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7352 if (mono_error_set_pending_exception (&error))
7354 MONO_OBJECT_SETREF (ac, res, res);
7356 mono_monitor_enter ((MonoObject*) ares);
7357 ares->completed = 1;
7359 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7360 mono_monitor_exit ((MonoObject*) ares);
7362 if (wait_event != NULL)
7363 SetEvent (wait_event);
7365 if (ac->cb_method) {
7366 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7367 if (mono_error_set_pending_exception (&error))
7376 mono_message_init (MonoDomain *domain,
7377 MonoMethodMessage *this_obj,
7378 MonoReflectionMethod *method,
7379 MonoArray *out_args,
7382 MONO_REQ_GC_UNSAFE_MODE;
7384 static MonoClass *object_array_klass;
7385 static MonoClass *byte_array_klass;
7386 static MonoClass *string_array_klass;
7387 mono_error_init (error);
7388 MonoMethodSignature *sig = mono_method_signature (method->method);
7395 if (!object_array_klass) {
7398 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7400 byte_array_klass = klass;
7402 klass = mono_array_class_get (mono_defaults.string_class, 1);
7404 string_array_klass = klass;
7406 klass = mono_array_class_get (mono_defaults.object_class, 1);
7409 mono_atomic_store_release (&object_array_klass, klass);
7412 MONO_OBJECT_SETREF (this_obj, method, method);
7414 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, error);
7415 return_val_if_nok (error, FALSE);
7417 MONO_OBJECT_SETREF (this_obj, args, arr);
7419 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, error);
7420 return_val_if_nok (error, FALSE);
7422 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7424 this_obj->async_result = NULL;
7425 this_obj->call_type = CallType_Sync;
7427 names = g_new (char *, sig->param_count);
7428 mono_method_get_param_names (method->method, (const char **) names);
7430 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, error);
7434 MONO_OBJECT_SETREF (this_obj, names, arr);
7436 for (i = 0; i < sig->param_count; i++) {
7437 name = mono_string_new_checked (domain, names [i], error);
7440 mono_array_setref (this_obj->names, i, name);
7444 for (i = 0, j = 0; i < sig->param_count; i++) {
7445 if (sig->params [i]->byref) {
7447 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7448 mono_array_setref (this_obj->args, i, arg);
7452 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7456 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7459 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7468 #ifndef DISABLE_REMOTING
7470 * mono_remoting_invoke:
7471 * @real_proxy: pointer to a RealProxy object
7472 * @msg: The MonoMethodMessage to execute
7473 * @exc: used to store exceptions
7474 * @out_args: used to store output arguments
7476 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7477 * IMessage interface and it is not trivial to extract results from there. So
7478 * we call an helper method PrivateInvoke instead of calling
7479 * RealProxy::Invoke() directly.
7481 * Returns: the result object.
7484 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7486 MONO_REQ_GC_UNSAFE_MODE;
7489 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7494 mono_error_init (error);
7496 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7499 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7501 mono_error_set_not_supported (error, "Linked away.");
7504 real_proxy->vtable->domain->private_invoke_method = im;
7507 pa [0] = real_proxy;
7512 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7513 return_val_if_nok (error, NULL);
7520 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7521 MonoObject **exc, MonoArray **out_args, MonoError *error)
7523 MONO_REQ_GC_UNSAFE_MODE;
7525 static MonoClass *object_array_klass;
7526 mono_error_init (error);
7530 MonoMethodSignature *sig;
7532 int i, j, outarg_count = 0;
7534 #ifndef DISABLE_REMOTING
7535 if (target && mono_object_is_transparent_proxy (target)) {
7536 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7537 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7538 target = tp->rp->unwrapped_server;
7540 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7545 domain = mono_domain_get ();
7546 method = msg->method->method;
7547 sig = mono_method_signature (method);
7549 for (i = 0; i < sig->param_count; i++) {
7550 if (sig->params [i]->byref)
7554 if (!object_array_klass) {
7557 klass = mono_array_class_get (mono_defaults.object_class, 1);
7560 mono_memory_barrier ();
7561 object_array_klass = klass;
7564 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7565 return_val_if_nok (error, NULL);
7567 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7570 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7571 return_val_if_nok (error, NULL);
7573 for (i = 0, j = 0; i < sig->param_count; i++) {
7574 if (sig->params [i]->byref) {
7576 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7577 mono_array_setref (*out_args, j, arg);
7586 * prepare_to_string_method:
7588 * @target: Set to @obj or unboxed value if a valuetype
7590 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7593 prepare_to_string_method (MonoObject *obj, void **target)
7595 MONO_REQ_GC_UNSAFE_MODE;
7597 static MonoMethod *to_string = NULL;
7605 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7607 method = mono_object_get_virtual_method (obj, to_string);
7609 // Unbox value type if needed
7610 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7611 *target = mono_object_unbox (obj);
7617 * mono_object_to_string:
7619 * @exc: Any exception thrown by ToString (). May be NULL.
7621 * Returns: the result of calling ToString () on an object.
7624 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7627 MonoString *s = NULL;
7629 MonoMethod *method = prepare_to_string_method (obj, &target);
7631 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7632 if (*exc == NULL && !mono_error_ok (&error))
7633 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7635 mono_error_cleanup (&error);
7637 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7638 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7645 * mono_object_to_string_checked:
7647 * @error: Set on error.
7649 * Returns: the result of calling ToString () on an object. If the
7650 * method cannot be invoked or if it raises an exception, sets @error
7654 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7656 mono_error_init (error);
7658 MonoMethod *method = prepare_to_string_method (obj, &target);
7659 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7663 * mono_object_try_to_string:
7665 * @exc: Any exception thrown by ToString (). Must not be NULL.
7666 * @error: Set if method cannot be invoked.
7668 * Returns: the result of calling ToString () on an object. If the
7669 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7673 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7676 mono_error_init (error);
7678 MonoMethod *method = prepare_to_string_method (obj, &target);
7679 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7685 * mono_print_unhandled_exception:
7686 * @exc: The exception
7688 * Prints the unhandled exception.
7691 mono_print_unhandled_exception (MonoObject *exc)
7693 MONO_REQ_GC_UNSAFE_MODE;
7696 char *message = (char*)"";
7697 gboolean free_message = FALSE;
7700 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7701 message = g_strdup ("OutOfMemoryException");
7702 free_message = TRUE;
7703 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7704 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7705 free_message = TRUE;
7708 if (((MonoException*)exc)->native_trace_ips) {
7709 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7710 free_message = TRUE;
7712 MonoObject *other_exc = NULL;
7713 str = mono_object_try_to_string (exc, &other_exc, &error);
7714 if (other_exc == NULL && !is_ok (&error))
7715 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7717 mono_error_cleanup (&error);
7719 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7720 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7722 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7723 original_backtrace, nested_backtrace);
7725 g_free (original_backtrace);
7726 g_free (nested_backtrace);
7727 free_message = TRUE;
7729 message = mono_string_to_utf8_checked (str, &error);
7730 if (!mono_error_ok (&error)) {
7731 mono_error_cleanup (&error);
7732 message = (char *) "";
7734 free_message = TRUE;
7741 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7742 * exc->vtable->klass->name, message);
7744 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7751 * mono_delegate_ctor_with_method:
7752 * @this: pointer to an uninitialized delegate object
7753 * @target: target object
7754 * @addr: pointer to native code
7756 * @error: set on error.
7758 * Initialize a delegate and sets a specific method, not the one
7759 * associated with addr. This is useful when sharing generic code.
7760 * In that case addr will most probably not be associated with the
7761 * correct instantiation of the method.
7762 * On failure returns FALSE and sets @error.
7765 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7767 MONO_REQ_GC_UNSAFE_MODE;
7769 mono_error_init (error);
7770 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7772 g_assert (this_obj);
7775 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7778 delegate->method = method;
7780 mono_stats.delegate_creations++;
7782 #ifndef DISABLE_REMOTING
7783 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7785 method = mono_marshal_get_remoting_invoke (method);
7786 delegate->method_ptr = mono_compile_method_checked (method, error);
7787 return_val_if_nok (error, FALSE);
7788 MONO_OBJECT_SETREF (delegate, target, target);
7792 delegate->method_ptr = addr;
7793 MONO_OBJECT_SETREF (delegate, target, target);
7796 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7797 if (callbacks.init_delegate)
7798 callbacks.init_delegate (delegate);
7803 * mono_delegate_ctor:
7804 * @this: pointer to an uninitialized delegate object
7805 * @target: target object
7806 * @addr: pointer to native code
7807 * @error: set on error.
7809 * This is used to initialize a delegate.
7810 * On failure returns FALSE and sets @error.
7813 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7815 MONO_REQ_GC_UNSAFE_MODE;
7817 mono_error_init (error);
7818 MonoDomain *domain = mono_domain_get ();
7820 MonoMethod *method = NULL;
7824 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7826 if (!ji && domain != mono_get_root_domain ())
7827 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7829 method = mono_jit_info_get_method (ji);
7830 g_assert (!method->klass->generic_container);
7833 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7837 * mono_method_call_message_new:
7838 * @method: method to encapsulate
7839 * @params: parameters to the method
7840 * @invoke: optional, delegate invoke.
7841 * @cb: async callback delegate.
7842 * @state: state passed to the async callback.
7843 * @error: set on error.
7845 * Translates arguments pointers into a MonoMethodMessage.
7846 * On failure returns NULL and sets @error.
7849 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7850 MonoDelegate **cb, MonoObject **state, MonoError *error)
7852 MONO_REQ_GC_UNSAFE_MODE;
7854 mono_error_init (error);
7856 MonoDomain *domain = mono_domain_get ();
7857 MonoMethodSignature *sig = mono_method_signature (method);
7858 MonoMethodMessage *msg;
7861 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
7862 return_val_if_nok (error, NULL);
7865 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
7866 return_val_if_nok (error, NULL);
7867 mono_message_init (domain, msg, rm, NULL, error);
7868 return_val_if_nok (error, NULL);
7869 count = sig->param_count - 2;
7871 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
7872 return_val_if_nok (error, NULL);
7873 mono_message_init (domain, msg, rm, NULL, error);
7874 return_val_if_nok (error, NULL);
7875 count = sig->param_count;
7878 for (i = 0; i < count; i++) {
7883 if (sig->params [i]->byref)
7884 vpos = *((gpointer *)params [i]);
7888 klass = mono_class_from_mono_type (sig->params [i]);
7890 if (klass->valuetype) {
7891 arg = mono_value_box_checked (domain, klass, vpos, error);
7892 return_val_if_nok (error, NULL);
7894 arg = *((MonoObject **)vpos);
7896 mono_array_setref (msg->args, i, arg);
7899 if (cb != NULL && state != NULL) {
7900 *cb = *((MonoDelegate **)params [i]);
7902 *state = *((MonoObject **)params [i]);
7909 * mono_method_return_message_restore:
7911 * Restore results from message based processing back to arguments pointers
7914 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
7916 MONO_REQ_GC_UNSAFE_MODE;
7918 mono_error_init (error);
7920 MonoMethodSignature *sig = mono_method_signature (method);
7921 int i, j, type, size, out_len;
7923 if (out_args == NULL)
7925 out_len = mono_array_length (out_args);
7929 for (i = 0, j = 0; i < sig->param_count; i++) {
7930 MonoType *pt = sig->params [i];
7935 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
7939 arg = (char *)mono_array_get (out_args, gpointer, j);
7942 g_assert (type != MONO_TYPE_VOID);
7944 if (MONO_TYPE_IS_REFERENCE (pt)) {
7945 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7948 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7949 size = mono_class_value_size (klass, NULL);
7950 if (klass->has_references)
7951 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7953 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7955 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7956 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7965 #ifndef DISABLE_REMOTING
7968 * mono_load_remote_field:
7969 * @this: pointer to an object
7970 * @klass: klass of the object containing @field
7971 * @field: the field to load
7972 * @res: a storage to store the result
7974 * This method is called by the runtime on attempts to load fields of
7975 * transparent proxy objects. @this points to such TP, @klass is the class of
7976 * the object containing @field. @res is a storage location which can be
7977 * used to store the result.
7979 * Returns: an address pointing to the value of field.
7982 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7985 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
7986 mono_error_cleanup (&error);
7991 * mono_load_remote_field_checked:
7992 * @this: pointer to an object
7993 * @klass: klass of the object containing @field
7994 * @field: the field to load
7995 * @res: a storage to store the result
7996 * @error: set on error
7998 * This method is called by the runtime on attempts to load fields of
7999 * transparent proxy objects. @this points to such TP, @klass is the class of
8000 * the object containing @field. @res is a storage location which can be
8001 * used to store the result.
8003 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8006 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8008 MONO_REQ_GC_UNSAFE_MODE;
8010 static MonoMethod *getter = NULL;
8012 mono_error_init (error);
8014 MonoDomain *domain = mono_domain_get ();
8015 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8016 MonoClass *field_class;
8017 MonoMethodMessage *msg;
8018 MonoArray *out_args;
8022 g_assert (mono_object_is_transparent_proxy (this_obj));
8023 g_assert (res != NULL);
8025 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8026 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8031 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8033 mono_error_set_not_supported (error, "Linked away.");
8038 field_class = mono_class_from_mono_type (field->type);
8040 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8041 return_val_if_nok (error, NULL);
8042 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8043 return_val_if_nok (error, NULL);
8044 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8045 return_val_if_nok (error, NULL);
8046 mono_message_init (domain, msg, rm, out_args, error);
8047 return_val_if_nok (error, NULL);
8049 full_name = mono_type_get_full_name (klass);
8050 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8051 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8054 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8055 return_val_if_nok (error, NULL);
8058 mono_error_set_exception_instance (error, (MonoException *)exc);
8062 if (mono_array_length (out_args) == 0)
8065 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8067 if (field_class->valuetype) {
8068 return ((char *)*res) + sizeof (MonoObject);
8074 * mono_load_remote_field_new:
8079 * Missing documentation.
8082 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8086 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8087 mono_error_cleanup (&error);
8092 * mono_load_remote_field_new_icall:
8093 * @this: pointer to an object
8094 * @klass: klass of the object containing @field
8095 * @field: the field to load
8097 * This method is called by the runtime on attempts to load fields of
8098 * transparent proxy objects. @this points to such TP, @klass is the class of
8099 * the object containing @field.
8101 * Returns: a freshly allocated object containing the value of the
8102 * field. On failure returns NULL and throws an exception.
8105 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8108 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8109 mono_error_set_pending_exception (&error);
8114 * mono_load_remote_field_new_checked:
8115 * @this: pointer to an object
8116 * @klass: klass of the object containing @field
8117 * @field: the field to load
8118 * @error: set on error.
8120 * This method is called by the runtime on attempts to load fields of
8121 * transparent proxy objects. @this points to such TP, @klass is the class of
8122 * the object containing @field.
8124 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8127 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8129 MONO_REQ_GC_UNSAFE_MODE;
8131 mono_error_init (error);
8133 static MonoMethod *getter = NULL;
8134 MonoDomain *domain = mono_domain_get ();
8135 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8136 MonoClass *field_class;
8137 MonoMethodMessage *msg;
8138 MonoArray *out_args;
8139 MonoObject *exc, *res;
8142 g_assert (mono_object_is_transparent_proxy (this_obj));
8144 field_class = mono_class_from_mono_type (field->type);
8146 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8148 if (field_class->valuetype) {
8149 res = mono_object_new_checked (domain, field_class, error);
8150 return_val_if_nok (error, NULL);
8151 val = ((gchar *) res) + sizeof (MonoObject);
8155 mono_field_get_value (tp->rp->unwrapped_server, field, val);
8160 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8162 mono_error_set_not_supported (error, "Linked away.");
8167 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8168 return_val_if_nok (error, NULL);
8169 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8170 return_val_if_nok (error, NULL);
8172 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8173 return_val_if_nok (error, NULL);
8174 mono_message_init (domain, msg, rm, out_args, error);
8175 return_val_if_nok (error, NULL);
8177 full_name = mono_type_get_full_name (klass);
8178 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8179 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8182 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8183 return_val_if_nok (error, NULL);
8186 mono_error_set_exception_instance (error, (MonoException *)exc);
8190 if (mono_array_length (out_args) == 0)
8193 res = mono_array_get (out_args, MonoObject *, 0);
8199 * mono_store_remote_field:
8200 * @this_obj: pointer to an object
8201 * @klass: klass of the object containing @field
8202 * @field: the field to load
8203 * @val: the value/object to store
8205 * This method is called by the runtime on attempts to store fields of
8206 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8207 * the object containing @field. @val is the new value to store in @field.
8210 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8213 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8214 mono_error_cleanup (&error);
8218 * mono_store_remote_field_checked:
8219 * @this_obj: pointer to an object
8220 * @klass: klass of the object containing @field
8221 * @field: the field to load
8222 * @val: the value/object to store
8223 * @error: set on error
8225 * This method is called by the runtime on attempts to store fields of
8226 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8227 * the object containing @field. @val is the new value to store in @field.
8229 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8232 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8235 MONO_REQ_GC_UNSAFE_MODE;
8237 static MonoMethod *setter = NULL;
8239 MonoDomain *domain = mono_domain_get ();
8240 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8241 MonoClass *field_class;
8242 MonoMethodMessage *msg;
8243 MonoArray *out_args;
8248 mono_error_init (error);
8250 g_assert (mono_object_is_transparent_proxy (this_obj));
8252 field_class = mono_class_from_mono_type (field->type);
8254 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8255 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
8256 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
8261 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8263 mono_error_set_not_supported (error, "Linked away.");
8268 if (field_class->valuetype) {
8269 arg = mono_value_box_checked (domain, field_class, val, error);
8270 return_val_if_nok (error, FALSE);
8272 arg = *((MonoObject **)val);
8275 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8276 return_val_if_nok (error, FALSE);
8277 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8278 return_val_if_nok (error, FALSE);
8279 mono_message_init (domain, msg, rm, NULL, error);
8280 return_val_if_nok (error, FALSE);
8282 full_name = mono_type_get_full_name (klass);
8283 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8284 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8285 mono_array_setref (msg->args, 2, arg);
8288 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8289 return_val_if_nok (error, FALSE);
8292 mono_error_set_exception_instance (error, (MonoException *)exc);
8299 * mono_store_remote_field_new:
8305 * Missing documentation
8308 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8311 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8312 mono_error_cleanup (&error);
8316 * mono_store_remote_field_new_icall:
8322 * Missing documentation
8325 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8328 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8329 mono_error_set_pending_exception (&error);
8333 * mono_store_remote_field_new_checked:
8340 * Missing documentation
8343 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8345 MONO_REQ_GC_UNSAFE_MODE;
8347 static MonoMethod *setter = NULL;
8348 MonoDomain *domain = mono_domain_get ();
8349 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8350 MonoClass *field_class;
8351 MonoMethodMessage *msg;
8352 MonoArray *out_args;
8356 mono_error_init (error);
8358 g_assert (mono_object_is_transparent_proxy (this_obj));
8360 field_class = mono_class_from_mono_type (field->type);
8362 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8363 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8364 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8369 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8371 mono_error_set_not_supported (error, "Linked away.");
8376 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8377 return_val_if_nok (error, FALSE);
8378 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8379 return_val_if_nok (error, FALSE);
8380 mono_message_init (domain, msg, rm, NULL, error);
8381 return_val_if_nok (error, FALSE);
8383 full_name = mono_type_get_full_name (klass);
8384 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8385 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8386 mono_array_setref (msg->args, 2, arg);
8389 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8390 return_val_if_nok (error, FALSE);
8393 mono_error_set_exception_instance (error, (MonoException *)exc);
8401 * mono_create_ftnptr:
8403 * Given a function address, create a function descriptor for it.
8404 * This is only needed on some platforms.
8407 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8409 return callbacks.create_ftnptr (domain, addr);
8413 * mono_get_addr_from_ftnptr:
8415 * Given a pointer to a function descriptor, return the function address.
8416 * This is only needed on some platforms.
8419 mono_get_addr_from_ftnptr (gpointer descr)
8421 return callbacks.get_addr_from_ftnptr (descr);
8425 * mono_string_chars:
8428 * Returns a pointer to the UCS16 characters stored in the MonoString
8431 mono_string_chars (MonoString *s)
8433 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8439 * mono_string_length:
8442 * Returns the lenght in characters of the string
8445 mono_string_length (MonoString *s)
8447 MONO_REQ_GC_UNSAFE_MODE;
8453 * mono_array_length:
8454 * @array: a MonoArray*
8456 * Returns the total number of elements in the array. This works for
8457 * both vectors and multidimensional arrays.
8460 mono_array_length (MonoArray *array)
8462 MONO_REQ_GC_UNSAFE_MODE;
8464 return array->max_length;
8468 * mono_array_addr_with_size:
8469 * @array: a MonoArray*
8470 * @size: size of the array elements
8471 * @idx: index into the array
8473 * Use this function to obtain the address for the @idx item on the
8474 * @array containing elements of size @size.
8476 * This method performs no bounds checking or type checking.
8478 * Returns the address of the @idx element in the array.
8481 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8483 MONO_REQ_GC_UNSAFE_MODE;
8485 return ((char*)(array)->vector) + size * idx;
8490 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8492 MonoDomain *domain = mono_domain_get ();
8496 mono_error_init (error);
8500 len = g_list_length (list);
8501 res = mono_array_new_checked (domain, eclass, len, error);
8502 return_val_if_nok (error, NULL);
8504 for (i = 0; list; list = list->next, i++)
8505 mono_array_set (res, gpointer, i, list->data);
8512 * The following section is purely to declare prototypes and
8513 * document the API, as these C files are processed by our
8519 * @array: array to alter
8520 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8521 * @index: index into the array
8522 * @value: value to set
8524 * Value Type version: This sets the @index's element of the @array
8525 * with elements of size sizeof(type) to the provided @value.
8527 * This macro does not attempt to perform type checking or bounds checking.
8529 * Use this to set value types in a `MonoArray`.
8531 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8536 * mono_array_setref:
8537 * @array: array to alter
8538 * @index: index into the array
8539 * @value: value to set
8541 * Reference Type version: This sets the @index's element of the
8542 * @array with elements of size sizeof(type) to the provided @value.
8544 * This macro does not attempt to perform type checking or bounds checking.
8546 * Use this to reference types in a `MonoArray`.
8548 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8554 * @array: array on which to operate on
8555 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8556 * @index: index into the array
8558 * Use this macro to retrieve the @index element of an @array and
8559 * extract the value assuming that the elements of the array match
8560 * the provided type value.
8562 * This method can be used with both arrays holding value types and
8563 * reference types. For reference types, the @type parameter should
8564 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8566 * This macro does not attempt to perform type checking or bounds checking.
8568 * Returns: The element at the @index position in the @array.
8570 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)