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 <mono/utils/mono-threads-coop.h>
51 #include "cominterop.h"
54 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
57 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
60 free_main_args (void);
63 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
65 /* Class lazy loading functions */
66 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
67 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
68 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
69 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
70 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
73 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
74 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
75 static mono_mutex_t ldstr_section;
78 * mono_runtime_object_init:
79 * @this_obj: the object to initialize
81 * This function calls the zero-argument constructor (which must
82 * exist) for the given object.
85 mono_runtime_object_init (MonoObject *this_obj)
88 mono_runtime_object_init_checked (this_obj, &error);
89 mono_error_assert_ok (&error);
93 * mono_runtime_object_init_checked:
94 * @this_obj: the object to initialize
95 * @error: set on error.
97 * This function calls the zero-argument constructor (which must
98 * exist) for the given object and returns TRUE on success, or FALSE
99 * on error and sets @error.
102 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
104 MONO_REQ_GC_UNSAFE_MODE;
106 MonoMethod *method = NULL;
107 MonoClass *klass = this_obj->vtable->klass;
109 mono_error_init (error);
110 method = mono_class_get_method_from_name (klass, ".ctor", 0);
112 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
114 if (method->klass->valuetype)
115 this_obj = (MonoObject *)mono_object_unbox (this_obj);
117 mono_runtime_invoke_checked (method, this_obj, NULL, error);
118 return is_ok (error);
121 /* The pseudo algorithm for type initialization from the spec
122 Note it doesn't say anything about domains - only threads.
124 2. If the type is initialized you are done.
125 2.1. If the type is not yet initialized, try to take an
127 2.2. If successful, record this thread as responsible for
128 initializing the type and proceed to step 2.3.
129 2.2.1. If not, see whether this thread or any thread
130 waiting for this thread to complete already holds the lock.
131 2.2.2. If so, return since blocking would create a deadlock. This thread
132 will now see an incompletely initialized state for the type,
133 but no deadlock will arise.
134 2.2.3 If not, block until the type is initialized then return.
135 2.3 Initialize the parent type and then all interfaces implemented
137 2.4 Execute the type initialization code for this type.
138 2.5 Mark the type as initialized, release the initialization lock,
139 awaken any threads waiting for this type to be initialized,
146 MonoNativeThreadId initializing_tid;
147 guint32 waiting_count;
149 MonoCoopMutex initialization_section;
150 } TypeInitializationLock;
152 /* for locking access to type_initialization_hash and blocked_thread_hash */
153 static MonoCoopMutex type_initialization_section;
156 mono_type_initialization_lock (void)
158 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
159 mono_coop_mutex_lock (&type_initialization_section);
163 mono_type_initialization_unlock (void)
165 mono_coop_mutex_unlock (&type_initialization_section);
169 mono_type_init_lock (TypeInitializationLock *lock)
171 MONO_REQ_GC_NEUTRAL_MODE;
173 mono_coop_mutex_lock (&lock->initialization_section);
177 mono_type_init_unlock (TypeInitializationLock *lock)
179 mono_coop_mutex_unlock (&lock->initialization_section);
182 /* from vtable to lock */
183 static GHashTable *type_initialization_hash;
185 /* from thread id to thread id being waited on */
186 static GHashTable *blocked_thread_hash;
189 static MonoThread *main_thread;
191 /* Functions supplied by the runtime */
192 static MonoRuntimeCallbacks callbacks;
195 * mono_thread_set_main:
196 * @thread: thread to set as the main thread
198 * This function can be used to instruct the runtime to treat @thread
199 * as the main thread, ie, the thread that would normally execute the Main()
200 * method. This basically means that at the end of @thread, the runtime will
201 * wait for the existing foreground threads to quit and other such details.
204 mono_thread_set_main (MonoThread *thread)
206 MONO_REQ_GC_UNSAFE_MODE;
208 static gboolean registered = FALSE;
211 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
215 main_thread = thread;
219 mono_thread_get_main (void)
221 MONO_REQ_GC_UNSAFE_MODE;
227 mono_type_initialization_init (void)
229 mono_coop_mutex_init_recursive (&type_initialization_section);
230 type_initialization_hash = g_hash_table_new (NULL, NULL);
231 blocked_thread_hash = g_hash_table_new (NULL, NULL);
232 mono_os_mutex_init_recursive (&ldstr_section);
236 mono_type_initialization_cleanup (void)
239 /* This is causing race conditions with
240 * mono_release_type_locks
242 mono_coop_mutex_destroy (&type_initialization_section);
243 g_hash_table_destroy (type_initialization_hash);
244 type_initialization_hash = NULL;
246 mono_os_mutex_destroy (&ldstr_section);
247 g_hash_table_destroy (blocked_thread_hash);
248 blocked_thread_hash = NULL;
254 * get_type_init_exception_for_vtable:
256 * Return the stored type initialization exception for VTABLE.
258 static MonoException*
259 get_type_init_exception_for_vtable (MonoVTable *vtable)
261 MONO_REQ_GC_UNSAFE_MODE;
264 MonoDomain *domain = vtable->domain;
265 MonoClass *klass = vtable->klass;
269 if (!vtable->init_failed)
270 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
273 * If the initializing thread was rudely aborted, the exception is not stored
277 mono_domain_lock (domain);
278 if (domain->type_init_exception_hash)
279 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
280 mono_domain_unlock (domain);
283 if (klass->name_space && *klass->name_space)
284 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
286 full_name = g_strdup (klass->name);
287 ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
289 return_val_if_nok (&error, NULL);
296 * mono_runtime_class_init:
297 * @vtable: vtable that needs to be initialized
299 * This routine calls the class constructor for @vtable.
302 mono_runtime_class_init (MonoVTable *vtable)
304 MONO_REQ_GC_UNSAFE_MODE;
307 mono_runtime_class_init_full (vtable, &error);
308 mono_error_assert_ok (&error);
312 * mono_runtime_class_init_full:
313 * @vtable that neeeds to be initialized
314 * @error set on error
316 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
320 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
322 MONO_REQ_GC_UNSAFE_MODE;
324 MonoMethod *method = NULL;
327 MonoDomain *domain = vtable->domain;
328 TypeInitializationLock *lock;
329 MonoNativeThreadId tid;
330 int do_initialization = 0;
331 MonoDomain *last_domain = NULL;
333 mono_error_init (error);
335 if (vtable->initialized)
338 klass = vtable->klass;
340 if (!klass->image->checked_module_cctor) {
341 mono_image_check_for_module_cctor (klass->image);
342 if (klass->image->has_module_cctor) {
343 MonoClass *module_klass;
344 MonoVTable *module_vtable;
346 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
351 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
354 if (!mono_runtime_class_init_full (module_vtable, error))
358 method = mono_class_get_cctor (klass);
360 vtable->initialized = 1;
364 tid = mono_native_thread_id_get ();
366 mono_type_initialization_lock ();
367 /* double check... */
368 if (vtable->initialized) {
369 mono_type_initialization_unlock ();
372 if (vtable->init_failed) {
373 mono_type_initialization_unlock ();
375 /* The type initialization already failed once, rethrow the same exception */
376 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
379 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
381 /* This thread will get to do the initialization */
382 if (mono_domain_get () != domain) {
383 /* Transfer into the target domain */
384 last_domain = mono_domain_get ();
385 if (!mono_domain_set (domain, FALSE)) {
386 vtable->initialized = 1;
387 mono_type_initialization_unlock ();
388 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
392 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
393 mono_coop_mutex_init_recursive (&lock->initialization_section);
394 lock->initializing_tid = tid;
395 lock->waiting_count = 1;
397 /* grab the vtable lock while this thread still owns type_initialization_section */
398 /* This is why type_initialization_lock needs to enter blocking mode */
399 mono_type_init_lock (lock);
400 g_hash_table_insert (type_initialization_hash, vtable, lock);
401 do_initialization = 1;
404 TypeInitializationLock *pending_lock;
406 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
407 mono_type_initialization_unlock ();
410 /* see if the thread doing the initialization is already blocked on this thread */
411 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
412 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
413 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
414 if (!pending_lock->done) {
415 mono_type_initialization_unlock ();
418 /* the thread doing the initialization is blocked on this thread,
419 but on a lock that has already been freed. It just hasn't got
424 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
426 ++lock->waiting_count;
427 /* record the fact that we are waiting on the initializing thread */
428 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
430 mono_type_initialization_unlock ();
432 if (do_initialization) {
433 MonoException *exc = NULL;
434 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
435 if (exc != NULL && mono_error_ok (error)) {
436 mono_error_set_exception_instance (error, exc);
439 /* If the initialization failed, mark the class as unusable. */
440 /* Avoid infinite loops */
441 if (!(mono_error_ok(error) ||
442 (klass->image == mono_defaults.corlib &&
443 !strcmp (klass->name_space, "System") &&
444 !strcmp (klass->name, "TypeInitializationException")))) {
445 vtable->init_failed = 1;
447 if (klass->name_space && *klass->name_space)
448 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
450 full_name = g_strdup (klass->name);
452 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
454 return_val_if_nok (error, FALSE);
456 mono_error_set_exception_instance (error, exc_to_throw);
458 MonoException *exc_to_store = mono_error_convert_to_exception (error);
459 /* What we really want to do here is clone the error object and store one copy in the
460 * domain's exception hash and use the other one to error out here. */
461 mono_error_init (error);
462 mono_error_set_exception_instance (error, exc_to_store);
464 * Store the exception object so it could be thrown on subsequent
467 mono_domain_lock (domain);
468 if (!domain->type_init_exception_hash)
469 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");
470 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
471 mono_domain_unlock (domain);
475 mono_domain_set (last_domain, TRUE);
477 mono_type_init_unlock (lock);
479 /* this just blocks until the initializing thread is done */
480 mono_type_init_lock (lock);
481 mono_type_init_unlock (lock);
484 mono_type_initialization_lock ();
485 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
486 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
487 --lock->waiting_count;
488 if (lock->waiting_count == 0) {
489 mono_coop_mutex_destroy (&lock->initialization_section);
490 g_hash_table_remove (type_initialization_hash, vtable);
493 mono_memory_barrier ();
494 if (!vtable->init_failed)
495 vtable->initialized = 1;
496 mono_type_initialization_unlock ();
498 if (vtable->init_failed) {
499 /* Either we were the initializing thread or we waited for the initialization */
500 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
507 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
509 MONO_REQ_GC_NEUTRAL_MODE;
511 MonoVTable *vtable = (MonoVTable*)key;
513 TypeInitializationLock *lock = (TypeInitializationLock*) value;
514 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
517 * Have to set this since it cannot be set by the normal code in
518 * mono_runtime_class_init (). In this case, the exception object is not stored,
519 * and get_type_init_exception_for_class () needs to be aware of this.
521 vtable->init_failed = 1;
522 mono_type_init_unlock (lock);
523 --lock->waiting_count;
524 if (lock->waiting_count == 0) {
525 mono_coop_mutex_destroy (&lock->initialization_section);
534 mono_release_type_locks (MonoInternalThread *thread)
536 MONO_REQ_GC_UNSAFE_MODE;
538 mono_type_initialization_lock ();
539 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
540 mono_type_initialization_unlock ();
543 #ifndef DISABLE_REMOTING
546 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
548 g_error ("remoting not installed");
552 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
556 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
558 g_assert_not_reached ();
562 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
563 static MonoImtThunkBuilder imt_thunk_builder;
564 static gboolean always_build_imt_thunks;
566 #if (MONO_IMT_SIZE > 32)
567 #error "MONO_IMT_SIZE cannot be larger than 32"
571 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
573 memcpy (&callbacks, cbs, sizeof (*cbs));
576 MonoRuntimeCallbacks*
577 mono_get_runtime_callbacks (void)
582 #ifndef DISABLE_REMOTING
584 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
586 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
591 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
593 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
597 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
598 imt_thunk_builder = func;
602 mono_set_always_build_imt_thunks (gboolean value)
604 always_build_imt_thunks = value;
608 * mono_compile_method:
609 * @method: The method to compile.
611 * This JIT-compiles the method, and returns the pointer to the native code
615 mono_compile_method (MonoMethod *method)
618 gpointer result = mono_compile_method_checked (method, &error);
619 mono_error_cleanup (&error);
624 * mono_compile_method:
625 * @method: The method to compile.
626 * @error: set on error.
628 * This JIT-compiles the method, and returns the pointer to the native code
629 * produced. On failure returns NULL and sets @error.
632 mono_compile_method_checked (MonoMethod *method, MonoError *error)
636 MONO_REQ_GC_NEUTRAL_MODE
638 mono_error_init (error);
640 if (!callbacks.compile_method) {
641 g_error ("compile method called on uninitialized runtime");
644 res = callbacks.compile_method (method, error);
649 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
653 MONO_REQ_GC_NEUTRAL_MODE;
655 mono_error_init (error);
656 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
661 mono_runtime_create_delegate_trampoline (MonoClass *klass)
663 MONO_REQ_GC_NEUTRAL_MODE
665 return arch_create_delegate_trampoline (mono_domain_get (), klass);
668 static MonoFreeMethodFunc default_mono_free_method = NULL;
671 * mono_install_free_method:
672 * @func: pointer to the MonoFreeMethodFunc used to release a method
674 * This is an internal VM routine, it is used for the engines to
675 * register a handler to release the resources associated with a method.
677 * Methods are freed when no more references to the delegate that holds
681 mono_install_free_method (MonoFreeMethodFunc func)
683 default_mono_free_method = func;
687 * mono_runtime_free_method:
688 * @domain; domain where the method is hosted
689 * @method: method to release
691 * This routine is invoked to free the resources associated with
692 * a method that has been JIT compiled. This is used to discard
693 * methods that were used only temporarily (for example, used in marshalling)
697 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
699 MONO_REQ_GC_NEUTRAL_MODE
701 if (default_mono_free_method != NULL)
702 default_mono_free_method (domain, method);
704 mono_method_clear_object (domain, method);
706 mono_free_method (method);
710 * The vtables in the root appdomain are assumed to be reachable by other
711 * roots, and we don't use typed allocation in the other domains.
714 /* The sync block is no longer a GC pointer */
715 #define GC_HEADER_BITMAP (0)
717 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
720 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
722 MONO_REQ_GC_NEUTRAL_MODE;
724 MonoClassField *field;
730 max_size = mono_class_data_size (klass) / sizeof (gpointer);
732 max_size = klass->instance_size / sizeof (gpointer);
733 if (max_size > size) {
734 g_assert (offset <= 0);
735 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
740 /*An Ephemeron cannot be marked by sgen*/
741 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
743 memset (bitmap, 0, size / 8);
748 for (p = klass; p != NULL; p = p->parent) {
749 gpointer iter = NULL;
750 while ((field = mono_class_get_fields (p, &iter))) {
754 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
756 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
759 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
762 /* FIXME: should not happen, flag as type load error */
763 if (field->type->byref)
766 if (static_fields && field->offset == -1)
770 pos = field->offset / sizeof (gpointer);
773 type = mono_type_get_underlying_type (field->type);
774 switch (type->type) {
777 case MONO_TYPE_FNPTR:
779 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
784 if (klass->image != mono_defaults.corlib)
787 case MONO_TYPE_STRING:
788 case MONO_TYPE_SZARRAY:
789 case MONO_TYPE_CLASS:
790 case MONO_TYPE_OBJECT:
791 case MONO_TYPE_ARRAY:
792 g_assert ((field->offset % sizeof(gpointer)) == 0);
794 g_assert (pos < size || pos <= max_size);
795 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
796 *max_set = MAX (*max_set, pos);
798 case MONO_TYPE_GENERICINST:
799 if (!mono_type_generic_inst_is_valuetype (type)) {
800 g_assert ((field->offset % sizeof(gpointer)) == 0);
802 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
803 *max_set = MAX (*max_set, pos);
808 case MONO_TYPE_VALUETYPE: {
809 MonoClass *fclass = mono_class_from_mono_type (field->type);
810 if (fclass->has_references) {
811 /* remove the object header */
812 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
826 case MONO_TYPE_BOOLEAN:
830 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
841 * mono_class_compute_bitmap:
843 * Mono internal function to compute a bitmap of reference fields in a class.
846 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
848 MONO_REQ_GC_NEUTRAL_MODE;
850 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
855 * similar to the above, but sets the bits in the bitmap for any non-ref field
856 * and ignores static fields
859 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
861 MonoClassField *field;
866 max_size = class->instance_size / sizeof (gpointer);
867 if (max_size >= size) {
868 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
871 for (p = class; p != NULL; p = p->parent) {
872 gpointer iter = NULL;
873 while ((field = mono_class_get_fields (p, &iter))) {
876 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
878 /* FIXME: should not happen, flag as type load error */
879 if (field->type->byref)
882 pos = field->offset / sizeof (gpointer);
885 type = mono_type_get_underlying_type (field->type);
886 switch (type->type) {
887 #if SIZEOF_VOID_P == 8
891 case MONO_TYPE_FNPTR:
896 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
897 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
898 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
901 #if SIZEOF_VOID_P == 4
905 case MONO_TYPE_FNPTR:
910 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
911 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
912 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
918 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
919 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
920 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
923 case MONO_TYPE_BOOLEAN:
926 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
928 case MONO_TYPE_STRING:
929 case MONO_TYPE_SZARRAY:
930 case MONO_TYPE_CLASS:
931 case MONO_TYPE_OBJECT:
932 case MONO_TYPE_ARRAY:
934 case MONO_TYPE_GENERICINST:
935 if (!mono_type_generic_inst_is_valuetype (type)) {
940 case MONO_TYPE_VALUETYPE: {
941 MonoClass *fclass = mono_class_from_mono_type (field->type);
942 /* remove the object header */
943 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
947 g_assert_not_reached ();
956 * mono_class_insecure_overlapping:
957 * check if a class with explicit layout has references and non-references
958 * fields overlapping.
960 * Returns: TRUE if it is insecure to load the type.
963 mono_class_insecure_overlapping (MonoClass *klass)
967 gsize default_bitmap [4] = {0};
969 gsize default_nrbitmap [4] = {0};
970 int i, insecure = FALSE;
973 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
974 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
976 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
977 int idx = i % (sizeof (bitmap [0]) * 8);
978 if (bitmap [idx] & nrbitmap [idx]) {
983 if (bitmap != default_bitmap)
985 if (nrbitmap != default_nrbitmap)
988 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
996 ves_icall_string_alloc (int length)
999 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1000 mono_error_set_pending_exception (&error);
1006 mono_class_compute_gc_descriptor (MonoClass *klass)
1008 MONO_REQ_GC_NEUTRAL_MODE;
1012 gsize default_bitmap [4] = {0};
1013 static gboolean gcj_inited = FALSE;
1016 mono_loader_lock ();
1018 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1019 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1022 mono_loader_unlock ();
1026 mono_class_init (klass);
1028 if (klass->gc_descr_inited)
1031 klass->gc_descr_inited = TRUE;
1032 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1034 bitmap = default_bitmap;
1035 if (klass == mono_defaults.string_class) {
1036 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1037 } else if (klass->rank) {
1038 mono_class_compute_gc_descriptor (klass->element_class);
1039 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1041 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1042 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1043 class->name_space, class->name);*/
1045 /* remove the object header */
1046 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1047 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));
1048 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1049 class->name_space, class->name);*/
1050 if (bitmap != default_bitmap)
1054 /*static int count = 0;
1057 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1058 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1060 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1061 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1063 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1064 if (bitmap != default_bitmap)
1070 * field_is_special_static:
1071 * @fklass: The MonoClass to look up.
1072 * @field: The MonoClassField describing the field.
1074 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1075 * SPECIAL_STATIC_NONE otherwise.
1078 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1080 MONO_REQ_GC_NEUTRAL_MODE;
1083 MonoCustomAttrInfo *ainfo;
1085 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1086 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1089 for (i = 0; i < ainfo->num_attrs; ++i) {
1090 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1091 if (klass->image == mono_defaults.corlib) {
1092 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1093 mono_custom_attrs_free (ainfo);
1094 return SPECIAL_STATIC_THREAD;
1096 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1097 mono_custom_attrs_free (ainfo);
1098 return SPECIAL_STATIC_CONTEXT;
1102 mono_custom_attrs_free (ainfo);
1103 return SPECIAL_STATIC_NONE;
1106 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1107 #define mix(a,b,c) { \
1108 a -= c; a ^= rot(c, 4); c += b; \
1109 b -= a; b ^= rot(a, 6); a += c; \
1110 c -= b; c ^= rot(b, 8); b += a; \
1111 a -= c; a ^= rot(c,16); c += b; \
1112 b -= a; b ^= rot(a,19); a += c; \
1113 c -= b; c ^= rot(b, 4); b += a; \
1115 #define final(a,b,c) { \
1116 c ^= b; c -= rot(b,14); \
1117 a ^= c; a -= rot(c,11); \
1118 b ^= a; b -= rot(a,25); \
1119 c ^= b; c -= rot(b,16); \
1120 a ^= c; a -= rot(c,4); \
1121 b ^= a; b -= rot(a,14); \
1122 c ^= b; c -= rot(b,24); \
1126 * mono_method_get_imt_slot:
1128 * The IMT slot is embedded into AOTed code, so this must return the same value
1129 * for the same method across all executions. This means:
1130 * - pointers shouldn't be used as hash values.
1131 * - mono_metadata_str_hash () should be used for hashing strings.
1134 mono_method_get_imt_slot (MonoMethod *method)
1136 MONO_REQ_GC_NEUTRAL_MODE;
1138 MonoMethodSignature *sig;
1140 guint32 *hashes_start, *hashes;
1144 /* This can be used to stress tests the collision code */
1148 * We do this to simplify generic sharing. It will hurt
1149 * performance in cases where a class implements two different
1150 * instantiations of the same generic interface.
1151 * The code in build_imt_slots () depends on this.
1153 if (method->is_inflated)
1154 method = ((MonoMethodInflated*)method)->declaring;
1156 sig = mono_method_signature (method);
1157 hashes_count = sig->param_count + 4;
1158 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1159 hashes = hashes_start;
1161 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1162 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1163 method->klass->name_space, method->klass->name, method->name);
1166 /* Initialize hashes */
1167 hashes [0] = mono_metadata_str_hash (method->klass->name);
1168 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1169 hashes [2] = mono_metadata_str_hash (method->name);
1170 hashes [3] = mono_metadata_type_hash (sig->ret);
1171 for (i = 0; i < sig->param_count; i++) {
1172 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1175 /* Setup internal state */
1176 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1178 /* Handle most of the hashes */
1179 while (hashes_count > 3) {
1188 /* Handle the last 3 hashes (all the case statements fall through) */
1189 switch (hashes_count) {
1190 case 3 : c += hashes [2];
1191 case 2 : b += hashes [1];
1192 case 1 : a += hashes [0];
1194 case 0: /* nothing left to add */
1198 free (hashes_start);
1199 /* Report the result */
1200 return c % MONO_IMT_SIZE;
1209 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1210 MONO_REQ_GC_NEUTRAL_MODE;
1212 guint32 imt_slot = mono_method_get_imt_slot (method);
1213 MonoImtBuilderEntry *entry;
1215 if (slot_num >= 0 && imt_slot != slot_num) {
1216 /* we build just a single imt slot and this is not it */
1220 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1221 entry->key = method;
1222 entry->value.vtable_slot = vtable_slot;
1223 entry->next = imt_builder [imt_slot];
1224 if (imt_builder [imt_slot] != NULL) {
1225 entry->children = imt_builder [imt_slot]->children + 1;
1226 if (entry->children == 1) {
1227 mono_stats.imt_slots_with_collisions++;
1228 *imt_collisions_bitmap |= (1 << imt_slot);
1231 entry->children = 0;
1232 mono_stats.imt_used_slots++;
1234 imt_builder [imt_slot] = entry;
1237 char *method_name = mono_method_full_name (method, TRUE);
1238 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1239 method, method_name, imt_slot, vtable_slot, entry->children);
1240 g_free (method_name);
1247 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1249 MonoMethod *method = e->key;
1250 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1254 method->klass->name_space,
1255 method->klass->name,
1258 printf (" * %s: NULL\n", message);
1264 compare_imt_builder_entries (const void *p1, const void *p2) {
1265 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1266 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1268 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1272 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1274 MONO_REQ_GC_NEUTRAL_MODE;
1276 int count = end - start;
1277 int chunk_start = out_array->len;
1280 for (i = start; i < end; ++i) {
1281 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1282 item->key = sorted_array [i]->key;
1283 item->value = sorted_array [i]->value;
1284 item->has_target_code = sorted_array [i]->has_target_code;
1285 item->is_equals = TRUE;
1287 item->check_target_idx = out_array->len + 1;
1289 item->check_target_idx = 0;
1290 g_ptr_array_add (out_array, item);
1293 int middle = start + count / 2;
1294 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1296 item->key = sorted_array [middle]->key;
1297 item->is_equals = FALSE;
1298 g_ptr_array_add (out_array, item);
1299 imt_emit_ir (sorted_array, start, middle, out_array);
1300 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1306 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1307 MONO_REQ_GC_NEUTRAL_MODE;
1309 int number_of_entries = entries->children + 1;
1310 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1311 GPtrArray *result = g_ptr_array_new ();
1312 MonoImtBuilderEntry *current_entry;
1315 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1316 sorted_array [i] = current_entry;
1318 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1320 /*for (i = 0; i < number_of_entries; i++) {
1321 print_imt_entry (" sorted array:", sorted_array [i], i);
1324 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1326 free (sorted_array);
1331 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1333 MONO_REQ_GC_NEUTRAL_MODE;
1335 if (imt_builder_entry != NULL) {
1336 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1337 /* No collision, return the vtable slot contents */
1338 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1340 /* Collision, build the thunk */
1341 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1344 result = imt_thunk_builder (vtable, domain,
1345 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1346 for (i = 0; i < imt_ir->len; ++i)
1347 g_free (g_ptr_array_index (imt_ir, i));
1348 g_ptr_array_free (imt_ir, TRUE);
1360 static MonoImtBuilderEntry*
1361 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1364 * LOCKING: requires the loader and domain locks.
1368 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1370 MONO_REQ_GC_NEUTRAL_MODE;
1374 guint32 imt_collisions_bitmap = 0;
1375 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1376 int method_count = 0;
1377 gboolean record_method_count_for_max_collisions = FALSE;
1378 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1381 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1383 for (i = 0; i < klass->interface_offsets_count; ++i) {
1384 MonoClass *iface = klass->interfaces_packed [i];
1385 int interface_offset = klass->interface_offsets_packed [i];
1386 int method_slot_in_interface, vt_slot;
1388 if (mono_class_has_variant_generic_params (iface))
1389 has_variant_iface = TRUE;
1391 mono_class_setup_methods (iface);
1392 vt_slot = interface_offset;
1393 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1396 if (slot_num >= 0 && iface->is_inflated) {
1398 * The imt slot of the method is the same as for its declaring method,
1399 * see the comment in mono_method_get_imt_slot (), so we can
1400 * avoid inflating methods which will be discarded by
1401 * add_imt_builder_entry anyway.
1403 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1404 if (mono_method_get_imt_slot (method) != slot_num) {
1409 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1410 if (method->is_generic) {
1411 has_generic_virtual = TRUE;
1416 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1417 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1422 if (extra_interfaces) {
1423 int interface_offset = klass->vtable_size;
1425 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1426 MonoClass* iface = (MonoClass *)list_item->data;
1427 int method_slot_in_interface;
1428 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1429 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1431 if (method->is_generic)
1432 has_generic_virtual = TRUE;
1433 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1435 interface_offset += iface->method.count;
1438 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1439 /* overwrite the imt slot only if we're building all the entries or if
1440 * we're building this specific one
1442 if (slot_num < 0 || i == slot_num) {
1443 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1446 if (imt_builder [i]) {
1447 MonoImtBuilderEntry *entry;
1449 /* Link entries with imt_builder [i] */
1450 for (entry = entries; entry->next; entry = entry->next) {
1452 MonoMethod *method = (MonoMethod*)entry->key;
1453 char *method_name = mono_method_full_name (method, TRUE);
1454 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1455 g_free (method_name);
1458 entry->next = imt_builder [i];
1459 entries->children += imt_builder [i]->children + 1;
1461 imt_builder [i] = entries;
1464 if (has_generic_virtual || has_variant_iface) {
1466 * There might be collisions later when the the thunk is expanded.
1468 imt_collisions_bitmap |= (1 << i);
1471 * The IMT thunk might be called with an instance of one of the
1472 * generic virtual methods, so has to fallback to the IMT trampoline.
1474 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1476 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1479 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1483 if (imt_builder [i] != NULL) {
1484 int methods_in_slot = imt_builder [i]->children + 1;
1485 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1486 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1487 record_method_count_for_max_collisions = TRUE;
1489 method_count += methods_in_slot;
1493 mono_stats.imt_number_of_methods += method_count;
1494 if (record_method_count_for_max_collisions) {
1495 mono_stats.imt_method_count_when_max_collisions = method_count;
1498 for (i = 0; i < MONO_IMT_SIZE; i++) {
1499 MonoImtBuilderEntry* entry = imt_builder [i];
1500 while (entry != NULL) {
1501 MonoImtBuilderEntry* next = entry->next;
1507 /* we OR the bitmap since we may build just a single imt slot at a time */
1508 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1512 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1513 MONO_REQ_GC_NEUTRAL_MODE;
1515 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1519 * mono_vtable_build_imt_slot:
1520 * @vtable: virtual object table struct
1521 * @imt_slot: slot in the IMT table
1523 * Fill the given @imt_slot in the IMT table of @vtable with
1524 * a trampoline or a thunk for the case of collisions.
1525 * This is part of the internal mono API.
1527 * LOCKING: Take the domain lock.
1530 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1532 MONO_REQ_GC_NEUTRAL_MODE;
1534 gpointer *imt = (gpointer*)vtable;
1535 imt -= MONO_IMT_SIZE;
1536 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1538 /* no support for extra interfaces: the proxy objects will need
1539 * to build the complete IMT
1540 * Update and heck needs to ahppen inside the proper domain lock, as all
1541 * the changes made to a MonoVTable.
1543 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1544 mono_domain_lock (vtable->domain);
1545 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1546 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1547 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1548 mono_domain_unlock (vtable->domain);
1549 mono_loader_unlock ();
1554 * The first two free list entries both belong to the wait list: The
1555 * first entry is the pointer to the head of the list and the second
1556 * entry points to the last element. That way appending and removing
1557 * the first element are both O(1) operations.
1559 #ifdef MONO_SMALL_CONFIG
1560 #define NUM_FREE_LISTS 6
1562 #define NUM_FREE_LISTS 12
1564 #define FIRST_FREE_LIST_SIZE 64
1565 #define MAX_WAIT_LENGTH 50
1566 #define THUNK_THRESHOLD 10
1569 * LOCKING: The domain lock must be held.
1572 init_thunk_free_lists (MonoDomain *domain)
1574 MONO_REQ_GC_NEUTRAL_MODE;
1576 if (domain->thunk_free_lists)
1578 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1582 list_index_for_size (int item_size)
1585 int size = FIRST_FREE_LIST_SIZE;
1587 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1596 * mono_method_alloc_generic_virtual_thunk:
1598 * @size: size in bytes
1600 * Allocs size bytes to be used for the code of a generic virtual
1601 * thunk. It's either allocated from the domain's code manager or
1602 * reused from a previously invalidated piece.
1604 * LOCKING: The domain lock must be held.
1607 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1609 MONO_REQ_GC_NEUTRAL_MODE;
1611 static gboolean inited = FALSE;
1612 static int generic_virtual_thunks_size = 0;
1616 MonoThunkFreeList **l;
1618 init_thunk_free_lists (domain);
1620 size += sizeof (guint32);
1621 if (size < sizeof (MonoThunkFreeList))
1622 size = sizeof (MonoThunkFreeList);
1624 i = list_index_for_size (size);
1625 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1626 if ((*l)->size >= size) {
1627 MonoThunkFreeList *item = *l;
1629 return ((guint32*)item) + 1;
1633 /* no suitable item found - search lists of larger sizes */
1634 while (++i < NUM_FREE_LISTS) {
1635 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1638 g_assert (item->size > size);
1639 domain->thunk_free_lists [i] = item->next;
1640 return ((guint32*)item) + 1;
1643 /* still nothing found - allocate it */
1645 mono_counters_register ("Generic virtual thunk bytes",
1646 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1649 generic_virtual_thunks_size += size;
1651 p = (guint32 *)mono_domain_code_reserve (domain, size);
1654 mono_domain_lock (domain);
1655 if (!domain->generic_virtual_thunks)
1656 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1657 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1658 mono_domain_unlock (domain);
1664 * LOCKING: The domain lock must be held.
1667 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1669 MONO_REQ_GC_NEUTRAL_MODE;
1671 guint32 *p = (guint32 *)code;
1672 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1673 gboolean found = FALSE;
1675 mono_domain_lock (domain);
1676 if (!domain->generic_virtual_thunks)
1677 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1678 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1680 mono_domain_unlock (domain);
1683 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1685 init_thunk_free_lists (domain);
1687 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1688 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1689 int length = item->length;
1692 /* unlink the first item from the wait list */
1693 domain->thunk_free_lists [0] = item->next;
1694 domain->thunk_free_lists [0]->length = length - 1;
1696 i = list_index_for_size (item->size);
1698 /* put it in the free list */
1699 item->next = domain->thunk_free_lists [i];
1700 domain->thunk_free_lists [i] = item;
1704 if (domain->thunk_free_lists [1]) {
1705 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1706 domain->thunk_free_lists [0]->length++;
1708 g_assert (!domain->thunk_free_lists [0]);
1710 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1711 domain->thunk_free_lists [0]->length = 1;
1715 typedef struct _GenericVirtualCase {
1719 struct _GenericVirtualCase *next;
1720 } GenericVirtualCase;
1723 * get_generic_virtual_entries:
1725 * Return IMT entries for the generic virtual method instances and
1726 * variant interface methods for vtable slot
1729 static MonoImtBuilderEntry*
1730 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1732 MONO_REQ_GC_NEUTRAL_MODE;
1734 GenericVirtualCase *list;
1735 MonoImtBuilderEntry *entries;
1737 mono_domain_lock (domain);
1738 if (!domain->generic_virtual_cases)
1739 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1741 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1744 for (; list; list = list->next) {
1745 MonoImtBuilderEntry *entry;
1747 if (list->count < THUNK_THRESHOLD)
1750 entry = g_new0 (MonoImtBuilderEntry, 1);
1751 entry->key = list->method;
1752 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1753 entry->has_target_code = 1;
1755 entry->children = entries->children + 1;
1756 entry->next = entries;
1760 mono_domain_unlock (domain);
1762 /* FIXME: Leaking memory ? */
1767 * mono_method_add_generic_virtual_invocation:
1769 * @vtable_slot: pointer to the vtable slot
1770 * @method: the inflated generic virtual method
1771 * @code: the method's code
1773 * Registers a call via unmanaged code to a generic virtual method
1774 * instantiation or variant interface method. If the number of calls reaches a threshold
1775 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1776 * virtual method thunk.
1779 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1780 gpointer *vtable_slot,
1781 MonoMethod *method, gpointer code)
1783 MONO_REQ_GC_NEUTRAL_MODE;
1785 static gboolean inited = FALSE;
1786 static int num_added = 0;
1788 GenericVirtualCase *gvc, *list;
1789 MonoImtBuilderEntry *entries;
1793 mono_domain_lock (domain);
1794 if (!domain->generic_virtual_cases)
1795 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1797 /* Check whether the case was already added */
1798 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1801 if (gvc->method == method)
1806 /* If not found, make a new one */
1808 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1809 gvc->method = method;
1812 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1814 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1817 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1823 if (++gvc->count == THUNK_THRESHOLD) {
1824 gpointer *old_thunk = (void **)*vtable_slot;
1825 gpointer vtable_trampoline = NULL;
1826 gpointer imt_trampoline = NULL;
1828 if ((gpointer)vtable_slot < (gpointer)vtable) {
1829 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1830 int imt_slot = MONO_IMT_SIZE + displacement;
1832 /* Force the rebuild of the thunk at the next call */
1833 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1834 *vtable_slot = imt_trampoline;
1836 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1838 entries = get_generic_virtual_entries (domain, vtable_slot);
1840 sorted = imt_sort_slot_entries (entries);
1842 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1846 MonoImtBuilderEntry *next = entries->next;
1851 for (i = 0; i < sorted->len; ++i)
1852 g_free (g_ptr_array_index (sorted, i));
1853 g_ptr_array_free (sorted, TRUE);
1856 #ifndef __native_client__
1857 /* We don't re-use any thunks as there is a lot of overhead */
1858 /* to deleting and re-using code in Native Client. */
1859 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1860 invalidate_generic_virtual_thunk (domain, old_thunk);
1864 mono_domain_unlock (domain);
1867 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1870 * mono_class_vtable:
1871 * @domain: the application domain
1872 * @class: the class to initialize
1874 * VTables are domain specific because we create domain specific code, and
1875 * they contain the domain specific static class data.
1876 * On failure, NULL is returned, and class->exception_type is set.
1879 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1882 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1883 mono_error_cleanup (&error);
1888 * mono_class_vtable_full:
1889 * @domain: the application domain
1890 * @class: the class to initialize
1891 * @error set on failure.
1893 * VTables are domain specific because we create domain specific code, and
1894 * they contain the domain specific static class data.
1897 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1899 MONO_REQ_GC_UNSAFE_MODE;
1901 MonoClassRuntimeInfo *runtime_info;
1903 mono_error_init (error);
1907 if (mono_class_has_failure (klass)) {
1908 mono_error_set_for_class_failure (error, klass);
1912 /* this check can be inlined in jitted code, too */
1913 runtime_info = klass->runtime_info;
1914 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1915 return runtime_info->domain_vtables [domain->domain_id];
1916 return mono_class_create_runtime_vtable (domain, klass, error);
1920 * mono_class_try_get_vtable:
1921 * @domain: the application domain
1922 * @class: the class to initialize
1924 * This function tries to get the associated vtable from @class if
1925 * it was already created.
1928 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1930 MONO_REQ_GC_NEUTRAL_MODE;
1932 MonoClassRuntimeInfo *runtime_info;
1936 runtime_info = klass->runtime_info;
1937 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1938 return runtime_info->domain_vtables [domain->domain_id];
1943 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1945 MONO_REQ_GC_NEUTRAL_MODE;
1947 size_t alloc_offset;
1950 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1951 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1952 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1954 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1955 g_assert ((imt_table_bytes & 7) == 4);
1962 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1966 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1968 MONO_REQ_GC_UNSAFE_MODE;
1971 MonoClassRuntimeInfo *runtime_info, *old_info;
1972 MonoClassField *field;
1974 int i, vtable_slots;
1975 size_t imt_table_bytes;
1977 guint32 vtable_size, class_size;
1979 gpointer *interface_offsets;
1981 mono_error_init (error);
1983 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1984 mono_domain_lock (domain);
1985 runtime_info = klass->runtime_info;
1986 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1987 mono_domain_unlock (domain);
1988 mono_loader_unlock ();
1989 return runtime_info->domain_vtables [domain->domain_id];
1991 if (!klass->inited || mono_class_has_failure (klass)) {
1992 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1993 mono_domain_unlock (domain);
1994 mono_loader_unlock ();
1995 mono_error_set_for_class_failure (error, klass);
2000 /* Array types require that their element type be valid*/
2001 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
2002 MonoClass *element_class = klass->element_class;
2003 if (!element_class->inited)
2004 mono_class_init (element_class);
2006 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
2007 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
2008 mono_class_setup_vtable (element_class);
2010 if (mono_class_has_failure (element_class)) {
2011 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2012 if (!mono_class_has_failure (klass))
2013 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
2014 mono_domain_unlock (domain);
2015 mono_loader_unlock ();
2016 mono_error_set_for_class_failure (error, klass);
2022 * For some classes, mono_class_init () already computed klass->vtable_size, and
2023 * that is all that is needed because of the vtable trampolines.
2025 if (!klass->vtable_size)
2026 mono_class_setup_vtable (klass);
2028 if (klass->generic_class && !klass->vtable)
2029 mono_class_check_vtable_constraints (klass, NULL);
2031 /* Initialize klass->has_finalize */
2032 mono_class_has_finalizer (klass);
2034 if (mono_class_has_failure (klass)) {
2035 mono_domain_unlock (domain);
2036 mono_loader_unlock ();
2037 mono_error_set_for_class_failure (error, klass);
2041 vtable_slots = klass->vtable_size;
2042 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2043 class_size = mono_class_data_size (klass);
2047 if (klass->interface_offsets_count) {
2048 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2049 mono_stats.imt_number_of_tables++;
2050 mono_stats.imt_tables_size += imt_table_bytes;
2052 imt_table_bytes = 0;
2055 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2057 mono_stats.used_class_count++;
2058 mono_stats.class_vtable_size += vtable_size;
2060 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2061 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2062 g_assert (!((gsize)vt & 7));
2065 vt->rank = klass->rank;
2066 vt->domain = domain;
2068 mono_class_compute_gc_descriptor (klass);
2070 * We can't use typed allocation in the non-root domains, since the
2071 * collector needs the GC descriptor stored in the vtable even after
2072 * the mempool containing the vtable is destroyed when the domain is
2073 * unloaded. An alternative might be to allocate vtables in the GC
2074 * heap, but this does not seem to work (it leads to crashes inside
2075 * libgc). If that approach is tried, two gc descriptors need to be
2076 * allocated for each class: one for the root domain, and one for all
2077 * other domains. The second descriptor should contain a bit for the
2078 * vtable field in MonoObject, since we can no longer assume the
2079 * vtable is reachable by other roots after the appdomain is unloaded.
2081 #ifdef HAVE_BOEHM_GC
2082 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2083 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2086 vt->gc_descr = klass->gc_descr;
2088 gc_bits = mono_gc_get_vtable_bits (klass);
2089 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2091 vt->gc_bits = gc_bits;
2094 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2095 if (klass->has_static_refs) {
2096 MonoGCDescriptor statics_gc_descr;
2098 gsize default_bitmap [4] = {0};
2101 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2102 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2103 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2104 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2105 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2106 if (bitmap != default_bitmap)
2109 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2111 vt->has_static_fields = TRUE;
2112 mono_stats.class_static_data_size += class_size;
2116 while ((field = mono_class_get_fields (klass, &iter))) {
2117 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2119 if (mono_field_is_deleted (field))
2121 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2122 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2123 if (special_static != SPECIAL_STATIC_NONE) {
2124 guint32 size, offset;
2126 gsize default_bitmap [4] = {0};
2131 if (mono_type_is_reference (field->type)) {
2132 default_bitmap [0] = 1;
2134 bitmap = default_bitmap;
2135 } else if (mono_type_is_struct (field->type)) {
2136 fclass = mono_class_from_mono_type (field->type);
2137 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2138 numbits = max_set + 1;
2140 default_bitmap [0] = 0;
2142 bitmap = default_bitmap;
2144 size = mono_type_size (field->type, &align);
2145 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2146 if (!domain->special_static_fields)
2147 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2148 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2149 if (bitmap != default_bitmap)
2152 * This marks the field as special static to speed up the
2153 * checks in mono_field_static_get/set_value ().
2159 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2160 MonoClass *fklass = mono_class_from_mono_type (field->type);
2161 const char *data = mono_field_get_data (field);
2163 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2164 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2165 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2168 if (fklass->valuetype) {
2169 memcpy (t, data, mono_class_value_size (fklass, NULL));
2171 /* it's a pointer type: add check */
2172 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2179 vt->max_interface_id = klass->max_interface_id;
2180 vt->interface_bitmap = klass->interface_bitmap;
2182 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2183 // class->name, klass->interface_offsets_count);
2185 /* Initialize vtable */
2186 if (callbacks.get_vtable_trampoline) {
2187 // This also covers the AOT case
2188 for (i = 0; i < klass->vtable_size; ++i) {
2189 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2192 mono_class_setup_vtable (klass);
2194 for (i = 0; i < klass->vtable_size; ++i) {
2197 cm = klass->vtable [i];
2199 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2200 if (!is_ok (error)) {
2201 mono_domain_unlock (domain);
2202 mono_loader_unlock ();
2209 if (imt_table_bytes) {
2210 /* Now that the vtable is full, we can actually fill up the IMT */
2211 for (i = 0; i < MONO_IMT_SIZE; ++i)
2212 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2216 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2217 * re-acquire them and check if another thread has created the vtable in the meantime.
2219 /* Special case System.MonoType to avoid infinite recursion */
2220 if (klass != mono_defaults.runtimetype_class) {
2221 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2222 if (!is_ok (error)) {
2223 mono_domain_unlock (domain);
2224 mono_loader_unlock ();
2228 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2229 /* This is unregistered in
2230 unregister_vtable_reflection_type() in
2232 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2235 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2237 /* class_vtable_array keeps an array of created vtables
2239 g_ptr_array_add (domain->class_vtable_array, vt);
2240 /* klass->runtime_info is protected by the loader lock, both when
2241 * it it enlarged and when it is stored info.
2245 * Store the vtable in klass->runtime_info.
2246 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2248 mono_memory_barrier ();
2250 old_info = klass->runtime_info;
2251 if (old_info && old_info->max_domain >= domain->domain_id) {
2252 /* someone already created a large enough runtime info */
2253 old_info->domain_vtables [domain->domain_id] = vt;
2255 int new_size = domain->domain_id;
2257 new_size = MAX (new_size, old_info->max_domain);
2259 /* make the new size a power of two */
2261 while (new_size > i)
2264 /* this is a bounded memory retention issue: may want to
2265 * handle it differently when we'll have a rcu-like system.
2267 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2268 runtime_info->max_domain = new_size - 1;
2269 /* copy the stuff from the older info */
2271 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2273 runtime_info->domain_vtables [domain->domain_id] = vt;
2275 mono_memory_barrier ();
2276 klass->runtime_info = runtime_info;
2279 if (klass == mono_defaults.runtimetype_class) {
2280 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2281 if (!is_ok (error)) {
2282 mono_domain_unlock (domain);
2283 mono_loader_unlock ();
2287 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2288 /* This is unregistered in
2289 unregister_vtable_reflection_type() in
2291 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2294 mono_domain_unlock (domain);
2295 mono_loader_unlock ();
2297 /* make sure the parent is initialized */
2298 /*FIXME shouldn't this fail the current type?*/
2300 mono_class_vtable_full (domain, klass->parent, error);
2305 #ifndef DISABLE_REMOTING
2307 * mono_class_proxy_vtable:
2308 * @domain: the application domain
2309 * @remove_class: the remote class
2310 * @error: set on error
2312 * Creates a vtable for transparent proxies. It is basically
2313 * a copy of the real vtable of the class wrapped in @remote_class,
2314 * but all function pointers invoke the remoting functions, and
2315 * vtable->klass points to the transparent proxy class, and not to @class.
2317 * On failure returns NULL and sets @error
2320 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2322 MONO_REQ_GC_UNSAFE_MODE;
2324 MonoVTable *vt, *pvt;
2325 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2327 GSList *extra_interfaces = NULL;
2328 MonoClass *klass = remote_class->proxy_class;
2329 gpointer *interface_offsets;
2330 uint8_t *bitmap = NULL;
2332 size_t imt_table_bytes;
2334 #ifdef COMPRESSED_INTERFACE_BITMAP
2338 mono_error_init (error);
2340 vt = mono_class_vtable (domain, klass);
2341 g_assert (vt); /*FIXME property handle failure*/
2342 max_interface_id = vt->max_interface_id;
2344 /* Calculate vtable space for extra interfaces */
2345 for (j = 0; j < remote_class->interface_count; j++) {
2346 MonoClass* iclass = remote_class->interfaces[j];
2350 /*FIXME test for interfaces with variant generic arguments*/
2351 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2352 continue; /* interface implemented by the class */
2353 if (g_slist_find (extra_interfaces, iclass))
2356 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2358 method_count = mono_class_num_methods (iclass);
2360 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2364 for (i = 0; i < ifaces->len; ++i) {
2365 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2366 /*FIXME test for interfaces with variant generic arguments*/
2367 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2368 continue; /* interface implemented by the class */
2369 if (g_slist_find (extra_interfaces, ic))
2371 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2372 method_count += mono_class_num_methods (ic);
2374 g_ptr_array_free (ifaces, TRUE);
2378 extra_interface_vtsize += method_count * sizeof (gpointer);
2379 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2382 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2383 mono_stats.imt_number_of_tables++;
2384 mono_stats.imt_tables_size += imt_table_bytes;
2386 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2388 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2390 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2391 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2392 g_assert (!((gsize)pvt & 7));
2394 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2396 pvt->klass = mono_defaults.transparent_proxy_class;
2397 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2398 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2400 /* initialize vtable */
2401 mono_class_setup_vtable (klass);
2402 for (i = 0; i < klass->vtable_size; ++i) {
2405 if ((cm = klass->vtable [i])) {
2406 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2410 pvt->vtable [i] = NULL;
2413 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2414 /* create trampolines for abstract methods */
2415 for (k = klass; k; k = k->parent) {
2417 gpointer iter = NULL;
2418 while ((m = mono_class_get_methods (k, &iter)))
2419 if (!pvt->vtable [m->slot]) {
2420 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2427 pvt->max_interface_id = max_interface_id;
2428 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2429 #ifdef COMPRESSED_INTERFACE_BITMAP
2430 bitmap = (uint8_t *)g_malloc0 (bsize);
2432 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2435 for (i = 0; i < klass->interface_offsets_count; ++i) {
2436 int interface_id = klass->interfaces_packed [i]->interface_id;
2437 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2440 if (extra_interfaces) {
2441 int slot = klass->vtable_size;
2447 /* Create trampolines for the methods of the interfaces */
2448 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2449 interf = (MonoClass *)list_item->data;
2451 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2455 while ((cm = mono_class_get_methods (interf, &iter))) {
2456 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2461 slot += mono_class_num_methods (interf);
2465 /* Now that the vtable is full, we can actually fill up the IMT */
2466 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2467 if (extra_interfaces) {
2468 g_slist_free (extra_interfaces);
2471 #ifdef COMPRESSED_INTERFACE_BITMAP
2472 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2473 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2474 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2477 pvt->interface_bitmap = bitmap;
2481 if (extra_interfaces)
2482 g_slist_free (extra_interfaces);
2483 #ifdef COMPRESSED_INTERFACE_BITMAP
2489 #endif /* DISABLE_REMOTING */
2492 * mono_class_field_is_special_static:
2494 * Returns whether @field is a thread/context static field.
2497 mono_class_field_is_special_static (MonoClassField *field)
2499 MONO_REQ_GC_NEUTRAL_MODE
2501 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2503 if (mono_field_is_deleted (field))
2505 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2506 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2513 * mono_class_field_get_special_static_type:
2514 * @field: The MonoClassField describing the field.
2516 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2517 * SPECIAL_STATIC_NONE otherwise.
2520 mono_class_field_get_special_static_type (MonoClassField *field)
2522 MONO_REQ_GC_NEUTRAL_MODE
2524 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2525 return SPECIAL_STATIC_NONE;
2526 if (mono_field_is_deleted (field))
2527 return SPECIAL_STATIC_NONE;
2528 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2529 return field_is_special_static (field->parent, field);
2530 return SPECIAL_STATIC_NONE;
2534 * mono_class_has_special_static_fields:
2536 * Returns whenever @klass has any thread/context static fields.
2539 mono_class_has_special_static_fields (MonoClass *klass)
2541 MONO_REQ_GC_NEUTRAL_MODE
2543 MonoClassField *field;
2547 while ((field = mono_class_get_fields (klass, &iter))) {
2548 g_assert (field->parent == klass);
2549 if (mono_class_field_is_special_static (field))
2556 #ifndef DISABLE_REMOTING
2558 * create_remote_class_key:
2559 * Creates an array of pointers that can be used as a hash key for a remote class.
2560 * The first element of the array is the number of pointers.
2563 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2565 MONO_REQ_GC_NEUTRAL_MODE;
2570 if (remote_class == NULL) {
2571 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2572 key = (void **)g_malloc (sizeof(gpointer) * 3);
2573 key [0] = GINT_TO_POINTER (2);
2574 key [1] = mono_defaults.marshalbyrefobject_class;
2575 key [2] = extra_class;
2577 key = (void **)g_malloc (sizeof(gpointer) * 2);
2578 key [0] = GINT_TO_POINTER (1);
2579 key [1] = extra_class;
2582 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2583 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2584 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2585 key [1] = remote_class->proxy_class;
2587 // Keep the list of interfaces sorted
2588 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2589 if (extra_class && remote_class->interfaces [i] > extra_class) {
2590 key [j++] = extra_class;
2593 key [j] = remote_class->interfaces [i];
2596 key [j] = extra_class;
2598 // Replace the old class. The interface list is the same
2599 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2600 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2601 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2602 for (i = 0; i < remote_class->interface_count; i++)
2603 key [2 + i] = remote_class->interfaces [i];
2611 * copy_remote_class_key:
2613 * Make a copy of KEY in the domain and return the copy.
2616 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2618 MONO_REQ_GC_NEUTRAL_MODE
2620 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2621 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2623 memcpy (mp_key, key, key_size);
2629 * mono_remote_class:
2630 * @domain: the application domain
2631 * @class_name: name of the remote class
2632 * @error: set on error
2634 * Creates and initializes a MonoRemoteClass object for a remote type.
2636 * On failure returns NULL and sets @error
2639 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2641 MONO_REQ_GC_UNSAFE_MODE;
2643 MonoRemoteClass *rc;
2644 gpointer* key, *mp_key;
2647 mono_error_init (error);
2649 key = create_remote_class_key (NULL, proxy_class);
2651 mono_domain_lock (domain);
2652 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2656 mono_domain_unlock (domain);
2660 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2661 if (!is_ok (error)) {
2663 mono_domain_unlock (domain);
2667 mp_key = copy_remote_class_key (domain, key);
2671 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2672 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2673 rc->interface_count = 1;
2674 rc->interfaces [0] = proxy_class;
2675 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2677 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2678 rc->interface_count = 0;
2679 rc->proxy_class = proxy_class;
2682 rc->default_vtable = NULL;
2683 rc->xdomain_vtable = NULL;
2684 rc->proxy_class_name = name;
2685 #ifndef DISABLE_PERFCOUNTERS
2686 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2689 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2691 mono_domain_unlock (domain);
2696 * clone_remote_class:
2697 * Creates a copy of the remote_class, adding the provided class or interface
2699 static MonoRemoteClass*
2700 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2702 MONO_REQ_GC_NEUTRAL_MODE;
2704 MonoRemoteClass *rc;
2705 gpointer* key, *mp_key;
2707 key = create_remote_class_key (remote_class, extra_class);
2708 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2714 mp_key = copy_remote_class_key (domain, key);
2718 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2720 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2721 rc->proxy_class = remote_class->proxy_class;
2722 rc->interface_count = remote_class->interface_count + 1;
2724 // Keep the list of interfaces sorted, since the hash key of
2725 // the remote class depends on this
2726 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2727 if (remote_class->interfaces [i] > extra_class && i == j)
2728 rc->interfaces [j++] = extra_class;
2729 rc->interfaces [j] = remote_class->interfaces [i];
2732 rc->interfaces [j] = extra_class;
2734 // Replace the old class. The interface array is the same
2735 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2736 rc->proxy_class = extra_class;
2737 rc->interface_count = remote_class->interface_count;
2738 if (rc->interface_count > 0)
2739 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2742 rc->default_vtable = NULL;
2743 rc->xdomain_vtable = NULL;
2744 rc->proxy_class_name = remote_class->proxy_class_name;
2746 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2752 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2754 MONO_REQ_GC_UNSAFE_MODE;
2756 mono_error_init (error);
2758 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2759 mono_domain_lock (domain);
2760 if (rp->target_domain_id != -1) {
2761 if (remote_class->xdomain_vtable == NULL)
2762 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2763 mono_domain_unlock (domain);
2764 mono_loader_unlock ();
2765 return_val_if_nok (error, NULL);
2766 return remote_class->xdomain_vtable;
2768 if (remote_class->default_vtable == NULL) {
2771 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2772 klass = mono_class_from_mono_type (type);
2774 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)))
2775 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2778 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2779 /* N.B. both branches of the if modify error */
2780 if (!is_ok (error)) {
2781 mono_domain_unlock (domain);
2782 mono_loader_unlock ();
2787 mono_domain_unlock (domain);
2788 mono_loader_unlock ();
2789 return remote_class->default_vtable;
2793 * mono_upgrade_remote_class:
2794 * @domain: the application domain
2795 * @tproxy: the proxy whose remote class has to be upgraded.
2796 * @klass: class to which the remote class can be casted.
2797 * @error: set on error
2799 * Updates the vtable of the remote class by adding the necessary method slots
2800 * and interface offsets so it can be safely casted to klass. klass can be a
2801 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2804 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2806 MONO_REQ_GC_UNSAFE_MODE;
2808 MonoTransparentProxy *tproxy;
2809 MonoRemoteClass *remote_class;
2810 gboolean redo_vtable;
2812 mono_error_init (error);
2813 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2814 mono_domain_lock (domain);
2816 tproxy = (MonoTransparentProxy*) proxy_object;
2817 remote_class = tproxy->remote_class;
2819 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2822 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2823 if (remote_class->interfaces [i] == klass)
2824 redo_vtable = FALSE;
2827 redo_vtable = (remote_class->proxy_class != klass);
2831 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2832 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2838 mono_domain_unlock (domain);
2839 mono_loader_unlock ();
2840 return is_ok (error);
2842 #endif /* DISABLE_REMOTING */
2846 * mono_object_get_virtual_method:
2847 * @obj: object to operate on.
2850 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2851 * the instance of a callvirt of method.
2854 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2856 MONO_REQ_GC_UNSAFE_MODE;
2859 MonoMethod **vtable;
2860 gboolean is_proxy = FALSE;
2861 MonoMethod *res = NULL;
2863 klass = mono_object_class (obj);
2864 #ifndef DISABLE_REMOTING
2865 if (klass == mono_defaults.transparent_proxy_class) {
2866 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2871 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2874 mono_class_setup_vtable (klass);
2875 vtable = klass->vtable;
2877 if (method->slot == -1) {
2878 /* method->slot might not be set for instances of generic methods */
2879 if (method->is_inflated) {
2880 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2881 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2884 g_assert_not_reached ();
2888 /* check method->slot is a valid index: perform isinstance? */
2889 if (method->slot != -1) {
2890 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2892 gboolean variance_used = FALSE;
2893 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2894 g_assert (iface_offset > 0);
2895 res = vtable [iface_offset + method->slot];
2898 res = vtable [method->slot];
2902 #ifndef DISABLE_REMOTING
2904 /* It may be an interface, abstract class method or generic method */
2905 if (!res || mono_method_signature (res)->generic_param_count)
2908 /* generic methods demand invoke_with_check */
2909 if (mono_method_signature (res)->generic_param_count)
2910 res = mono_marshal_get_remoting_invoke_with_check (res);
2913 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2914 res = mono_cominterop_get_invoke (res);
2917 res = mono_marshal_get_remoting_invoke (res);
2922 if (method->is_inflated) {
2924 /* Have to inflate the result */
2925 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2926 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2936 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2938 MONO_REQ_GC_UNSAFE_MODE;
2940 MonoObject *result = NULL;
2942 g_assert (callbacks.runtime_invoke);
2944 mono_error_init (error);
2946 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2947 mono_profiler_method_start_invoke (method);
2949 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2951 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2952 mono_profiler_method_end_invoke (method);
2954 if (!mono_error_ok (error))
2961 * mono_runtime_invoke:
2962 * @method: method to invoke
2963 * @obJ: object instance
2964 * @params: arguments to the method
2965 * @exc: exception information.
2967 * Invokes the method represented by @method on the object @obj.
2969 * obj is the 'this' pointer, it should be NULL for static
2970 * methods, a MonoObject* for object instances and a pointer to
2971 * the value type for value types.
2973 * The params array contains the arguments to the method with the
2974 * same convention: MonoObject* pointers for object instances and
2975 * pointers to the value type otherwise.
2977 * From unmanaged code you'll usually use the
2978 * mono_runtime_invoke() variant.
2980 * Note that this function doesn't handle virtual methods for
2981 * you, it will exec the exact method you pass: we still need to
2982 * expose a function to lookup the derived class implementation
2983 * of a virtual method (there are examples of this in the code,
2986 * You can pass NULL as the exc argument if you don't want to
2987 * catch exceptions, otherwise, *exc will be set to the exception
2988 * thrown, if any. if an exception is thrown, you can't use the
2989 * MonoObject* result from the function.
2991 * If the method returns a value type, it is boxed in an object
2995 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
3000 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
3001 if (*exc == NULL && !mono_error_ok(&error)) {
3002 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3004 mono_error_cleanup (&error);
3006 res = mono_runtime_invoke_checked (method, obj, params, &error);
3007 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3013 * mono_runtime_try_invoke:
3014 * @method: method to invoke
3015 * @obJ: object instance
3016 * @params: arguments to the method
3017 * @exc: exception information.
3018 * @error: set on error
3020 * Invokes the method represented by @method on the object @obj.
3022 * obj is the 'this' pointer, it should be NULL for static
3023 * methods, a MonoObject* for object instances and a pointer to
3024 * the value type for value types.
3026 * The params array contains the arguments to the method with the
3027 * same convention: MonoObject* pointers for object instances and
3028 * pointers to the value type otherwise.
3030 * From unmanaged code you'll usually use the
3031 * mono_runtime_invoke() variant.
3033 * Note that this function doesn't handle virtual methods for
3034 * you, it will exec the exact method you pass: we still need to
3035 * expose a function to lookup the derived class implementation
3036 * of a virtual method (there are examples of this in the code,
3039 * For this function, you must not pass NULL as the exc argument if
3040 * you don't want to catch exceptions, use
3041 * mono_runtime_invoke_checked(). If an exception is thrown, you
3042 * can't use the MonoObject* result from the function.
3044 * If this method cannot be invoked, @error will be set and @exc and
3045 * the return value must not be used.
3047 * If the method returns a value type, it is boxed in an object
3051 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3053 MONO_REQ_GC_UNSAFE_MODE;
3055 g_assert (exc != NULL);
3057 if (mono_runtime_get_no_exec ())
3058 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3060 return do_runtime_invoke (method, obj, params, exc, error);
3064 * mono_runtime_invoke_checked:
3065 * @method: method to invoke
3066 * @obJ: object instance
3067 * @params: arguments to the method
3068 * @error: set on error
3070 * Invokes the method represented by @method on the object @obj.
3072 * obj is the 'this' pointer, it should be NULL for static
3073 * methods, a MonoObject* for object instances and a pointer to
3074 * the value type for value types.
3076 * The params array contains the arguments to the method with the
3077 * same convention: MonoObject* pointers for object instances and
3078 * pointers to the value type otherwise.
3080 * From unmanaged code you'll usually use the
3081 * mono_runtime_invoke() variant.
3083 * Note that this function doesn't handle virtual methods for
3084 * you, it will exec the exact method you pass: we still need to
3085 * expose a function to lookup the derived class implementation
3086 * of a virtual method (there are examples of this in the code,
3089 * If an exception is thrown, you can't use the MonoObject* result
3090 * from the function.
3092 * If this method cannot be invoked, @error will be set. If the
3093 * method throws an exception (and we're in coop mode) the exception
3094 * will be set in @error.
3096 * If the method returns a value type, it is boxed in an object
3100 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3102 MONO_REQ_GC_UNSAFE_MODE;
3104 if (mono_runtime_get_no_exec ())
3105 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3107 return do_runtime_invoke (method, obj, params, NULL, error);
3111 * mono_method_get_unmanaged_thunk:
3112 * @method: method to generate a thunk for.
3114 * Returns an unmanaged->managed thunk that can be used to call
3115 * a managed method directly from C.
3117 * The thunk's C signature closely matches the managed signature:
3119 * C#: public bool Equals (object obj);
3120 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3121 * MonoObject*, MonoException**);
3123 * The 1st ("this") parameter must not be used with static methods:
3125 * C#: public static bool ReferenceEquals (object a, object b);
3126 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3129 * The last argument must be a non-null pointer of a MonoException* pointer.
3130 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3131 * exception has been thrown in managed code. Otherwise it will point
3132 * to the MonoException* caught by the thunk. In this case, the result of
3133 * the thunk is undefined:
3135 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3136 * MonoException *ex = NULL;
3137 * Equals func = mono_method_get_unmanaged_thunk (method);
3138 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3140 * // handle exception
3143 * The calling convention of the thunk matches the platform's default
3144 * convention. This means that under Windows, C declarations must
3145 * contain the __stdcall attribute:
3147 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3148 * MonoObject*, MonoException**);
3152 * Value type arguments and return values are treated as they were objects:
3154 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3155 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3157 * Arguments must be properly boxed upon trunk's invocation, while return
3158 * values must be unboxed.
3161 mono_method_get_unmanaged_thunk (MonoMethod *method)
3163 MONO_REQ_GC_NEUTRAL_MODE;
3164 MONO_REQ_API_ENTRYPOINT;
3169 g_assert (!mono_threads_is_coop_enabled ());
3171 MONO_ENTER_GC_UNSAFE;
3172 method = mono_marshal_get_thunk_invoke_wrapper (method);
3173 res = mono_compile_method_checked (method, &error);
3174 mono_error_cleanup (&error);
3175 MONO_EXIT_GC_UNSAFE;
3181 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3183 MONO_REQ_GC_UNSAFE_MODE;
3187 /* object fields cannot be byref, so we don't need a
3189 gpointer *p = (gpointer*)dest;
3196 case MONO_TYPE_BOOLEAN:
3198 case MONO_TYPE_U1: {
3199 guint8 *p = (guint8*)dest;
3200 *p = value ? *(guint8*)value : 0;
3205 case MONO_TYPE_CHAR: {
3206 guint16 *p = (guint16*)dest;
3207 *p = value ? *(guint16*)value : 0;
3210 #if SIZEOF_VOID_P == 4
3215 case MONO_TYPE_U4: {
3216 gint32 *p = (gint32*)dest;
3217 *p = value ? *(gint32*)value : 0;
3220 #if SIZEOF_VOID_P == 8
3225 case MONO_TYPE_U8: {
3226 gint64 *p = (gint64*)dest;
3227 *p = value ? *(gint64*)value : 0;
3230 case MONO_TYPE_R4: {
3231 float *p = (float*)dest;
3232 *p = value ? *(float*)value : 0;
3235 case MONO_TYPE_R8: {
3236 double *p = (double*)dest;
3237 *p = value ? *(double*)value : 0;
3240 case MONO_TYPE_STRING:
3241 case MONO_TYPE_SZARRAY:
3242 case MONO_TYPE_CLASS:
3243 case MONO_TYPE_OBJECT:
3244 case MONO_TYPE_ARRAY:
3245 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3247 case MONO_TYPE_FNPTR:
3248 case MONO_TYPE_PTR: {
3249 gpointer *p = (gpointer*)dest;
3250 *p = deref_pointer? *(gpointer*)value: value;
3253 case MONO_TYPE_VALUETYPE:
3254 /* note that 't' and 'type->type' can be different */
3255 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3256 t = mono_class_enum_basetype (type->data.klass)->type;
3259 MonoClass *klass = mono_class_from_mono_type (type);
3260 int size = mono_class_value_size (klass, NULL);
3262 mono_gc_bzero_atomic (dest, size);
3264 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3267 case MONO_TYPE_GENERICINST:
3268 t = type->data.generic_class->container_class->byval_arg.type;
3271 g_error ("got type %x", type->type);
3276 * mono_field_set_value:
3277 * @obj: Instance object
3278 * @field: MonoClassField describing the field to set
3279 * @value: The value to be set
3281 * Sets the value of the field described by @field in the object instance @obj
3282 * to the value passed in @value. This method should only be used for instance
3283 * fields. For static fields, use mono_field_static_set_value.
3285 * The value must be on the native format of the field type.
3288 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3290 MONO_REQ_GC_UNSAFE_MODE;
3294 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3296 dest = (char*)obj + field->offset;
3297 mono_copy_value (field->type, dest, value, FALSE);
3301 * mono_field_static_set_value:
3302 * @field: MonoClassField describing the field to set
3303 * @value: The value to be set
3305 * Sets the value of the static field described by @field
3306 * to the value passed in @value.
3308 * The value must be on the native format of the field type.
3311 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3313 MONO_REQ_GC_UNSAFE_MODE;
3317 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3318 /* you cant set a constant! */
3319 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3321 if (field->offset == -1) {
3322 /* Special static */
3325 mono_domain_lock (vt->domain);
3326 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3327 mono_domain_unlock (vt->domain);
3328 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3330 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3332 mono_copy_value (field->type, dest, value, FALSE);
3336 * mono_vtable_get_static_field_data:
3338 * Internal use function: return a pointer to the memory holding the static fields
3339 * for a class or NULL if there are no static fields.
3340 * This is exported only for use by the debugger.
3343 mono_vtable_get_static_field_data (MonoVTable *vt)
3345 MONO_REQ_GC_NEUTRAL_MODE
3347 if (!vt->has_static_fields)
3349 return vt->vtable [vt->klass->vtable_size];
3353 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3355 MONO_REQ_GC_UNSAFE_MODE;
3359 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3360 if (field->offset == -1) {
3361 /* Special static */
3364 mono_domain_lock (vt->domain);
3365 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3366 mono_domain_unlock (vt->domain);
3367 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3369 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3372 src = (guint8*)obj + field->offset;
3379 * mono_field_get_value:
3380 * @obj: Object instance
3381 * @field: MonoClassField describing the field to fetch information from
3382 * @value: pointer to the location where the value will be stored
3384 * Use this routine to get the value of the field @field in the object
3387 * The pointer provided by value must be of the field type, for reference
3388 * types this is a MonoObject*, for value types its the actual pointer to
3393 * mono_field_get_value (obj, int_field, &i);
3396 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3398 MONO_REQ_GC_UNSAFE_MODE;
3404 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3406 src = (char*)obj + field->offset;
3407 mono_copy_value (field->type, value, src, TRUE);
3411 * mono_field_get_value_object:
3412 * @domain: domain where the object will be created (if boxing)
3413 * @field: MonoClassField describing the field to fetch information from
3414 * @obj: The object instance for the field.
3416 * Returns: a new MonoObject with the value from the given field. If the
3417 * field represents a value type, the value is boxed.
3421 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3424 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3425 mono_error_assert_ok (&error);
3430 * mono_field_get_value_object_checked:
3431 * @domain: domain where the object will be created (if boxing)
3432 * @field: MonoClassField describing the field to fetch information from
3433 * @obj: The object instance for the field.
3434 * @error: Set on error.
3436 * Returns: a new MonoObject with the value from the given field. If the
3437 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3441 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3443 MONO_REQ_GC_UNSAFE_MODE;
3445 mono_error_init (error);
3449 MonoVTable *vtable = NULL;
3451 gboolean is_static = FALSE;
3452 gboolean is_ref = FALSE;
3453 gboolean is_literal = FALSE;
3454 gboolean is_ptr = FALSE;
3455 MonoType *type = mono_field_get_type_checked (field, error);
3457 return_val_if_nok (error, NULL);
3459 switch (type->type) {
3460 case MONO_TYPE_STRING:
3461 case MONO_TYPE_OBJECT:
3462 case MONO_TYPE_CLASS:
3463 case MONO_TYPE_ARRAY:
3464 case MONO_TYPE_SZARRAY:
3469 case MONO_TYPE_BOOLEAN:
3472 case MONO_TYPE_CHAR:
3481 case MONO_TYPE_VALUETYPE:
3482 is_ref = type->byref;
3484 case MONO_TYPE_GENERICINST:
3485 is_ref = !mono_type_generic_inst_is_valuetype (type);
3491 g_error ("type 0x%x not handled in "
3492 "mono_field_get_value_object", type->type);
3496 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3499 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3503 vtable = mono_class_vtable_full (domain, field->parent, error);
3504 return_val_if_nok (error, NULL);
3506 if (!vtable->initialized) {
3507 mono_runtime_class_init_full (vtable, error);
3508 return_val_if_nok (error, NULL);
3517 get_default_field_value (domain, field, &o, error);
3518 return_val_if_nok (error, NULL);
3519 } else if (is_static) {
3520 mono_field_static_get_value_checked (vtable, field, &o, error);
3521 return_val_if_nok (error, NULL);
3523 mono_field_get_value (obj, field, &o);
3529 static MonoMethod *m;
3535 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3536 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3542 get_default_field_value (domain, field, v, error);
3543 return_val_if_nok (error, NULL);
3544 } else if (is_static) {
3545 mono_field_static_get_value_checked (vtable, field, v, error);
3546 return_val_if_nok (error, NULL);
3548 mono_field_get_value (obj, field, v);
3551 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3552 args [0] = ptr ? *ptr : NULL;
3553 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3554 return_val_if_nok (error, NULL);
3556 o = mono_runtime_invoke_checked (m, NULL, args, error);
3557 return_val_if_nok (error, NULL);
3562 /* boxed value type */
3563 klass = mono_class_from_mono_type (type);
3565 if (mono_class_is_nullable (klass))
3566 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3568 o = mono_object_new_checked (domain, klass, error);
3569 return_val_if_nok (error, NULL);
3570 v = ((gchar *) o) + sizeof (MonoObject);
3573 get_default_field_value (domain, field, v, error);
3574 return_val_if_nok (error, NULL);
3575 } else if (is_static) {
3576 mono_field_static_get_value_checked (vtable, field, v, error);
3577 return_val_if_nok (error, NULL);
3579 mono_field_get_value (obj, field, v);
3586 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3588 MONO_REQ_GC_UNSAFE_MODE;
3590 mono_error_init (error);
3592 const char *p = blob;
3593 mono_metadata_decode_blob_size (p, &p);
3596 case MONO_TYPE_BOOLEAN:
3599 *(guint8 *) value = *p;
3601 case MONO_TYPE_CHAR:
3604 *(guint16*) value = read16 (p);
3608 *(guint32*) value = read32 (p);
3612 *(guint64*) value = read64 (p);
3615 readr4 (p, (float*) value);
3618 readr8 (p, (double*) value);
3620 case MONO_TYPE_STRING:
3621 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3623 case MONO_TYPE_CLASS:
3624 *(gpointer*) value = NULL;
3628 g_warning ("type 0x%02x should not be in constant table", type);
3634 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3636 MONO_REQ_GC_NEUTRAL_MODE;
3638 MonoTypeEnum def_type;
3641 mono_error_init (error);
3643 data = mono_class_get_field_default_value (field, &def_type);
3644 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3648 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3650 MONO_REQ_GC_UNSAFE_MODE;
3654 mono_error_init (error);
3656 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3658 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3659 get_default_field_value (vt->domain, field, value, error);
3663 if (field->offset == -1) {
3664 /* Special static */
3665 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3666 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3668 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3670 mono_copy_value (field->type, value, src, TRUE);
3674 * mono_field_static_get_value:
3675 * @vt: vtable to the object
3676 * @field: MonoClassField describing the field to fetch information from
3677 * @value: where the value is returned
3679 * Use this routine to get the value of the static field @field value.
3681 * The pointer provided by value must be of the field type, for reference
3682 * types this is a MonoObject*, for value types its the actual pointer to
3687 * mono_field_static_get_value (vt, int_field, &i);
3690 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3692 MONO_REQ_GC_NEUTRAL_MODE;
3695 mono_field_static_get_value_checked (vt, field, value, &error);
3696 mono_error_cleanup (&error);
3700 * mono_field_static_get_value_checked:
3701 * @vt: vtable to the object
3702 * @field: MonoClassField describing the field to fetch information from
3703 * @value: where the value is returned
3704 * @error: set on error
3706 * Use this routine to get the value of the static field @field value.
3708 * The pointer provided by value must be of the field type, for reference
3709 * types this is a MonoObject*, for value types its the actual pointer to
3714 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3715 * if (!is_ok (error)) { ... }
3717 * On failure sets @error.
3720 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3722 MONO_REQ_GC_NEUTRAL_MODE;
3724 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3728 * mono_property_set_value:
3729 * @prop: MonoProperty to set
3730 * @obj: instance object on which to act
3731 * @params: parameters to pass to the propery
3732 * @exc: optional exception
3734 * Invokes the property's set method with the given arguments on the
3735 * object instance obj (or NULL for static properties).
3737 * You can pass NULL as the exc argument if you don't want to
3738 * catch exceptions, otherwise, *exc will be set to the exception
3739 * thrown, if any. if an exception is thrown, you can't use the
3740 * MonoObject* result from the function.
3743 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3745 MONO_REQ_GC_UNSAFE_MODE;
3748 do_runtime_invoke (prop->set, obj, params, exc, &error);
3749 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3750 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3752 mono_error_cleanup (&error);
3757 * mono_property_set_value_checked:
3758 * @prop: MonoProperty to set
3759 * @obj: instance object on which to act
3760 * @params: parameters to pass to the propery
3761 * @error: set on error
3763 * Invokes the property's set method with the given arguments on the
3764 * object instance obj (or NULL for static properties).
3766 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3767 * If an exception is thrown, it will be caught and returned via @error.
3770 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3772 MONO_REQ_GC_UNSAFE_MODE;
3776 mono_error_init (error);
3777 do_runtime_invoke (prop->set, obj, params, &exc, error);
3778 if (exc != NULL && is_ok (error))
3779 mono_error_set_exception_instance (error, (MonoException*)exc);
3780 return is_ok (error);
3784 * mono_property_get_value:
3785 * @prop: MonoProperty to fetch
3786 * @obj: instance object on which to act
3787 * @params: parameters to pass to the propery
3788 * @exc: optional exception
3790 * Invokes the property's get method with the given arguments on the
3791 * object instance obj (or NULL for static properties).
3793 * You can pass NULL as the exc argument if you don't want to
3794 * catch exceptions, otherwise, *exc will be set to the exception
3795 * thrown, if any. if an exception is thrown, you can't use the
3796 * MonoObject* result from the function.
3798 * Returns: the value from invoking the get method on the property.
3801 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3803 MONO_REQ_GC_UNSAFE_MODE;
3806 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3807 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3808 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3810 mono_error_cleanup (&error); /* FIXME don't raise here */
3817 * mono_property_get_value_checked:
3818 * @prop: MonoProperty to fetch
3819 * @obj: instance object on which to act
3820 * @params: parameters to pass to the propery
3821 * @error: set on error
3823 * Invokes the property's get method with the given arguments on the
3824 * object instance obj (or NULL for static properties).
3826 * If an exception is thrown, you can't use the
3827 * MonoObject* result from the function. The exception will be propagated via @error.
3829 * Returns: the value from invoking the get method on the property. On
3830 * failure returns NULL and sets @error.
3833 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3835 MONO_REQ_GC_UNSAFE_MODE;
3838 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3839 if (exc != NULL && !is_ok (error))
3840 mono_error_set_exception_instance (error, (MonoException*) exc);
3848 * mono_nullable_init:
3849 * @buf: The nullable structure to initialize.
3850 * @value: the value to initialize from
3851 * @klass: the type for the object
3853 * Initialize the nullable structure pointed to by @buf from @value which
3854 * should be a boxed value type. The size of @buf should be able to hold
3855 * as much data as the @klass->instance_size (which is the number of bytes
3856 * that will be copies).
3858 * Since Nullables have variable structure, we can not define a C
3859 * structure for them.
3862 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3864 MONO_REQ_GC_UNSAFE_MODE;
3866 MonoClass *param_class = klass->cast_class;
3868 mono_class_setup_fields_locking (klass);
3869 g_assert (klass->fields_inited);
3871 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3872 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3874 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3876 if (param_class->has_references)
3877 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3879 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3881 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3886 * mono_nullable_box:
3887 * @buf: The buffer representing the data to be boxed
3888 * @klass: the type to box it as.
3889 * @error: set on oerr
3891 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3892 * @buf. On failure returns NULL and sets @error
3895 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3897 MONO_REQ_GC_UNSAFE_MODE;
3899 mono_error_init (error);
3900 MonoClass *param_class = klass->cast_class;
3902 mono_class_setup_fields_locking (klass);
3903 g_assert (klass->fields_inited);
3905 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3906 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3908 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3909 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3910 return_val_if_nok (error, NULL);
3911 if (param_class->has_references)
3912 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3914 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3922 * mono_get_delegate_invoke:
3923 * @klass: The delegate class
3925 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3928 mono_get_delegate_invoke (MonoClass *klass)
3930 MONO_REQ_GC_NEUTRAL_MODE;
3934 /* This is called at runtime, so avoid the slower search in metadata */
3935 mono_class_setup_methods (klass);
3936 if (mono_class_has_failure (klass))
3938 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3943 * mono_get_delegate_begin_invoke:
3944 * @klass: The delegate class
3946 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3949 mono_get_delegate_begin_invoke (MonoClass *klass)
3951 MONO_REQ_GC_NEUTRAL_MODE;
3955 /* This is called at runtime, so avoid the slower search in metadata */
3956 mono_class_setup_methods (klass);
3957 if (mono_class_has_failure (klass))
3959 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3964 * mono_get_delegate_end_invoke:
3965 * @klass: The delegate class
3967 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3970 mono_get_delegate_end_invoke (MonoClass *klass)
3972 MONO_REQ_GC_NEUTRAL_MODE;
3976 /* This is called at runtime, so avoid the slower search in metadata */
3977 mono_class_setup_methods (klass);
3978 if (mono_class_has_failure (klass))
3980 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3985 * mono_runtime_delegate_invoke:
3986 * @delegate: pointer to a delegate object.
3987 * @params: parameters for the delegate.
3988 * @exc: Pointer to the exception result.
3990 * Invokes the delegate method @delegate with the parameters provided.
3992 * You can pass NULL as the exc argument if you don't want to
3993 * catch exceptions, otherwise, *exc will be set to the exception
3994 * thrown, if any. if an exception is thrown, you can't use the
3995 * MonoObject* result from the function.
3998 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4000 MONO_REQ_GC_UNSAFE_MODE;
4004 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
4006 mono_error_cleanup (&error);
4009 if (!is_ok (&error))
4010 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4014 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
4015 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4021 * mono_runtime_delegate_try_invoke:
4022 * @delegate: pointer to a delegate object.
4023 * @params: parameters for the delegate.
4024 * @exc: Pointer to the exception result.
4025 * @error: set on error
4027 * Invokes the delegate method @delegate with the parameters provided.
4029 * You can pass NULL as the exc argument if you don't want to
4030 * catch exceptions, otherwise, *exc will be set to the exception
4031 * thrown, if any. On failure to execute, @error will be set.
4032 * if an exception is thrown, you can't use the
4033 * MonoObject* result from the function.
4036 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4038 MONO_REQ_GC_UNSAFE_MODE;
4040 mono_error_init (error);
4042 MonoClass *klass = delegate->vtable->klass;
4045 im = mono_get_delegate_invoke (klass);
4047 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4050 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4052 o = mono_runtime_invoke_checked (im, delegate, params, error);
4059 * mono_runtime_delegate_invoke_checked:
4060 * @delegate: pointer to a delegate object.
4061 * @params: parameters for the delegate.
4062 * @error: set on error
4064 * Invokes the delegate method @delegate with the parameters provided.
4066 * On failure @error will be set and you can't use the MonoObject*
4067 * result from the function.
4070 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4072 mono_error_init (error);
4073 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4076 static char **main_args = NULL;
4077 static int num_main_args = 0;
4080 * mono_runtime_get_main_args:
4082 * Returns: a MonoArray with the arguments passed to the main program
4085 mono_runtime_get_main_args (void)
4087 MONO_REQ_GC_UNSAFE_MODE;
4089 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4090 mono_error_assert_ok (&error);
4095 * mono_runtime_get_main_args:
4096 * @error: set on error
4098 * Returns: a MonoArray with the arguments passed to the main
4099 * program. On failure returns NULL and sets @error.
4102 mono_runtime_get_main_args_checked (MonoError *error)
4106 MonoDomain *domain = mono_domain_get ();
4108 mono_error_init (error);
4110 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4111 return_val_if_nok (error, NULL);
4113 for (i = 0; i < num_main_args; ++i)
4114 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4120 free_main_args (void)
4122 MONO_REQ_GC_NEUTRAL_MODE;
4126 for (i = 0; i < num_main_args; ++i)
4127 g_free (main_args [i]);
4134 * mono_runtime_set_main_args:
4135 * @argc: number of arguments from the command line
4136 * @argv: array of strings from the command line
4138 * Set the command line arguments from an embedding application that doesn't otherwise call
4139 * mono_runtime_run_main ().
4142 mono_runtime_set_main_args (int argc, char* argv[])
4144 MONO_REQ_GC_NEUTRAL_MODE;
4149 main_args = g_new0 (char*, argc);
4150 num_main_args = argc;
4152 for (i = 0; i < argc; ++i) {
4155 utf8_arg = mono_utf8_from_external (argv[i]);
4156 if (utf8_arg == NULL) {
4157 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4158 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4162 main_args [i] = utf8_arg;
4169 * Prepare an array of arguments in order to execute a standard Main()
4170 * method (argc/argv contains the executable name). This method also
4171 * sets the command line argument value needed by System.Environment.
4175 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4177 MONO_REQ_GC_UNSAFE_MODE;
4181 MonoArray *args = NULL;
4182 MonoDomain *domain = mono_domain_get ();
4183 gchar *utf8_fullpath;
4184 MonoMethodSignature *sig;
4186 g_assert (method != NULL);
4188 mono_thread_set_main (mono_thread_current ());
4190 main_args = g_new0 (char*, argc);
4191 num_main_args = argc;
4193 if (!g_path_is_absolute (argv [0])) {
4194 gchar *basename = g_path_get_basename (argv [0]);
4195 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4199 utf8_fullpath = mono_utf8_from_external (fullpath);
4200 if(utf8_fullpath == NULL) {
4201 /* Printing the arg text will cause glib to
4202 * whinge about "Invalid UTF-8", but at least
4203 * its relevant, and shows the problem text
4206 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4207 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4214 utf8_fullpath = mono_utf8_from_external (argv[0]);
4215 if(utf8_fullpath == NULL) {
4216 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4217 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4222 main_args [0] = utf8_fullpath;
4224 for (i = 1; i < argc; ++i) {
4227 utf8_arg=mono_utf8_from_external (argv[i]);
4228 if(utf8_arg==NULL) {
4229 /* Ditto the comment about Invalid UTF-8 here */
4230 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4231 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4235 main_args [i] = utf8_arg;
4240 sig = mono_method_signature (method);
4242 g_print ("Unable to load Main method.\n");
4246 if (sig->param_count) {
4247 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4248 mono_error_assert_ok (&error);
4249 for (i = 0; i < argc; ++i) {
4250 /* The encodings should all work, given that
4251 * we've checked all these args for the
4254 gchar *str = mono_utf8_from_external (argv [i]);
4255 MonoString *arg = mono_string_new (domain, str);
4256 mono_array_setref (args, i, arg);
4260 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4261 mono_error_assert_ok (&error);
4264 mono_assembly_set_main (method->klass->image->assembly);
4270 * mono_runtime_run_main:
4271 * @method: the method to start the application with (usually Main)
4272 * @argc: number of arguments from the command line
4273 * @argv: array of strings from the command line
4274 * @exc: excetption results
4276 * Execute a standard Main() method (argc/argv contains the
4277 * executable name). This method also sets the command line argument value
4278 * needed by System.Environment.
4283 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4286 MONO_REQ_GC_UNSAFE_MODE;
4289 MonoArray *args = prepare_run_main (method, argc, argv);
4292 res = mono_runtime_try_exec_main (method, args, exc, &error);
4293 if (*exc == NULL && !is_ok (&error))
4294 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4296 mono_error_cleanup (&error);
4298 res = mono_runtime_exec_main_checked (method, args, &error);
4299 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4305 * mono_runtime_run_main_checked:
4306 * @method: the method to start the application with (usually Main)
4307 * @argc: number of arguments from the command line
4308 * @argv: array of strings from the command line
4309 * @error: set on error
4311 * Execute a standard Main() method (argc/argv contains the
4312 * executable name). This method also sets the command line argument value
4313 * needed by System.Environment. On failure sets @error.
4318 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4321 mono_error_init (error);
4322 MonoArray *args = prepare_run_main (method, argc, argv);
4323 return mono_runtime_exec_main_checked (method, args, error);
4327 * mono_runtime_try_run_main:
4328 * @method: the method to start the application with (usually Main)
4329 * @argc: number of arguments from the command line
4330 * @argv: array of strings from the command line
4331 * @exc: set if Main throws an exception
4332 * @error: set if Main can't be executed
4334 * Execute a standard Main() method (argc/argv contains the executable
4335 * name). This method also sets the command line argument value needed
4336 * by System.Environment. On failure sets @error if Main can't be
4337 * executed or @exc if it threw and exception.
4342 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4343 MonoObject **exc, MonoError *error)
4346 mono_error_init (error);
4347 MonoArray *args = prepare_run_main (method, argc, argv);
4348 return mono_runtime_try_exec_main (method, args, exc, error);
4353 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4355 static MonoMethod *serialize_method;
4361 if (!serialize_method) {
4362 MonoClass *klass = mono_class_get_remoting_services_class ();
4363 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4366 if (!serialize_method) {
4371 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4376 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4377 if (*exc == NULL && !mono_error_ok (&error))
4378 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4380 mono_error_cleanup (&error);
4389 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4391 MONO_REQ_GC_UNSAFE_MODE;
4393 static MonoMethod *deserialize_method;
4399 if (!deserialize_method) {
4400 MonoClass *klass = mono_class_get_remoting_services_class ();
4401 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4403 if (!deserialize_method) {
4411 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4412 if (*exc == NULL && !mono_error_ok (&error))
4413 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4415 mono_error_cleanup (&error);
4423 #ifndef DISABLE_REMOTING
4425 make_transparent_proxy (MonoObject *obj, MonoError *error)
4427 MONO_REQ_GC_UNSAFE_MODE;
4429 static MonoMethod *get_proxy_method;
4431 MonoDomain *domain = mono_domain_get ();
4432 MonoRealProxy *real_proxy;
4433 MonoReflectionType *reflection_type;
4434 MonoTransparentProxy *transparent_proxy;
4436 mono_error_init (error);
4438 if (!get_proxy_method)
4439 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4441 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4443 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4444 return_val_if_nok (error, NULL);
4445 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4446 return_val_if_nok (error, NULL);
4448 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4449 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4451 MonoObject *exc = NULL;
4453 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4454 if (exc != NULL && is_ok (error))
4455 mono_error_set_exception_instance (error, (MonoException*)exc);
4457 return (MonoObject*) transparent_proxy;
4459 #endif /* DISABLE_REMOTING */
4462 * mono_object_xdomain_representation
4464 * @target_domain: a domain
4465 * @error: set on error.
4467 * Creates a representation of obj in the domain target_domain. This
4468 * is either a copy of obj arrived through via serialization and
4469 * deserialization or a proxy, depending on whether the object is
4470 * serializable or marshal by ref. obj must not be in target_domain.
4472 * If the object cannot be represented in target_domain, NULL is
4473 * returned and @error is set appropriately.
4476 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4478 MONO_REQ_GC_UNSAFE_MODE;
4480 mono_error_init (error);
4481 MonoObject *deserialized = NULL;
4483 #ifndef DISABLE_REMOTING
4484 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4485 deserialized = make_transparent_proxy (obj, error);
4490 gboolean failure = FALSE;
4491 MonoDomain *domain = mono_domain_get ();
4492 MonoObject *serialized;
4493 MonoObject *exc = NULL;
4495 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4496 serialized = serialize_object (obj, &failure, &exc);
4497 mono_domain_set_internal_with_options (target_domain, FALSE);
4499 deserialized = deserialize_object (serialized, &failure, &exc);
4500 if (domain != target_domain)
4501 mono_domain_set_internal_with_options (domain, FALSE);
4503 mono_error_set_exception_instance (error, (MonoException*)exc);
4506 return deserialized;
4509 /* Used in call_unhandled_exception_delegate */
4511 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4513 MONO_REQ_GC_UNSAFE_MODE;
4515 mono_error_init (error);
4518 MonoMethod *method = NULL;
4519 MonoBoolean is_terminating = TRUE;
4522 klass = mono_class_get_unhandled_exception_event_args_class ();
4523 mono_class_init (klass);
4525 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4526 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4530 args [1] = &is_terminating;
4532 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4533 return_val_if_nok (error, NULL);
4535 mono_runtime_invoke_checked (method, obj, args, error);
4536 return_val_if_nok (error, NULL);
4541 /* Used in mono_unhandled_exception */
4543 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4544 MONO_REQ_GC_UNSAFE_MODE;
4547 MonoObject *e = NULL;
4549 MonoDomain *current_domain = mono_domain_get ();
4551 if (domain != current_domain)
4552 mono_domain_set_internal_with_options (domain, FALSE);
4554 g_assert (domain == mono_object_domain (domain->domain));
4556 if (mono_object_domain (exc) != domain) {
4558 exc = mono_object_xdomain_representation (exc, domain, &error);
4560 if (!is_ok (&error)) {
4561 MonoError inner_error;
4562 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4563 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4564 mono_error_assert_ok (&inner_error);
4566 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4567 "System.Runtime.Serialization", "SerializationException",
4568 "Could not serialize unhandled exception.");
4572 g_assert (mono_object_domain (exc) == domain);
4574 pa [0] = domain->domain;
4575 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4576 mono_error_assert_ok (&error);
4577 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4578 if (!is_ok (&error)) {
4580 e = (MonoObject*)mono_error_convert_to_exception (&error);
4582 mono_error_cleanup (&error);
4585 if (domain != current_domain)
4586 mono_domain_set_internal_with_options (current_domain, FALSE);
4589 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4590 if (!mono_error_ok (&error)) {
4591 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4592 mono_error_cleanup (&error);
4594 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4600 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4603 * mono_runtime_unhandled_exception_policy_set:
4604 * @policy: the new policy
4606 * This is a VM internal routine.
4608 * Sets the runtime policy for handling unhandled exceptions.
4611 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4612 runtime_unhandled_exception_policy = policy;
4616 * mono_runtime_unhandled_exception_policy_get:
4618 * This is a VM internal routine.
4620 * Gets the runtime policy for handling unhandled exceptions.
4622 MonoRuntimeUnhandledExceptionPolicy
4623 mono_runtime_unhandled_exception_policy_get (void) {
4624 return runtime_unhandled_exception_policy;
4628 * mono_unhandled_exception:
4629 * @exc: exception thrown
4631 * This is a VM internal routine.
4633 * We call this function when we detect an unhandled exception
4634 * in the default domain.
4636 * It invokes the * UnhandledException event in AppDomain or prints
4637 * a warning to the console
4640 mono_unhandled_exception (MonoObject *exc)
4642 MONO_REQ_GC_UNSAFE_MODE;
4645 MonoClassField *field;
4646 MonoDomain *current_domain, *root_domain;
4647 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4649 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4652 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4655 current_domain = mono_domain_get ();
4656 root_domain = mono_get_root_domain ();
4658 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4659 mono_error_assert_ok (&error);
4660 if (current_domain != root_domain) {
4661 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4662 mono_error_assert_ok (&error);
4665 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4666 mono_print_unhandled_exception (exc);
4668 if (root_appdomain_delegate)
4669 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4670 if (current_appdomain_delegate)
4671 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4674 /* set exitcode only if we will abort the process */
4675 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4676 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4678 mono_environment_exitcode_set (1);
4683 * mono_runtime_exec_managed_code:
4684 * @domain: Application domain
4685 * @main_func: function to invoke from the execution thread
4686 * @main_args: parameter to the main_func
4688 * Launch a new thread to execute a function
4690 * main_func is called back from the thread with main_args as the
4691 * parameter. The callback function is expected to start Main()
4692 * eventually. This function then waits for all managed threads to
4694 * It is not necesseray anymore to execute managed code in a subthread,
4695 * so this function should not be used anymore by default: just
4696 * execute the code and then call mono_thread_manage ().
4699 mono_runtime_exec_managed_code (MonoDomain *domain,
4700 MonoMainThreadFunc main_func,
4704 mono_thread_create_checked (domain, main_func, main_args, &error);
4705 mono_error_assert_ok (&error);
4707 mono_thread_manage ();
4711 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4713 MonoInternalThread* thread = mono_thread_internal_current ();
4714 MonoCustomAttrInfo* cinfo;
4715 gboolean has_stathread_attribute;
4717 if (!domain->entry_assembly) {
4719 MonoAssembly *assembly;
4721 assembly = method->klass->image->assembly;
4722 domain->entry_assembly = assembly;
4723 /* Domains created from another domain already have application_base and configuration_file set */
4724 if (domain->setup->application_base == NULL) {
4725 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4728 if (domain->setup->configuration_file == NULL) {
4729 str = g_strconcat (assembly->image->name, ".config", NULL);
4730 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4732 mono_domain_set_options_from_config (domain);
4736 MonoError cattr_error;
4737 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4738 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4740 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4742 mono_custom_attrs_free (cinfo);
4744 has_stathread_attribute = FALSE;
4746 if (has_stathread_attribute) {
4747 thread->apartment_state = ThreadApartmentState_STA;
4749 thread->apartment_state = ThreadApartmentState_MTA;
4751 mono_thread_init_apartment_state ();
4756 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4758 MONO_REQ_GC_UNSAFE_MODE;
4763 mono_error_init (error);
4768 /* FIXME: check signature of method */
4769 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4771 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4773 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4776 mono_environment_exitcode_set (rval);
4778 mono_runtime_invoke_checked (method, NULL, pa, error);
4783 /* If the return type of Main is void, only
4784 * set the exitcode if an exception was thrown
4785 * (we don't want to blow away an
4786 * explicitly-set exit code)
4789 mono_environment_exitcode_set (rval);
4796 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc, MonoError *error)
4798 MONO_REQ_GC_UNSAFE_MODE;
4803 mono_error_init (error);
4809 /* FIXME: check signature of method */
4810 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4812 res = mono_runtime_try_invoke (method, NULL, pa, exc, error);
4813 if (*exc == NULL && !mono_error_ok (error))
4814 *exc = (MonoObject*) mono_error_convert_to_exception (error);
4816 mono_error_cleanup (error);
4819 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4823 mono_environment_exitcode_set (rval);
4825 mono_runtime_try_invoke (method, NULL, pa, exc, error);
4826 if (*exc == NULL && !mono_error_ok (error))
4827 *exc = (MonoObject*) mono_error_convert_to_exception (error);
4829 mono_error_cleanup (error);
4834 /* If the return type of Main is void, only
4835 * set the exitcode if an exception was thrown
4836 * (we don't want to blow away an
4837 * explicitly-set exit code)
4840 mono_environment_exitcode_set (rval);
4848 * Execute a standard Main() method (args doesn't contain the
4852 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4855 prepare_thread_to_exec_main (mono_object_domain (args), method);
4857 int rval = do_try_exec_main (method, args, exc, &error);
4858 if (*exc == NULL && !is_ok (&error))
4859 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4861 mono_error_cleanup (&error);
4864 int rval = do_exec_main_checked (method, args, &error);
4865 mono_error_raise_exception (&error); /* OK to throw, external only with no better option */
4871 * Execute a standard Main() method (args doesn't contain the
4874 * On failure sets @error
4877 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4879 mono_error_init (error);
4880 prepare_thread_to_exec_main (mono_object_domain (args), method);
4881 return do_exec_main_checked (method, args, error);
4885 * Execute a standard Main() method (args doesn't contain the
4888 * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4891 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc, MonoError *error)
4893 mono_error_init (error);
4894 prepare_thread_to_exec_main (mono_object_domain (args), method);
4895 return do_try_exec_main (method, args, exc, error);
4900 /** invoke_array_extract_argument:
4901 * @params: array of arguments to the method.
4902 * @i: the index of the argument to extract.
4903 * @t: ith type from the method signature.
4904 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4905 * @error: set on error.
4907 * Given an array of method arguments, return the ith one using the corresponding type
4908 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4910 * On failure sets @error and returns NULL.
4913 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4915 MonoType *t_orig = t;
4916 gpointer result = NULL;
4917 mono_error_init (error);
4922 case MONO_TYPE_BOOLEAN:
4925 case MONO_TYPE_CHAR:
4934 case MONO_TYPE_VALUETYPE:
4935 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4936 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4937 result = mono_array_get (params, MonoObject*, i);
4939 *has_byref_nullables = TRUE;
4941 /* MS seems to create the objects if a null is passed in */
4942 if (!mono_array_get (params, MonoObject*, i)) {
4943 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4944 return_val_if_nok (error, NULL);
4945 mono_array_setref (params, i, o);
4950 * We can't pass the unboxed vtype byref to the callee, since
4951 * that would mean the callee would be able to modify boxed
4952 * primitive types. So we (and MS) make a copy of the boxed
4953 * object, pass that to the callee, and replace the original
4954 * boxed object in the arg array with the copy.
4956 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4957 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4958 return_val_if_nok (error, NULL);
4959 mono_array_setref (params, i, copy);
4962 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4965 case MONO_TYPE_STRING:
4966 case MONO_TYPE_OBJECT:
4967 case MONO_TYPE_CLASS:
4968 case MONO_TYPE_ARRAY:
4969 case MONO_TYPE_SZARRAY:
4971 result = mono_array_addr (params, MonoObject*, i);
4972 // FIXME: I need to check this code path
4974 result = mono_array_get (params, MonoObject*, i);
4976 case MONO_TYPE_GENERICINST:
4978 t = &t->data.generic_class->container_class->this_arg;
4980 t = &t->data.generic_class->container_class->byval_arg;
4982 case MONO_TYPE_PTR: {
4985 /* The argument should be an IntPtr */
4986 arg = mono_array_get (params, MonoObject*, i);
4990 g_assert (arg->vtable->klass == mono_defaults.int_class);
4991 result = ((MonoIntPtr*)arg)->m_value;
4996 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
5001 * mono_runtime_invoke_array:
5002 * @method: method to invoke
5003 * @obJ: object instance
5004 * @params: arguments to the method
5005 * @exc: exception information.
5007 * Invokes the method represented by @method on the object @obj.
5009 * obj is the 'this' pointer, it should be NULL for static
5010 * methods, a MonoObject* for object instances and a pointer to
5011 * the value type for value types.
5013 * The params array contains the arguments to the method with the
5014 * same convention: MonoObject* pointers for object instances and
5015 * pointers to the value type otherwise. The _invoke_array
5016 * variant takes a C# object[] as the params argument (MonoArray
5017 * *params): in this case the value types are boxed inside the
5018 * respective reference representation.
5020 * From unmanaged code you'll usually use the
5021 * mono_runtime_invoke_checked() variant.
5023 * Note that this function doesn't handle virtual methods for
5024 * you, it will exec the exact method you pass: we still need to
5025 * expose a function to lookup the derived class implementation
5026 * of a virtual method (there are examples of this in the code,
5029 * You can pass NULL as the exc argument if you don't want to
5030 * catch exceptions, otherwise, *exc will be set to the exception
5031 * thrown, if any. if an exception is thrown, you can't use the
5032 * MonoObject* result from the function.
5034 * If the method returns a value type, it is boxed in an object
5038 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5043 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
5045 mono_error_cleanup (&error);
5048 if (!is_ok (&error))
5049 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
5053 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
5054 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
5060 * mono_runtime_invoke_array_checked:
5061 * @method: method to invoke
5062 * @obJ: object instance
5063 * @params: arguments to the method
5064 * @error: set on failure.
5066 * Invokes the method represented by @method on the object @obj.
5068 * obj is the 'this' pointer, it should be NULL for static
5069 * methods, a MonoObject* for object instances and a pointer to
5070 * the value type for value types.
5072 * The params array contains the arguments to the method with the
5073 * same convention: MonoObject* pointers for object instances and
5074 * pointers to the value type otherwise. The _invoke_array
5075 * variant takes a C# object[] as the params argument (MonoArray
5076 * *params): in this case the value types are boxed inside the
5077 * respective reference representation.
5079 * From unmanaged code you'll usually use the
5080 * mono_runtime_invoke_checked() variant.
5082 * Note that this function doesn't handle virtual methods for
5083 * you, it will exec the exact method you pass: we still need to
5084 * expose a function to lookup the derived class implementation
5085 * of a virtual method (there are examples of this in the code,
5088 * On failure or exception, @error will be set. In that case, you
5089 * can't use the MonoObject* result from the function.
5091 * If the method returns a value type, it is boxed in an object
5095 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5098 mono_error_init (error);
5099 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5103 * mono_runtime_try_invoke_array:
5104 * @method: method to invoke
5105 * @obJ: object instance
5106 * @params: arguments to the method
5107 * @exc: exception information.
5108 * @error: set on failure.
5110 * Invokes the method represented by @method on the object @obj.
5112 * obj is the 'this' pointer, it should be NULL for static
5113 * methods, a MonoObject* for object instances and a pointer to
5114 * the value type for value types.
5116 * The params array contains the arguments to the method with the
5117 * same convention: MonoObject* pointers for object instances and
5118 * pointers to the value type otherwise. The _invoke_array
5119 * variant takes a C# object[] as the params argument (MonoArray
5120 * *params): in this case the value types are boxed inside the
5121 * respective reference representation.
5123 * From unmanaged code you'll usually use the
5124 * mono_runtime_invoke_checked() variant.
5126 * Note that this function doesn't handle virtual methods for
5127 * you, it will exec the exact method you pass: we still need to
5128 * expose a function to lookup the derived class implementation
5129 * of a virtual method (there are examples of this in the code,
5132 * You can pass NULL as the exc argument if you don't want to catch
5133 * exceptions, otherwise, *exc will be set to the exception thrown, if
5134 * any. On other failures, @error will be set. If an exception is
5135 * thrown or there's an error, you can't use the MonoObject* result
5136 * from the function.
5138 * If the method returns a value type, it is boxed in an object
5142 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5143 MonoObject **exc, MonoError *error)
5145 MONO_REQ_GC_UNSAFE_MODE;
5147 mono_error_init (error);
5149 MonoMethodSignature *sig = mono_method_signature (method);
5150 gpointer *pa = NULL;
5153 gboolean has_byref_nullables = FALSE;
5155 if (NULL != params) {
5156 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5157 for (i = 0; i < mono_array_length (params); i++) {
5158 MonoType *t = sig->params [i];
5159 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5160 return_val_if_nok (error, NULL);
5164 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5167 if (mono_class_is_nullable (method->klass)) {
5168 /* Need to create a boxed vtype instead */
5174 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5179 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5180 mono_error_assert_ok (error);
5181 g_assert (obj); /*maybe we should raise a TLE instead?*/
5182 #ifndef DISABLE_REMOTING
5183 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5184 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5187 if (method->klass->valuetype)
5188 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5191 } else if (method->klass->valuetype) {
5192 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5193 return_val_if_nok (error, NULL);
5197 mono_runtime_try_invoke (method, o, pa, exc, error);
5199 mono_runtime_invoke_checked (method, o, pa, error);
5202 return (MonoObject *)obj;
5204 if (mono_class_is_nullable (method->klass)) {
5205 MonoObject *nullable;
5207 /* Convert the unboxed vtype into a Nullable structure */
5208 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5209 return_val_if_nok (error, NULL);
5211 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5212 return_val_if_nok (error, NULL);
5213 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5214 obj = mono_object_unbox (nullable);
5217 /* obj must be already unboxed if needed */
5219 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5221 res = mono_runtime_invoke_checked (method, obj, pa, error);
5223 return_val_if_nok (error, NULL);
5225 if (sig->ret->type == MONO_TYPE_PTR) {
5226 MonoClass *pointer_class;
5227 static MonoMethod *box_method;
5229 MonoObject *box_exc;
5232 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5233 * convert it to a Pointer object.
5235 pointer_class = mono_class_get_pointer_class ();
5237 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5239 g_assert (res->vtable->klass == mono_defaults.int_class);
5240 box_args [0] = ((MonoIntPtr*)res)->m_value;
5241 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5242 return_val_if_nok (error, NULL);
5244 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5245 g_assert (box_exc == NULL);
5246 mono_error_assert_ok (error);
5249 if (has_byref_nullables) {
5251 * The runtime invoke wrapper already converted byref nullables back,
5252 * and stored them in pa, we just need to copy them back to the
5255 for (i = 0; i < mono_array_length (params); i++) {
5256 MonoType *t = sig->params [i];
5258 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5259 mono_array_setref (params, i, pa [i]);
5269 * @klass: the class of the object that we want to create
5271 * Returns: a newly created object whose definition is
5272 * looked up using @klass. This will not invoke any constructors,
5273 * so the consumer of this routine has to invoke any constructors on
5274 * its own to initialize the object.
5276 * It returns NULL on failure.
5279 mono_object_new (MonoDomain *domain, MonoClass *klass)
5281 MONO_REQ_GC_UNSAFE_MODE;
5285 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5287 mono_error_cleanup (&error);
5292 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5294 MONO_REQ_GC_UNSAFE_MODE;
5298 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5300 mono_error_set_pending_exception (&error);
5305 * mono_object_new_checked:
5306 * @klass: the class of the object that we want to create
5307 * @error: set on error
5309 * Returns: a newly created object whose definition is
5310 * looked up using @klass. This will not invoke any constructors,
5311 * so the consumer of this routine has to invoke any constructors on
5312 * its own to initialize the object.
5314 * It returns NULL on failure and sets @error.
5317 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5319 MONO_REQ_GC_UNSAFE_MODE;
5323 vtable = mono_class_vtable (domain, klass);
5324 g_assert (vtable); /* FIXME don't swallow the error */
5326 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5331 * mono_object_new_pinned:
5333 * Same as mono_object_new, but the returned object will be pinned.
5334 * For SGEN, these objects will only be freed at appdomain unload.
5337 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5339 MONO_REQ_GC_UNSAFE_MODE;
5343 mono_error_init (error);
5345 vtable = mono_class_vtable (domain, klass);
5346 g_assert (vtable); /* FIXME don't swallow the error */
5348 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5350 if (G_UNLIKELY (!o))
5351 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5352 else if (G_UNLIKELY (vtable->klass->has_finalize))
5353 mono_object_register_finalizer (o);
5359 * mono_object_new_specific:
5360 * @vtable: the vtable of the object that we want to create
5362 * Returns: A newly created object with class and domain specified
5366 mono_object_new_specific (MonoVTable *vtable)
5369 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5370 mono_error_cleanup (&error);
5376 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5378 MONO_REQ_GC_UNSAFE_MODE;
5382 mono_error_init (error);
5384 /* check for is_com_object for COM Interop */
5385 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5388 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5391 MonoClass *klass = mono_class_get_activation_services_class ();
5394 mono_class_init (klass);
5396 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5398 mono_error_set_not_supported (error, "Linked away.");
5401 vtable->domain->create_proxy_for_type_method = im;
5404 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5405 if (!mono_error_ok (error))
5408 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5409 if (!mono_error_ok (error))
5416 return mono_object_new_alloc_specific_checked (vtable, error);
5420 ves_icall_object_new_specific (MonoVTable *vtable)
5423 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5424 mono_error_set_pending_exception (&error);
5430 * mono_object_new_alloc_specific:
5431 * @vtable: virtual table for the object.
5433 * This function allocates a new `MonoObject` with the type derived
5434 * from the @vtable information. If the class of this object has a
5435 * finalizer, then the object will be tracked for finalization.
5437 * This method might raise an exception on errors. Use the
5438 * `mono_object_new_fast_checked` method if you want to manually raise
5441 * Returns: the allocated object.
5444 mono_object_new_alloc_specific (MonoVTable *vtable)
5447 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5448 mono_error_cleanup (&error);
5454 * mono_object_new_alloc_specific_checked:
5455 * @vtable: virtual table for the object.
5456 * @error: holds the error return value.
5458 * This function allocates a new `MonoObject` with the type derived
5459 * from the @vtable information. If the class of this object has a
5460 * finalizer, then the object will be tracked for finalization.
5462 * If there is not enough memory, the @error parameter will be set
5463 * and will contain a user-visible message with the amount of bytes
5464 * that were requested.
5466 * Returns: the allocated object, or NULL if there is not enough memory
5470 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5472 MONO_REQ_GC_UNSAFE_MODE;
5476 mono_error_init (error);
5478 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5480 if (G_UNLIKELY (!o))
5481 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5482 else if (G_UNLIKELY (vtable->klass->has_finalize))
5483 mono_object_register_finalizer (o);
5489 * mono_object_new_fast:
5490 * @vtable: virtual table for the object.
5492 * This function allocates a new `MonoObject` with the type derived
5493 * from the @vtable information. The returned object is not tracked
5494 * for finalization. If your object implements a finalizer, you should
5495 * use `mono_object_new_alloc_specific` instead.
5497 * This method might raise an exception on errors. Use the
5498 * `mono_object_new_fast_checked` method if you want to manually raise
5501 * Returns: the allocated object.
5504 mono_object_new_fast (MonoVTable *vtable)
5507 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5508 mono_error_cleanup (&error);
5514 * mono_object_new_fast_checked:
5515 * @vtable: virtual table for the object.
5516 * @error: holds the error return value.
5518 * This function allocates a new `MonoObject` with the type derived
5519 * from the @vtable information. The returned object is not tracked
5520 * for finalization. If your object implements a finalizer, you should
5521 * use `mono_object_new_alloc_specific_checked` instead.
5523 * If there is not enough memory, the @error parameter will be set
5524 * and will contain a user-visible message with the amount of bytes
5525 * that were requested.
5527 * Returns: the allocated object, or NULL if there is not enough memory
5531 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5533 MONO_REQ_GC_UNSAFE_MODE;
5537 mono_error_init (error);
5539 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5541 if (G_UNLIKELY (!o))
5542 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5548 ves_icall_object_new_fast (MonoVTable *vtable)
5551 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5552 mono_error_set_pending_exception (&error);
5558 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5560 MONO_REQ_GC_UNSAFE_MODE;
5564 mono_error_init (error);
5566 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5568 if (G_UNLIKELY (!o))
5569 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5570 else if (G_UNLIKELY (vtable->klass->has_finalize))
5571 mono_object_register_finalizer (o);
5577 * mono_class_get_allocation_ftn:
5579 * @for_box: the object will be used for boxing
5580 * @pass_size_in_words:
5582 * Return the allocation function appropriate for the given class.
5586 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5588 MONO_REQ_GC_NEUTRAL_MODE;
5590 *pass_size_in_words = FALSE;
5592 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5593 return ves_icall_object_new_specific;
5595 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5597 return ves_icall_object_new_fast;
5600 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5601 * of the overhead of parameter passing.
5604 *pass_size_in_words = TRUE;
5605 #ifdef GC_REDIRECT_TO_LOCAL
5606 return GC_local_gcj_fast_malloc;
5608 return GC_gcj_fast_malloc;
5613 return ves_icall_object_new_specific;
5617 * mono_object_new_from_token:
5618 * @image: Context where the type_token is hosted
5619 * @token: a token of the type that we want to create
5621 * Returns: A newly created object whose definition is
5622 * looked up using @token in the @image image
5625 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5627 MONO_REQ_GC_UNSAFE_MODE;
5633 klass = mono_class_get_checked (image, token, &error);
5634 mono_error_assert_ok (&error);
5636 result = mono_object_new_checked (domain, klass, &error);
5638 mono_error_cleanup (&error);
5645 * mono_object_clone:
5646 * @obj: the object to clone
5648 * Returns: A newly created object who is a shallow copy of @obj
5651 mono_object_clone (MonoObject *obj)
5654 MonoObject *o = mono_object_clone_checked (obj, &error);
5655 mono_error_cleanup (&error);
5661 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5663 MONO_REQ_GC_UNSAFE_MODE;
5668 mono_error_init (error);
5670 size = obj->vtable->klass->instance_size;
5672 if (obj->vtable->klass->rank)
5673 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5675 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5677 if (G_UNLIKELY (!o)) {
5678 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5682 /* If the object doesn't contain references this will do a simple memmove. */
5683 mono_gc_wbarrier_object_copy (o, obj);
5685 if (obj->vtable->klass->has_finalize)
5686 mono_object_register_finalizer (o);
5691 * mono_array_full_copy:
5692 * @src: source array to copy
5693 * @dest: destination array
5695 * Copies the content of one array to another with exactly the same type and size.
5698 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5700 MONO_REQ_GC_UNSAFE_MODE;
5703 MonoClass *klass = src->obj.vtable->klass;
5705 g_assert (klass == dest->obj.vtable->klass);
5707 size = mono_array_length (src);
5708 g_assert (size == mono_array_length (dest));
5709 size *= mono_array_element_size (klass);
5711 if (klass->element_class->valuetype) {
5712 if (klass->element_class->has_references)
5713 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5715 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5717 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5720 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5725 * mono_array_clone_in_domain:
5726 * @domain: the domain in which the array will be cloned into
5727 * @array: the array to clone
5728 * @error: set on error
5730 * This routine returns a copy of the array that is hosted on the
5731 * specified MonoDomain. On failure returns NULL and sets @error.
5734 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5736 MONO_REQ_GC_UNSAFE_MODE;
5741 MonoClass *klass = array->obj.vtable->klass;
5743 mono_error_init (error);
5745 if (array->bounds == NULL) {
5746 size = mono_array_length (array);
5747 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5748 return_val_if_nok (error, NULL);
5750 size *= mono_array_element_size (klass);
5752 if (klass->element_class->valuetype) {
5753 if (klass->element_class->has_references)
5754 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5756 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5758 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5761 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5766 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5767 size = mono_array_element_size (klass);
5768 for (i = 0; i < klass->rank; ++i) {
5769 sizes [i] = array->bounds [i].length;
5770 size *= array->bounds [i].length;
5771 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5773 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5774 return_val_if_nok (error, NULL);
5776 if (klass->element_class->valuetype) {
5777 if (klass->element_class->has_references)
5778 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5780 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5782 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5785 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5793 * @array: the array to clone
5795 * Returns: A newly created array who is a shallow copy of @array
5798 mono_array_clone (MonoArray *array)
5800 MONO_REQ_GC_UNSAFE_MODE;
5803 MonoArray *result = mono_array_clone_checked (array, &error);
5804 mono_error_cleanup (&error);
5809 * mono_array_clone_checked:
5810 * @array: the array to clone
5811 * @error: set on error
5813 * Returns: A newly created array who is a shallow copy of @array. On
5814 * failure returns NULL and sets @error.
5817 mono_array_clone_checked (MonoArray *array, MonoError *error)
5820 MONO_REQ_GC_UNSAFE_MODE;
5821 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5824 /* helper macros to check for overflow when calculating the size of arrays */
5825 #ifdef MONO_BIG_ARRAYS
5826 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5827 #define MYGUINT_MAX MYGUINT64_MAX
5828 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5829 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5830 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5831 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5832 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5834 #define MYGUINT32_MAX 4294967295U
5835 #define MYGUINT_MAX MYGUINT32_MAX
5836 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5837 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5838 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5839 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5840 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5844 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5846 MONO_REQ_GC_NEUTRAL_MODE;
5850 byte_len = mono_array_element_size (klass);
5851 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5854 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5856 byte_len += MONO_SIZEOF_MONO_ARRAY;
5864 * mono_array_new_full:
5865 * @domain: domain where the object is created
5866 * @array_class: array class
5867 * @lengths: lengths for each dimension in the array
5868 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5870 * This routine creates a new array objects with the given dimensions,
5871 * lower bounds and type.
5874 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5877 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5878 mono_error_cleanup (&error);
5884 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5886 MONO_REQ_GC_UNSAFE_MODE;
5888 uintptr_t byte_len = 0, len, bounds_size;
5891 MonoArrayBounds *bounds;
5895 mono_error_init (error);
5897 if (!array_class->inited)
5898 mono_class_init (array_class);
5902 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5903 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5905 if (len > MONO_ARRAY_MAX_INDEX) {
5906 mono_error_set_generic_error (error, "System", "OverflowException", "");
5911 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5913 for (i = 0; i < array_class->rank; ++i) {
5914 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5915 mono_error_set_generic_error (error, "System", "OverflowException", "");
5918 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5919 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5926 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5927 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5933 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5934 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5937 byte_len = (byte_len + 3) & ~3;
5938 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5939 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5942 byte_len += bounds_size;
5945 * Following three lines almost taken from mono_object_new ():
5946 * they need to be kept in sync.
5948 vtable = mono_class_vtable_full (domain, array_class, error);
5949 return_val_if_nok (error, NULL);
5952 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5954 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5956 if (G_UNLIKELY (!o)) {
5957 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5961 array = (MonoArray*)o;
5963 bounds = array->bounds;
5966 for (i = 0; i < array_class->rank; ++i) {
5967 bounds [i].length = lengths [i];
5969 bounds [i].lower_bound = lower_bounds [i];
5978 * @domain: domain where the object is created
5979 * @eclass: element class
5980 * @n: number of array elements
5982 * This routine creates a new szarray with @n elements of type @eclass.
5985 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5987 MONO_REQ_GC_UNSAFE_MODE;
5990 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5991 mono_error_cleanup (&error);
5996 * mono_array_new_checked:
5997 * @domain: domain where the object is created
5998 * @eclass: element class
5999 * @n: number of array elements
6000 * @error: set on error
6002 * This routine creates a new szarray with @n elements of type @eclass.
6003 * On failure returns NULL and sets @error.
6006 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
6010 mono_error_init (error);
6012 ac = mono_array_class_get (eclass, 1);
6015 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
6016 return_val_if_nok (error, NULL);
6018 return mono_array_new_specific_checked (vtable, n, error);
6022 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6025 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
6026 mono_error_set_pending_exception (&error);
6032 * mono_array_new_specific:
6033 * @vtable: a vtable in the appropriate domain for an initialized class
6034 * @n: number of array elements
6036 * This routine is a fast alternative to mono_array_new() for code which
6037 * can be sure about the domain it operates in.
6040 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
6043 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6044 mono_error_cleanup (&error);
6050 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
6052 MONO_REQ_GC_UNSAFE_MODE;
6057 mono_error_init (error);
6059 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6060 mono_error_set_generic_error (error, "System", "OverflowException", "");
6064 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6065 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6068 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6070 if (G_UNLIKELY (!o)) {
6071 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
6075 return (MonoArray*)o;
6079 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6082 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6083 mono_error_set_pending_exception (&error);
6089 * mono_string_new_utf16:
6090 * @text: a pointer to an utf16 string
6091 * @len: the length of the string
6093 * Returns: A newly created string object which contains @text.
6096 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6098 MONO_REQ_GC_UNSAFE_MODE;
6101 MonoString *res = NULL;
6102 res = mono_string_new_utf16_checked (domain, text, len, &error);
6103 mono_error_cleanup (&error);
6109 * mono_string_new_utf16_checked:
6110 * @text: a pointer to an utf16 string
6111 * @len: the length of the string
6112 * @error: written on error.
6114 * Returns: A newly created string object which contains @text.
6115 * On error, returns NULL and sets @error.
6118 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6120 MONO_REQ_GC_UNSAFE_MODE;
6124 mono_error_init (error);
6126 s = mono_string_new_size_checked (domain, len, error);
6128 memcpy (mono_string_chars (s), text, len * 2);
6134 * mono_string_new_utf32:
6135 * @text: a pointer to an utf32 string
6136 * @len: the length of the string
6137 * @error: set on failure.
6139 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6142 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6144 MONO_REQ_GC_UNSAFE_MODE;
6147 mono_unichar2 *utf16_output = NULL;
6148 gint32 utf16_len = 0;
6149 GError *gerror = NULL;
6150 glong items_written;
6152 mono_error_init (error);
6153 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6156 g_error_free (gerror);
6158 while (utf16_output [utf16_len]) utf16_len++;
6160 s = mono_string_new_size_checked (domain, utf16_len, error);
6161 return_val_if_nok (error, NULL);
6163 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6165 g_free (utf16_output);
6171 * mono_string_new_utf32:
6172 * @text: a pointer to an utf32 string
6173 * @len: the length of the string
6175 * Returns: A newly created string object which contains @text.
6178 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6181 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6182 mono_error_cleanup (&error);
6187 * mono_string_new_size:
6188 * @text: a pointer to an utf16 string
6189 * @len: the length of the string
6191 * Returns: A newly created string object of @len
6194 mono_string_new_size (MonoDomain *domain, gint32 len)
6197 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6198 mono_error_cleanup (&error);
6204 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6206 MONO_REQ_GC_UNSAFE_MODE;
6212 mono_error_init (error);
6214 /* check for overflow */
6215 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6216 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6220 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6221 g_assert (size > 0);
6223 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6226 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6228 if (G_UNLIKELY (!s)) {
6229 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6237 * mono_string_new_len:
6238 * @text: a pointer to an utf8 string
6239 * @length: number of bytes in @text to consider
6241 * Returns: A newly created string object which contains @text.
6244 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6246 MONO_REQ_GC_UNSAFE_MODE;
6249 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6250 mono_error_cleanup (&error);
6255 * mono_string_new_len_checked:
6256 * @text: a pointer to an utf8 string
6257 * @length: number of bytes in @text to consider
6258 * @error: set on error
6260 * Returns: A newly created string object which contains @text. On
6261 * failure returns NULL and sets @error.
6264 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6266 MONO_REQ_GC_UNSAFE_MODE;
6268 mono_error_init (error);
6270 GError *eg_error = NULL;
6271 MonoString *o = NULL;
6273 glong items_written;
6275 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6278 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6280 g_error_free (eg_error);
6289 * @text: a pointer to an utf8 string
6291 * Returns: A newly created string object which contains @text.
6293 * This function asserts if it cannot allocate a new string.
6295 * @deprecated Use mono_string_new_checked in new code.
6298 mono_string_new (MonoDomain *domain, const char *text)
6301 MonoString *res = NULL;
6302 res = mono_string_new_checked (domain, text, &error);
6303 mono_error_assert_ok (&error);
6308 * mono_string_new_checked:
6309 * @text: a pointer to an utf8 string
6310 * @merror: set on error
6312 * Returns: A newly created string object which contains @text.
6313 * On error returns NULL and sets @merror.
6316 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6318 MONO_REQ_GC_UNSAFE_MODE;
6320 GError *eg_error = NULL;
6321 MonoString *o = NULL;
6323 glong items_written;
6326 mono_error_init (error);
6330 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6333 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6335 g_error_free (eg_error);
6339 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6344 MonoString *o = NULL;
6346 if (!g_utf8_validate (text, -1, &end)) {
6347 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6351 len = g_utf8_strlen (text, -1);
6352 o = mono_string_new_size_checked (domain, len, error);
6355 str = mono_string_chars (o);
6357 while (text < end) {
6358 *str++ = g_utf8_get_char (text);
6359 text = g_utf8_next_char (text);
6368 * mono_string_new_wrapper:
6369 * @text: pointer to utf8 characters.
6371 * Helper function to create a string object from @text in the current domain.
6374 mono_string_new_wrapper (const char *text)
6376 MONO_REQ_GC_UNSAFE_MODE;
6378 MonoDomain *domain = mono_domain_get ();
6381 return mono_string_new (domain, text);
6388 * @class: the class of the value
6389 * @value: a pointer to the unboxed data
6391 * Returns: A newly created object which contains @value.
6394 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6397 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6398 mono_error_cleanup (&error);
6403 * mono_value_box_checked:
6404 * @domain: the domain of the new object
6405 * @class: the class of the value
6406 * @value: a pointer to the unboxed data
6407 * @error: set on error
6409 * Returns: A newly created object which contains @value. On failure
6410 * returns NULL and sets @error.
6413 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6415 MONO_REQ_GC_UNSAFE_MODE;
6420 mono_error_init (error);
6422 g_assert (klass->valuetype);
6423 if (mono_class_is_nullable (klass))
6424 return mono_nullable_box ((guint8 *)value, klass, error);
6426 vtable = mono_class_vtable (domain, klass);
6429 size = mono_class_instance_size (klass);
6430 res = mono_object_new_alloc_specific_checked (vtable, error);
6431 return_val_if_nok (error, NULL);
6433 size = size - sizeof (MonoObject);
6436 g_assert (size == mono_class_value_size (klass, NULL));
6437 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6439 #if NO_UNALIGNED_ACCESS
6440 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6444 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6447 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6450 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6453 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6456 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6460 if (klass->has_finalize) {
6461 mono_object_register_finalizer (res);
6462 return_val_if_nok (error, NULL);
6469 * @dest: destination pointer
6470 * @src: source pointer
6471 * @klass: a valuetype class
6473 * Copy a valuetype from @src to @dest. This function must be used
6474 * when @klass contains references fields.
6477 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6479 MONO_REQ_GC_UNSAFE_MODE;
6481 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6485 * mono_value_copy_array:
6486 * @dest: destination array
6487 * @dest_idx: index in the @dest array
6488 * @src: source pointer
6489 * @count: number of items
6491 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6492 * This function must be used when @klass contains references fields.
6493 * Overlap is handled.
6496 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6498 MONO_REQ_GC_UNSAFE_MODE;
6500 int size = mono_array_element_size (dest->obj.vtable->klass);
6501 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6502 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6503 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6507 * mono_object_get_domain:
6508 * @obj: object to query
6510 * Returns: the MonoDomain where the object is hosted
6513 mono_object_get_domain (MonoObject *obj)
6515 MONO_REQ_GC_UNSAFE_MODE;
6517 return mono_object_domain (obj);
6521 * mono_object_get_class:
6522 * @obj: object to query
6524 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6526 * Returns: the MonoClass of the object.
6529 mono_object_get_class (MonoObject *obj)
6531 MONO_REQ_GC_UNSAFE_MODE;
6533 return mono_object_class (obj);
6536 * mono_object_get_size:
6537 * @o: object to query
6539 * Returns: the size, in bytes, of @o
6542 mono_object_get_size (MonoObject* o)
6544 MONO_REQ_GC_UNSAFE_MODE;
6546 MonoClass* klass = mono_object_class (o);
6547 if (klass == mono_defaults.string_class) {
6548 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6549 } else if (o->vtable->rank) {
6550 MonoArray *array = (MonoArray*)o;
6551 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6552 if (array->bounds) {
6555 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6559 return mono_class_instance_size (klass);
6564 * mono_object_unbox:
6565 * @obj: object to unbox
6567 * Returns: a pointer to the start of the valuetype boxed in this
6570 * This method will assert if the object passed is not a valuetype.
6573 mono_object_unbox (MonoObject *obj)
6575 MONO_REQ_GC_UNSAFE_MODE;
6577 /* add assert for valuetypes? */
6578 g_assert (obj->vtable->klass->valuetype);
6579 return ((char*)obj) + sizeof (MonoObject);
6583 * mono_object_isinst:
6585 * @klass: a pointer to a class
6587 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6590 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6592 MONO_REQ_GC_UNSAFE_MODE;
6595 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6596 mono_error_cleanup (&error);
6602 * mono_object_isinst_checked:
6604 * @klass: a pointer to a class
6605 * @error: set on error
6607 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6608 * On failure returns NULL and sets @error.
6611 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6613 MONO_REQ_GC_UNSAFE_MODE;
6615 mono_error_init (error);
6617 MonoObject *result = NULL;
6620 mono_class_init (klass);
6622 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6623 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6630 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6634 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6636 MONO_REQ_GC_UNSAFE_MODE;
6639 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6640 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6645 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6647 MONO_REQ_GC_UNSAFE_MODE;
6651 mono_error_init (error);
6658 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6659 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6663 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6664 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6667 MonoClass *oklass = vt->klass;
6668 if (mono_class_is_transparent_proxy (oklass))
6669 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6671 mono_class_setup_supertypes (klass);
6672 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6675 #ifndef DISABLE_REMOTING
6676 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6678 MonoDomain *domain = mono_domain_get ();
6680 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6681 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6682 MonoMethod *im = NULL;
6685 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6687 mono_error_set_not_supported (error, "Linked away.");
6690 im = mono_object_get_virtual_method (rp, im);
6693 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6694 return_val_if_nok (error, NULL);
6697 res = mono_runtime_invoke_checked (im, rp, pa, error);
6698 return_val_if_nok (error, NULL);
6700 if (*(MonoBoolean *) mono_object_unbox(res)) {
6701 /* Update the vtable of the remote type, so it can safely cast to this new type */
6702 mono_upgrade_remote_class (domain, obj, klass, error);
6703 return_val_if_nok (error, NULL);
6707 #endif /* DISABLE_REMOTING */
6712 * mono_object_castclass_mbyref:
6714 * @klass: a pointer to a class
6716 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6719 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6721 MONO_REQ_GC_UNSAFE_MODE;
6724 if (!obj) return NULL;
6725 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6726 mono_error_cleanup (&error);
6731 MonoDomain *orig_domain;
6737 str_lookup (MonoDomain *domain, gpointer user_data)
6739 MONO_REQ_GC_UNSAFE_MODE;
6741 LDStrInfo *info = (LDStrInfo *)user_data;
6742 if (info->res || domain == info->orig_domain)
6744 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6748 mono_string_get_pinned (MonoString *str, MonoError *error)
6750 MONO_REQ_GC_UNSAFE_MODE;
6752 mono_error_init (error);
6754 /* We only need to make a pinned version of a string if this is a moving GC */
6755 if (!mono_gc_is_moving ())
6759 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6760 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6762 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6763 news->length = mono_string_length (str);
6765 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6771 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6773 MONO_REQ_GC_UNSAFE_MODE;
6775 MonoGHashTable *ldstr_table;
6776 MonoString *s, *res;
6779 mono_error_init (error);
6781 domain = ((MonoObject *)str)->vtable->domain;
6782 ldstr_table = domain->ldstr_table;
6784 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6790 /* Allocate outside the lock */
6792 s = mono_string_get_pinned (str, error);
6793 return_val_if_nok (error, NULL);
6796 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6801 mono_g_hash_table_insert (ldstr_table, s, s);
6806 LDStrInfo ldstr_info;
6807 ldstr_info.orig_domain = domain;
6808 ldstr_info.ins = str;
6809 ldstr_info.res = NULL;
6811 mono_domain_foreach (str_lookup, &ldstr_info);
6812 if (ldstr_info.res) {
6814 * the string was already interned in some other domain:
6815 * intern it in the current one as well.
6817 mono_g_hash_table_insert (ldstr_table, str, str);
6827 * mono_string_is_interned:
6828 * @o: String to probe
6830 * Returns whether the string has been interned.
6833 mono_string_is_interned (MonoString *o)
6836 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6837 /* This function does not fail. */
6838 mono_error_assert_ok (&error);
6843 * mono_string_intern:
6844 * @o: String to intern
6846 * Interns the string passed.
6847 * Returns: The interned string.
6850 mono_string_intern (MonoString *str)
6853 MonoString *result = mono_string_intern_checked (str, &error);
6854 mono_error_assert_ok (&error);
6859 * mono_string_intern_checked:
6860 * @o: String to intern
6861 * @error: set on error.
6863 * Interns the string passed.
6864 * Returns: The interned string. On failure returns NULL and sets @error
6867 mono_string_intern_checked (MonoString *str, MonoError *error)
6869 MONO_REQ_GC_UNSAFE_MODE;
6871 mono_error_init (error);
6873 return mono_string_is_interned_lookup (str, TRUE, error);
6878 * @domain: the domain where the string will be used.
6879 * @image: a metadata context
6880 * @idx: index into the user string table.
6882 * Implementation for the ldstr opcode.
6883 * Returns: a loaded string from the @image/@idx combination.
6886 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6889 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6890 mono_error_cleanup (&error);
6895 * mono_ldstr_checked:
6896 * @domain: the domain where the string will be used.
6897 * @image: a metadata context
6898 * @idx: index into the user string table.
6899 * @error: set on error.
6901 * Implementation for the ldstr opcode.
6902 * Returns: a loaded string from the @image/@idx combination.
6903 * On failure returns NULL and sets @error.
6906 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6908 MONO_REQ_GC_UNSAFE_MODE;
6909 mono_error_init (error);
6911 if (image->dynamic) {
6912 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6915 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6916 return NULL; /*FIXME we should probably be raising an exception here*/
6917 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6923 * mono_ldstr_metadata_sig
6924 * @domain: the domain for the string
6925 * @sig: the signature of a metadata string
6926 * @error: set on error
6928 * Returns: a MonoString for a string stored in the metadata. On
6929 * failure returns NULL and sets @error.
6932 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6934 MONO_REQ_GC_UNSAFE_MODE;
6936 mono_error_init (error);
6937 const char *str = sig;
6938 MonoString *o, *interned;
6941 len2 = mono_metadata_decode_blob_size (str, &str);
6944 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6945 return_val_if_nok (error, NULL);
6946 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6949 guint16 *p2 = (guint16*)mono_string_chars (o);
6950 for (i = 0; i < len2; ++i) {
6951 *p2 = GUINT16_FROM_LE (*p2);
6957 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6960 return interned; /* o will get garbage collected */
6962 o = mono_string_get_pinned (o, error);
6965 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6967 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6979 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6983 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6989 GError *gerror = NULL;
6991 mono_error_init (error);
6993 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6994 return NULL; /*FIXME we should probably be raising an exception here*/
6995 str = mono_metadata_user_string (image, idx);
6997 len2 = mono_metadata_decode_blob_size (str, &str);
7000 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
7002 mono_error_set_argument (error, "string", "%s", gerror->message);
7003 g_error_free (gerror);
7006 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7007 if (len2 > written) {
7008 /* allocate the total length and copy the part of the string that has been converted */
7009 char *as2 = (char *)g_malloc0 (len2);
7010 memcpy (as2, as, written);
7019 * mono_string_to_utf8:
7020 * @s: a System.String
7022 * Returns the UTF8 representation for @s.
7023 * The resulting buffer needs to be freed with mono_free().
7025 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7028 mono_string_to_utf8 (MonoString *s)
7030 MONO_REQ_GC_UNSAFE_MODE;
7033 char *result = mono_string_to_utf8_checked (s, &error);
7035 if (!is_ok (&error)) {
7036 mono_error_cleanup (&error);
7043 * mono_string_to_utf8_checked:
7044 * @s: a System.String
7045 * @error: a MonoError.
7047 * Converts a MonoString to its UTF8 representation. May fail; check
7048 * @error to determine whether the conversion was successful.
7049 * The resulting buffer should be freed with mono_free().
7052 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7054 MONO_REQ_GC_UNSAFE_MODE;
7058 GError *gerror = NULL;
7060 mono_error_init (error);
7066 return g_strdup ("");
7068 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7070 mono_error_set_argument (error, "string", "%s", gerror->message);
7071 g_error_free (gerror);
7074 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7075 if (s->length > written) {
7076 /* allocate the total length and copy the part of the string that has been converted */
7077 char *as2 = (char *)g_malloc0 (s->length);
7078 memcpy (as2, as, written);
7087 * mono_string_to_utf8_ignore:
7090 * Converts a MonoString to its UTF8 representation. Will ignore
7091 * invalid surrogate pairs.
7092 * The resulting buffer should be freed with mono_free().
7096 mono_string_to_utf8_ignore (MonoString *s)
7098 MONO_REQ_GC_UNSAFE_MODE;
7107 return g_strdup ("");
7109 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7111 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7112 if (s->length > written) {
7113 /* allocate the total length and copy the part of the string that has been converted */
7114 char *as2 = (char *)g_malloc0 (s->length);
7115 memcpy (as2, as, written);
7124 * mono_string_to_utf8_image_ignore:
7125 * @s: a System.String
7127 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7130 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7132 MONO_REQ_GC_UNSAFE_MODE;
7134 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7138 * mono_string_to_utf8_mp_ignore:
7139 * @s: a System.String
7141 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7144 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7146 MONO_REQ_GC_UNSAFE_MODE;
7148 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7153 * mono_string_to_utf16:
7156 * Return an null-terminated array of the utf-16 chars
7157 * contained in @s. The result must be freed with g_free().
7158 * This is a temporary helper until our string implementation
7159 * is reworked to always include the null terminating char.
7162 mono_string_to_utf16 (MonoString *s)
7164 MONO_REQ_GC_UNSAFE_MODE;
7171 as = (char *)g_malloc ((s->length * 2) + 2);
7172 as [(s->length * 2)] = '\0';
7173 as [(s->length * 2) + 1] = '\0';
7176 return (gunichar2 *)(as);
7179 memcpy (as, mono_string_chars(s), s->length * 2);
7180 return (gunichar2 *)(as);
7184 * mono_string_to_utf32:
7187 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7188 * contained in @s. The result must be freed with g_free().
7191 mono_string_to_utf32 (MonoString *s)
7193 MONO_REQ_GC_UNSAFE_MODE;
7195 mono_unichar4 *utf32_output = NULL;
7196 GError *error = NULL;
7197 glong items_written;
7202 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7205 g_error_free (error);
7207 return utf32_output;
7211 * mono_string_from_utf16:
7212 * @data: the UTF16 string (LPWSTR) to convert
7214 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7216 * Returns: a MonoString.
7219 mono_string_from_utf16 (gunichar2 *data)
7222 MonoString *result = mono_string_from_utf16_checked (data, &error);
7223 mono_error_cleanup (&error);
7228 * mono_string_from_utf16_checked:
7229 * @data: the UTF16 string (LPWSTR) to convert
7230 * @error: set on error
7232 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7234 * Returns: a MonoString. On failure sets @error and returns NULL.
7237 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7240 MONO_REQ_GC_UNSAFE_MODE;
7242 mono_error_init (error);
7243 MonoDomain *domain = mono_domain_get ();
7249 while (data [len]) len++;
7251 return mono_string_new_utf16_checked (domain, data, len, error);
7255 * mono_string_from_utf32:
7256 * @data: the UTF32 string (LPWSTR) to convert
7258 * Converts a UTF32 (UCS-4)to a MonoString.
7260 * Returns: a MonoString.
7263 mono_string_from_utf32 (mono_unichar4 *data)
7266 MonoString *result = mono_string_from_utf32_checked (data, &error);
7267 mono_error_cleanup (&error);
7272 * mono_string_from_utf32_checked:
7273 * @data: the UTF32 string (LPWSTR) to convert
7274 * @error: set on error
7276 * Converts a UTF32 (UCS-4)to a MonoString.
7278 * Returns: a MonoString. On failure returns NULL and sets @error.
7281 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7283 MONO_REQ_GC_UNSAFE_MODE;
7285 mono_error_init (error);
7286 MonoString* result = NULL;
7287 mono_unichar2 *utf16_output = NULL;
7288 GError *gerror = NULL;
7289 glong items_written;
7295 while (data [len]) len++;
7297 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7300 g_error_free (gerror);
7302 result = mono_string_from_utf16_checked (utf16_output, error);
7303 g_free (utf16_output);
7308 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7310 MONO_REQ_GC_UNSAFE_MODE;
7317 r = mono_string_to_utf8_ignore (s);
7319 r = mono_string_to_utf8_checked (s, error);
7320 if (!mono_error_ok (error))
7327 len = strlen (r) + 1;
7329 mp_s = (char *)mono_mempool_alloc (mp, len);
7331 mp_s = (char *)mono_image_alloc (image, len);
7333 memcpy (mp_s, r, len);
7341 * mono_string_to_utf8_image:
7342 * @s: a System.String
7344 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7347 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7349 MONO_REQ_GC_UNSAFE_MODE;
7351 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7355 * mono_string_to_utf8_mp:
7356 * @s: a System.String
7358 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7361 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7363 MONO_REQ_GC_UNSAFE_MODE;
7365 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7369 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7372 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7374 eh_callbacks = *cbs;
7377 MonoRuntimeExceptionHandlingCallbacks *
7378 mono_get_eh_callbacks (void)
7380 return &eh_callbacks;
7384 * mono_raise_exception:
7385 * @ex: exception object
7387 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7390 mono_raise_exception (MonoException *ex)
7392 MONO_REQ_GC_UNSAFE_MODE;
7395 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7396 * that will cause gcc to omit the function epilog, causing problems when
7397 * the JIT tries to walk the stack, since the return address on the stack
7398 * will point into the next function in the executable, not this one.
7400 eh_callbacks.mono_raise_exception (ex);
7404 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7406 MONO_REQ_GC_UNSAFE_MODE;
7408 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7412 * mono_wait_handle_new:
7413 * @domain: Domain where the object will be created
7414 * @handle: Handle for the wait handle
7415 * @error: set on error.
7417 * Returns: A new MonoWaitHandle created in the given domain for the
7418 * given handle. On failure returns NULL and sets @rror.
7421 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7423 MONO_REQ_GC_UNSAFE_MODE;
7425 MonoWaitHandle *res;
7426 gpointer params [1];
7427 static MonoMethod *handle_set;
7429 mono_error_init (error);
7430 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7431 return_val_if_nok (error, NULL);
7433 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7435 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7437 params [0] = &handle;
7439 mono_runtime_invoke_checked (handle_set, res, params, error);
7444 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7446 MONO_REQ_GC_UNSAFE_MODE;
7448 static MonoClassField *f_safe_handle = NULL;
7451 if (!f_safe_handle) {
7452 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7453 g_assert (f_safe_handle);
7456 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7462 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7464 MONO_REQ_GC_UNSAFE_MODE;
7466 RuntimeInvokeFunction runtime_invoke;
7468 mono_error_init (error);
7470 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7471 MonoMethod *method = mono_get_context_capture_method ();
7472 MonoMethod *wrapper;
7475 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7476 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7477 return_val_if_nok (error, NULL);
7478 domain->capture_context_method = mono_compile_method_checked (method, error);
7479 return_val_if_nok (error, NULL);
7482 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7484 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7487 * mono_async_result_new:
7488 * @domain:domain where the object will be created.
7489 * @handle: wait handle.
7490 * @state: state to pass to AsyncResult
7491 * @data: C closure data.
7492 * @error: set on error.
7494 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7495 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7496 * On failure returns NULL and sets @error.
7500 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7502 MONO_REQ_GC_UNSAFE_MODE;
7504 mono_error_init (error);
7505 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7506 return_val_if_nok (error, NULL);
7507 MonoObject *context = mono_runtime_capture_context (domain, error);
7508 return_val_if_nok (error, NULL);
7509 /* we must capture the execution context from the original thread */
7511 MONO_OBJECT_SETREF (res, execution_context, context);
7512 /* note: result may be null if the flow is suppressed */
7515 res->data = (void **)data;
7516 MONO_OBJECT_SETREF (res, object_data, object_data);
7517 MONO_OBJECT_SETREF (res, async_state, state);
7518 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7519 return_val_if_nok (error, NULL);
7521 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7523 res->sync_completed = FALSE;
7524 res->completed = FALSE;
7530 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7532 MONO_REQ_GC_UNSAFE_MODE;
7539 g_assert (ares->async_delegate);
7541 ac = (MonoAsyncCall*) ares->object_data;
7543 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7544 if (mono_error_set_pending_exception (&error))
7547 gpointer wait_event = NULL;
7549 ac->msg->exc = NULL;
7550 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7551 if (mono_error_set_pending_exception (&error))
7553 MONO_OBJECT_SETREF (ac, res, res);
7555 mono_monitor_enter ((MonoObject*) ares);
7556 ares->completed = 1;
7558 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7559 mono_monitor_exit ((MonoObject*) ares);
7561 if (wait_event != NULL)
7562 SetEvent (wait_event);
7564 if (ac->cb_method) {
7565 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7566 if (mono_error_set_pending_exception (&error))
7575 mono_message_init (MonoDomain *domain,
7576 MonoMethodMessage *this_obj,
7577 MonoReflectionMethod *method,
7578 MonoArray *out_args,
7581 MONO_REQ_GC_UNSAFE_MODE;
7583 static MonoClass *object_array_klass;
7584 static MonoClass *byte_array_klass;
7585 static MonoClass *string_array_klass;
7586 mono_error_init (error);
7587 MonoMethodSignature *sig = mono_method_signature (method->method);
7594 if (!object_array_klass) {
7597 klass = mono_array_class_get (mono_defaults.byte_class, 1);
7599 byte_array_klass = klass;
7601 klass = mono_array_class_get (mono_defaults.string_class, 1);
7603 string_array_klass = klass;
7605 klass = mono_array_class_get (mono_defaults.object_class, 1);
7608 mono_atomic_store_release (&object_array_klass, klass);
7611 MONO_OBJECT_SETREF (this_obj, method, method);
7613 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, error);
7614 return_val_if_nok (error, FALSE);
7616 MONO_OBJECT_SETREF (this_obj, args, arr);
7618 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, error);
7619 return_val_if_nok (error, FALSE);
7621 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
7623 this_obj->async_result = NULL;
7624 this_obj->call_type = CallType_Sync;
7626 names = g_new (char *, sig->param_count);
7627 mono_method_get_param_names (method->method, (const char **) names);
7629 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, error);
7633 MONO_OBJECT_SETREF (this_obj, names, arr);
7635 for (i = 0; i < sig->param_count; i++) {
7636 name = mono_string_new_checked (domain, names [i], error);
7639 mono_array_setref (this_obj->names, i, name);
7643 for (i = 0, j = 0; i < sig->param_count; i++) {
7644 if (sig->params [i]->byref) {
7646 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
7647 mono_array_setref (this_obj->args, i, arg);
7651 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
7655 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
7658 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
7667 #ifndef DISABLE_REMOTING
7669 * mono_remoting_invoke:
7670 * @real_proxy: pointer to a RealProxy object
7671 * @msg: The MonoMethodMessage to execute
7672 * @exc: used to store exceptions
7673 * @out_args: used to store output arguments
7675 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7676 * IMessage interface and it is not trivial to extract results from there. So
7677 * we call an helper method PrivateInvoke instead of calling
7678 * RealProxy::Invoke() directly.
7680 * Returns: the result object.
7683 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7685 MONO_REQ_GC_UNSAFE_MODE;
7688 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7693 mono_error_init (error);
7695 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7698 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7700 mono_error_set_not_supported (error, "Linked away.");
7703 real_proxy->vtable->domain->private_invoke_method = im;
7706 pa [0] = real_proxy;
7711 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7712 return_val_if_nok (error, NULL);
7719 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7720 MonoObject **exc, MonoArray **out_args, MonoError *error)
7722 MONO_REQ_GC_UNSAFE_MODE;
7724 static MonoClass *object_array_klass;
7725 mono_error_init (error);
7729 MonoMethodSignature *sig;
7731 int i, j, outarg_count = 0;
7733 #ifndef DISABLE_REMOTING
7734 if (target && mono_object_is_transparent_proxy (target)) {
7735 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7736 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7737 target = tp->rp->unwrapped_server;
7739 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7744 domain = mono_domain_get ();
7745 method = msg->method->method;
7746 sig = mono_method_signature (method);
7748 for (i = 0; i < sig->param_count; i++) {
7749 if (sig->params [i]->byref)
7753 if (!object_array_klass) {
7756 klass = mono_array_class_get (mono_defaults.object_class, 1);
7759 mono_memory_barrier ();
7760 object_array_klass = klass;
7763 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7764 return_val_if_nok (error, NULL);
7766 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7769 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7770 return_val_if_nok (error, NULL);
7772 for (i = 0, j = 0; i < sig->param_count; i++) {
7773 if (sig->params [i]->byref) {
7775 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7776 mono_array_setref (*out_args, j, arg);
7785 * prepare_to_string_method:
7787 * @target: Set to @obj or unboxed value if a valuetype
7789 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7792 prepare_to_string_method (MonoObject *obj, void **target)
7794 MONO_REQ_GC_UNSAFE_MODE;
7796 static MonoMethod *to_string = NULL;
7804 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7806 method = mono_object_get_virtual_method (obj, to_string);
7808 // Unbox value type if needed
7809 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7810 *target = mono_object_unbox (obj);
7816 * mono_object_to_string:
7818 * @exc: Any exception thrown by ToString (). May be NULL.
7820 * Returns: the result of calling ToString () on an object.
7823 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7826 MonoString *s = NULL;
7828 MonoMethod *method = prepare_to_string_method (obj, &target);
7830 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7831 if (*exc == NULL && !mono_error_ok (&error))
7832 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7834 mono_error_cleanup (&error);
7836 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7837 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7844 * mono_object_to_string_checked:
7846 * @error: Set on error.
7848 * Returns: the result of calling ToString () on an object. If the
7849 * method cannot be invoked or if it raises an exception, sets @error
7853 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7855 mono_error_init (error);
7857 MonoMethod *method = prepare_to_string_method (obj, &target);
7858 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7862 * mono_object_try_to_string:
7864 * @exc: Any exception thrown by ToString (). Must not be NULL.
7865 * @error: Set if method cannot be invoked.
7867 * Returns: the result of calling ToString () on an object. If the
7868 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7872 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7875 mono_error_init (error);
7877 MonoMethod *method = prepare_to_string_method (obj, &target);
7878 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7884 * mono_print_unhandled_exception:
7885 * @exc: The exception
7887 * Prints the unhandled exception.
7890 mono_print_unhandled_exception (MonoObject *exc)
7892 MONO_REQ_GC_UNSAFE_MODE;
7895 char *message = (char*)"";
7896 gboolean free_message = FALSE;
7899 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7900 message = g_strdup ("OutOfMemoryException");
7901 free_message = TRUE;
7902 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7903 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7904 free_message = TRUE;
7907 if (((MonoException*)exc)->native_trace_ips) {
7908 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7909 free_message = TRUE;
7911 MonoObject *other_exc = NULL;
7912 str = mono_object_try_to_string (exc, &other_exc, &error);
7913 if (other_exc == NULL && !is_ok (&error))
7914 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7916 mono_error_cleanup (&error);
7918 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7919 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7921 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7922 original_backtrace, nested_backtrace);
7924 g_free (original_backtrace);
7925 g_free (nested_backtrace);
7926 free_message = TRUE;
7928 message = mono_string_to_utf8_checked (str, &error);
7929 if (!mono_error_ok (&error)) {
7930 mono_error_cleanup (&error);
7931 message = (char *) "";
7933 free_message = TRUE;
7940 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7941 * exc->vtable->klass->name, message);
7943 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7950 * mono_delegate_ctor_with_method:
7951 * @this: pointer to an uninitialized delegate object
7952 * @target: target object
7953 * @addr: pointer to native code
7955 * @error: set on error.
7957 * Initialize a delegate and sets a specific method, not the one
7958 * associated with addr. This is useful when sharing generic code.
7959 * In that case addr will most probably not be associated with the
7960 * correct instantiation of the method.
7961 * On failure returns FALSE and sets @error.
7964 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7966 MONO_REQ_GC_UNSAFE_MODE;
7968 mono_error_init (error);
7969 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7971 g_assert (this_obj);
7974 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7977 delegate->method = method;
7979 mono_stats.delegate_creations++;
7981 #ifndef DISABLE_REMOTING
7982 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7984 method = mono_marshal_get_remoting_invoke (method);
7985 delegate->method_ptr = mono_compile_method_checked (method, error);
7986 return_val_if_nok (error, FALSE);
7987 MONO_OBJECT_SETREF (delegate, target, target);
7991 delegate->method_ptr = addr;
7992 MONO_OBJECT_SETREF (delegate, target, target);
7995 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7996 if (callbacks.init_delegate)
7997 callbacks.init_delegate (delegate);
8002 * mono_delegate_ctor:
8003 * @this: pointer to an uninitialized delegate object
8004 * @target: target object
8005 * @addr: pointer to native code
8006 * @error: set on error.
8008 * This is used to initialize a delegate.
8009 * On failure returns FALSE and sets @error.
8012 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
8014 MONO_REQ_GC_UNSAFE_MODE;
8016 mono_error_init (error);
8017 MonoDomain *domain = mono_domain_get ();
8019 MonoMethod *method = NULL;
8023 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
8025 if (!ji && domain != mono_get_root_domain ())
8026 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
8028 method = mono_jit_info_get_method (ji);
8029 g_assert (!method->klass->generic_container);
8032 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
8036 * mono_method_call_message_new:
8037 * @method: method to encapsulate
8038 * @params: parameters to the method
8039 * @invoke: optional, delegate invoke.
8040 * @cb: async callback delegate.
8041 * @state: state passed to the async callback.
8042 * @error: set on error.
8044 * Translates arguments pointers into a MonoMethodMessage.
8045 * On failure returns NULL and sets @error.
8048 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
8049 MonoDelegate **cb, MonoObject **state, MonoError *error)
8051 MONO_REQ_GC_UNSAFE_MODE;
8053 mono_error_init (error);
8055 MonoDomain *domain = mono_domain_get ();
8056 MonoMethodSignature *sig = mono_method_signature (method);
8057 MonoMethodMessage *msg;
8060 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8061 return_val_if_nok (error, NULL);
8064 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8065 return_val_if_nok (error, NULL);
8066 mono_message_init (domain, msg, rm, NULL, error);
8067 return_val_if_nok (error, NULL);
8068 count = sig->param_count - 2;
8070 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8071 return_val_if_nok (error, NULL);
8072 mono_message_init (domain, msg, rm, NULL, error);
8073 return_val_if_nok (error, NULL);
8074 count = sig->param_count;
8077 for (i = 0; i < count; i++) {
8082 if (sig->params [i]->byref)
8083 vpos = *((gpointer *)params [i]);
8087 klass = mono_class_from_mono_type (sig->params [i]);
8089 if (klass->valuetype) {
8090 arg = mono_value_box_checked (domain, klass, vpos, error);
8091 return_val_if_nok (error, NULL);
8093 arg = *((MonoObject **)vpos);
8095 mono_array_setref (msg->args, i, arg);
8098 if (cb != NULL && state != NULL) {
8099 *cb = *((MonoDelegate **)params [i]);
8101 *state = *((MonoObject **)params [i]);
8108 * mono_method_return_message_restore:
8110 * Restore results from message based processing back to arguments pointers
8113 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8115 MONO_REQ_GC_UNSAFE_MODE;
8117 mono_error_init (error);
8119 MonoMethodSignature *sig = mono_method_signature (method);
8120 int i, j, type, size, out_len;
8122 if (out_args == NULL)
8124 out_len = mono_array_length (out_args);
8128 for (i = 0, j = 0; i < sig->param_count; i++) {
8129 MonoType *pt = sig->params [i];
8134 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8138 arg = (char *)mono_array_get (out_args, gpointer, j);
8141 g_assert (type != MONO_TYPE_VOID);
8143 if (MONO_TYPE_IS_REFERENCE (pt)) {
8144 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8147 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8148 size = mono_class_value_size (klass, NULL);
8149 if (klass->has_references)
8150 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8152 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8154 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8155 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8164 #ifndef DISABLE_REMOTING
8167 * mono_load_remote_field:
8168 * @this: pointer to an object
8169 * @klass: klass of the object containing @field
8170 * @field: the field to load
8171 * @res: a storage to store the result
8173 * This method is called by the runtime on attempts to load fields of
8174 * transparent proxy objects. @this points to such TP, @klass is the class of
8175 * the object containing @field. @res is a storage location which can be
8176 * used to store the result.
8178 * Returns: an address pointing to the value of field.
8181 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8184 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8185 mono_error_cleanup (&error);
8190 * mono_load_remote_field_checked:
8191 * @this: pointer to an object
8192 * @klass: klass of the object containing @field
8193 * @field: the field to load
8194 * @res: a storage to store the result
8195 * @error: set on error
8197 * This method is called by the runtime on attempts to load fields of
8198 * transparent proxy objects. @this points to such TP, @klass is the class of
8199 * the object containing @field. @res is a storage location which can be
8200 * used to store the result.
8202 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8205 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8207 MONO_REQ_GC_UNSAFE_MODE;
8209 static MonoMethod *getter = NULL;
8211 mono_error_init (error);
8213 MonoDomain *domain = mono_domain_get ();
8214 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8215 MonoClass *field_class;
8216 MonoMethodMessage *msg;
8217 MonoArray *out_args;
8221 g_assert (mono_object_is_transparent_proxy (this_obj));
8222 g_assert (res != NULL);
8224 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8225 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8230 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8232 mono_error_set_not_supported (error, "Linked away.");
8237 field_class = mono_class_from_mono_type (field->type);
8239 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8240 return_val_if_nok (error, NULL);
8241 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8242 return_val_if_nok (error, NULL);
8243 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8244 return_val_if_nok (error, NULL);
8245 mono_message_init (domain, msg, rm, out_args, error);
8246 return_val_if_nok (error, NULL);
8248 full_name = mono_type_get_full_name (klass);
8249 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8250 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8253 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8254 return_val_if_nok (error, NULL);
8257 mono_error_set_exception_instance (error, (MonoException *)exc);
8261 if (mono_array_length (out_args) == 0)
8264 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8266 if (field_class->valuetype) {
8267 return ((char *)*res) + sizeof (MonoObject);
8273 * mono_load_remote_field_new:
8278 * Missing documentation.
8281 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8285 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8286 mono_error_cleanup (&error);
8291 * mono_load_remote_field_new_icall:
8292 * @this: pointer to an object
8293 * @klass: klass of the object containing @field
8294 * @field: the field to load
8296 * This method is called by the runtime on attempts to load fields of
8297 * transparent proxy objects. @this points to such TP, @klass is the class of
8298 * the object containing @field.
8300 * Returns: a freshly allocated object containing the value of the
8301 * field. On failure returns NULL and throws an exception.
8304 mono_load_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8307 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8308 mono_error_set_pending_exception (&error);
8313 * mono_load_remote_field_new_checked:
8314 * @this: pointer to an object
8315 * @klass: klass of the object containing @field
8316 * @field: the field to load
8317 * @error: set on error.
8319 * This method is called by the runtime on attempts to load fields of
8320 * transparent proxy objects. @this points to such TP, @klass is the class of
8321 * the object containing @field.
8323 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8326 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8328 MONO_REQ_GC_UNSAFE_MODE;
8330 mono_error_init (error);
8332 static MonoMethod *getter = NULL;
8333 MonoDomain *domain = mono_domain_get ();
8334 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8335 MonoClass *field_class;
8336 MonoMethodMessage *msg;
8337 MonoArray *out_args;
8338 MonoObject *exc, *res;
8341 g_assert (mono_object_is_transparent_proxy (this_obj));
8343 field_class = mono_class_from_mono_type (field->type);
8345 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8347 if (field_class->valuetype) {
8348 res = mono_object_new_checked (domain, field_class, error);
8349 return_val_if_nok (error, NULL);
8350 val = ((gchar *) res) + sizeof (MonoObject);
8354 mono_field_get_value (tp->rp->unwrapped_server, field, val);
8359 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8361 mono_error_set_not_supported (error, "Linked away.");
8366 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8367 return_val_if_nok (error, NULL);
8368 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8369 return_val_if_nok (error, NULL);
8371 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8372 return_val_if_nok (error, NULL);
8373 mono_message_init (domain, msg, rm, out_args, error);
8374 return_val_if_nok (error, NULL);
8376 full_name = mono_type_get_full_name (klass);
8377 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8378 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8381 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8382 return_val_if_nok (error, NULL);
8385 mono_error_set_exception_instance (error, (MonoException *)exc);
8389 if (mono_array_length (out_args) == 0)
8392 res = mono_array_get (out_args, MonoObject *, 0);
8398 * mono_store_remote_field:
8399 * @this_obj: pointer to an object
8400 * @klass: klass of the object containing @field
8401 * @field: the field to load
8402 * @val: the value/object to store
8404 * This method is called by the runtime on attempts to store fields of
8405 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8406 * the object containing @field. @val is the new value to store in @field.
8409 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8412 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8413 mono_error_cleanup (&error);
8417 * mono_store_remote_field_checked:
8418 * @this_obj: pointer to an object
8419 * @klass: klass of the object containing @field
8420 * @field: the field to load
8421 * @val: the value/object to store
8422 * @error: set on error
8424 * This method is called by the runtime on attempts to store fields of
8425 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8426 * the object containing @field. @val is the new value to store in @field.
8428 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8431 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8434 MONO_REQ_GC_UNSAFE_MODE;
8436 static MonoMethod *setter = NULL;
8438 MonoDomain *domain = mono_domain_get ();
8439 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8440 MonoClass *field_class;
8441 MonoMethodMessage *msg;
8442 MonoArray *out_args;
8447 mono_error_init (error);
8449 g_assert (mono_object_is_transparent_proxy (this_obj));
8451 field_class = mono_class_from_mono_type (field->type);
8453 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8454 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
8455 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
8460 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8462 mono_error_set_not_supported (error, "Linked away.");
8467 if (field_class->valuetype) {
8468 arg = mono_value_box_checked (domain, field_class, val, error);
8469 return_val_if_nok (error, FALSE);
8471 arg = *((MonoObject **)val);
8474 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8475 return_val_if_nok (error, FALSE);
8476 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8477 return_val_if_nok (error, FALSE);
8478 mono_message_init (domain, msg, rm, NULL, error);
8479 return_val_if_nok (error, FALSE);
8481 full_name = mono_type_get_full_name (klass);
8482 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8483 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8484 mono_array_setref (msg->args, 2, arg);
8487 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8488 return_val_if_nok (error, FALSE);
8491 mono_error_set_exception_instance (error, (MonoException *)exc);
8498 * mono_store_remote_field_new:
8504 * Missing documentation
8507 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8510 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8511 mono_error_cleanup (&error);
8515 * mono_store_remote_field_new_icall:
8521 * Missing documentation
8524 mono_store_remote_field_new_icall (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8527 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8528 mono_error_set_pending_exception (&error);
8532 * mono_store_remote_field_new_checked:
8539 * Missing documentation
8542 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8544 MONO_REQ_GC_UNSAFE_MODE;
8546 static MonoMethod *setter = NULL;
8547 MonoDomain *domain = mono_domain_get ();
8548 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8549 MonoClass *field_class;
8550 MonoMethodMessage *msg;
8551 MonoArray *out_args;
8555 mono_error_init (error);
8557 g_assert (mono_object_is_transparent_proxy (this_obj));
8559 field_class = mono_class_from_mono_type (field->type);
8561 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8562 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
8563 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
8568 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
8570 mono_error_set_not_supported (error, "Linked away.");
8575 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8576 return_val_if_nok (error, FALSE);
8577 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, error);
8578 return_val_if_nok (error, FALSE);
8579 mono_message_init (domain, msg, rm, NULL, error);
8580 return_val_if_nok (error, FALSE);
8582 full_name = mono_type_get_full_name (klass);
8583 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8584 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8585 mono_array_setref (msg->args, 2, arg);
8588 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8589 return_val_if_nok (error, FALSE);
8592 mono_error_set_exception_instance (error, (MonoException *)exc);
8600 * mono_create_ftnptr:
8602 * Given a function address, create a function descriptor for it.
8603 * This is only needed on some platforms.
8606 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8608 return callbacks.create_ftnptr (domain, addr);
8612 * mono_get_addr_from_ftnptr:
8614 * Given a pointer to a function descriptor, return the function address.
8615 * This is only needed on some platforms.
8618 mono_get_addr_from_ftnptr (gpointer descr)
8620 return callbacks.get_addr_from_ftnptr (descr);
8624 * mono_string_chars:
8627 * Returns a pointer to the UCS16 characters stored in the MonoString
8630 mono_string_chars (MonoString *s)
8632 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8638 * mono_string_length:
8641 * Returns the lenght in characters of the string
8644 mono_string_length (MonoString *s)
8646 MONO_REQ_GC_UNSAFE_MODE;
8652 * mono_array_length:
8653 * @array: a MonoArray*
8655 * Returns the total number of elements in the array. This works for
8656 * both vectors and multidimensional arrays.
8659 mono_array_length (MonoArray *array)
8661 MONO_REQ_GC_UNSAFE_MODE;
8663 return array->max_length;
8667 * mono_array_addr_with_size:
8668 * @array: a MonoArray*
8669 * @size: size of the array elements
8670 * @idx: index into the array
8672 * Use this function to obtain the address for the @idx item on the
8673 * @array containing elements of size @size.
8675 * This method performs no bounds checking or type checking.
8677 * Returns the address of the @idx element in the array.
8680 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8682 MONO_REQ_GC_UNSAFE_MODE;
8684 return ((char*)(array)->vector) + size * idx;
8689 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8691 MonoDomain *domain = mono_domain_get ();
8695 mono_error_init (error);
8699 len = g_list_length (list);
8700 res = mono_array_new_checked (domain, eclass, len, error);
8701 return_val_if_nok (error, NULL);
8703 for (i = 0; list; list = list->next, i++)
8704 mono_array_set (res, gpointer, i, list->data);
8711 * The following section is purely to declare prototypes and
8712 * document the API, as these C files are processed by our
8718 * @array: array to alter
8719 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8720 * @index: index into the array
8721 * @value: value to set
8723 * Value Type version: This sets the @index's element of the @array
8724 * with elements of size sizeof(type) to the provided @value.
8726 * This macro does not attempt to perform type checking or bounds checking.
8728 * Use this to set value types in a `MonoArray`.
8730 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8735 * mono_array_setref:
8736 * @array: array to alter
8737 * @index: index into the array
8738 * @value: value to set
8740 * Reference Type version: This sets the @index's element of the
8741 * @array with elements of size sizeof(type) to the provided @value.
8743 * This macro does not attempt to perform type checking or bounds checking.
8745 * Use this to reference types in a `MonoArray`.
8747 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8753 * @array: array on which to operate on
8754 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8755 * @index: index into the array
8757 * Use this macro to retrieve the @index element of an @array and
8758 * extract the value assuming that the elements of the array match
8759 * the provided type value.
8761 * This method can be used with both arrays holding value types and
8762 * reference types. For reference types, the @type parameter should
8763 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8765 * This macro does not attempt to perform type checking or bounds checking.
8767 * Returns: The element at the @index position in the @array.
8769 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)