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;
332 MonoException * pending_tae = NULL;
334 mono_error_init (error);
336 if (vtable->initialized)
339 klass = vtable->klass;
341 if (!klass->image->checked_module_cctor) {
342 mono_image_check_for_module_cctor (klass->image);
343 if (klass->image->has_module_cctor) {
344 MonoClass *module_klass;
345 MonoVTable *module_vtable;
347 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
352 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
355 if (!mono_runtime_class_init_full (module_vtable, error))
359 method = mono_class_get_cctor (klass);
361 vtable->initialized = 1;
365 tid = mono_native_thread_id_get ();
367 mono_type_initialization_lock ();
368 /* double check... */
369 if (vtable->initialized) {
370 mono_type_initialization_unlock ();
373 if (vtable->init_failed) {
374 mono_type_initialization_unlock ();
376 /* The type initialization already failed once, rethrow the same exception */
377 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
380 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
382 /* This thread will get to do the initialization */
383 if (mono_domain_get () != domain) {
384 /* Transfer into the target domain */
385 last_domain = mono_domain_get ();
386 if (!mono_domain_set (domain, FALSE)) {
387 vtable->initialized = 1;
388 mono_type_initialization_unlock ();
389 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
393 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
394 mono_coop_mutex_init_recursive (&lock->initialization_section);
395 lock->initializing_tid = tid;
396 lock->waiting_count = 1;
398 /* grab the vtable lock while this thread still owns type_initialization_section */
399 /* This is why type_initialization_lock needs to enter blocking mode */
400 mono_type_init_lock (lock);
401 g_hash_table_insert (type_initialization_hash, vtable, lock);
402 do_initialization = 1;
405 TypeInitializationLock *pending_lock;
407 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
408 mono_type_initialization_unlock ();
411 /* see if the thread doing the initialization is already blocked on this thread */
412 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
413 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
414 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
415 if (!pending_lock->done) {
416 mono_type_initialization_unlock ();
419 /* the thread doing the initialization is blocked on this thread,
420 but on a lock that has already been freed. It just hasn't got
425 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
427 ++lock->waiting_count;
428 /* record the fact that we are waiting on the initializing thread */
429 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
431 mono_type_initialization_unlock ();
433 if (do_initialization) {
434 MonoException *exc = NULL;
436 mono_threads_begin_abort_protected_block ();
437 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
438 mono_threads_end_abort_protected_block ();
440 //exception extracted, error will be set to the right value later
441 if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
442 exc = mono_error_convert_to_exception (error);
444 mono_error_cleanup (error);
446 mono_error_init (error);
448 /* If the initialization failed, mark the class as unusable. */
449 /* Avoid infinite loops */
451 (klass->image == mono_defaults.corlib &&
452 !strcmp (klass->name_space, "System") &&
453 !strcmp (klass->name, "TypeInitializationException")))) {
454 vtable->init_failed = 1;
456 if (klass->name_space && *klass->name_space)
457 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
459 full_name = g_strdup (klass->name);
461 MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
464 mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
467 * Store the exception object so it could be thrown on subsequent
470 mono_domain_lock (domain);
471 if (!domain->type_init_exception_hash)
472 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");
473 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
474 mono_domain_unlock (domain);
478 mono_domain_set (last_domain, TRUE);
480 mono_type_init_unlock (lock);
481 if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class)
483 //TAEs are blocked around .cctors, they must escape as soon as no cctor is left to run.
485 pending_tae = mono_thread_try_resume_interruption ();
487 /* this just blocks until the initializing thread is done */
488 mono_type_init_lock (lock);
489 mono_type_init_unlock (lock);
492 mono_type_initialization_lock ();
493 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
494 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
495 --lock->waiting_count;
496 if (lock->waiting_count == 0) {
497 mono_coop_mutex_destroy (&lock->initialization_section);
498 g_hash_table_remove (type_initialization_hash, vtable);
501 mono_memory_barrier ();
502 if (!vtable->init_failed)
503 vtable->initialized = 1;
504 mono_type_initialization_unlock ();
508 mono_error_set_exception_instance (error, pending_tae);
509 else if (vtable->init_failed) {
510 /* Either we were the initializing thread or we waited for the initialization */
511 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
518 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
520 MONO_REQ_GC_NEUTRAL_MODE;
522 MonoVTable *vtable = (MonoVTable*)key;
524 TypeInitializationLock *lock = (TypeInitializationLock*) value;
525 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
528 * Have to set this since it cannot be set by the normal code in
529 * mono_runtime_class_init (). In this case, the exception object is not stored,
530 * and get_type_init_exception_for_class () needs to be aware of this.
532 vtable->init_failed = 1;
533 mono_type_init_unlock (lock);
534 --lock->waiting_count;
535 if (lock->waiting_count == 0) {
536 mono_coop_mutex_destroy (&lock->initialization_section);
545 mono_release_type_locks (MonoInternalThread *thread)
547 MONO_REQ_GC_UNSAFE_MODE;
549 mono_type_initialization_lock ();
550 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
551 mono_type_initialization_unlock ();
554 #ifndef DISABLE_REMOTING
557 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
559 g_error ("remoting not installed");
563 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
567 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
569 g_assert_not_reached ();
573 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
574 static MonoImtThunkBuilder imt_thunk_builder;
575 static gboolean always_build_imt_thunks;
577 #if (MONO_IMT_SIZE > 32)
578 #error "MONO_IMT_SIZE cannot be larger than 32"
582 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
584 memcpy (&callbacks, cbs, sizeof (*cbs));
587 MonoRuntimeCallbacks*
588 mono_get_runtime_callbacks (void)
593 #ifndef DISABLE_REMOTING
595 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
597 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
602 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
604 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
608 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
609 imt_thunk_builder = func;
613 mono_set_always_build_imt_thunks (gboolean value)
615 always_build_imt_thunks = value;
619 * mono_compile_method:
620 * @method: The method to compile.
622 * This JIT-compiles the method, and returns the pointer to the native code
626 mono_compile_method (MonoMethod *method)
629 gpointer result = mono_compile_method_checked (method, &error);
630 mono_error_cleanup (&error);
635 * mono_compile_method:
636 * @method: The method to compile.
637 * @error: set on error.
639 * This JIT-compiles the method, and returns the pointer to the native code
640 * produced. On failure returns NULL and sets @error.
643 mono_compile_method_checked (MonoMethod *method, MonoError *error)
647 MONO_REQ_GC_NEUTRAL_MODE
649 mono_error_init (error);
651 if (!callbacks.compile_method) {
652 g_error ("compile method called on uninitialized runtime");
655 res = callbacks.compile_method (method, error);
660 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
664 MONO_REQ_GC_NEUTRAL_MODE;
666 mono_error_init (error);
667 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
672 mono_runtime_create_delegate_trampoline (MonoClass *klass)
674 MONO_REQ_GC_NEUTRAL_MODE
676 return arch_create_delegate_trampoline (mono_domain_get (), klass);
679 static MonoFreeMethodFunc default_mono_free_method = NULL;
682 * mono_install_free_method:
683 * @func: pointer to the MonoFreeMethodFunc used to release a method
685 * This is an internal VM routine, it is used for the engines to
686 * register a handler to release the resources associated with a method.
688 * Methods are freed when no more references to the delegate that holds
692 mono_install_free_method (MonoFreeMethodFunc func)
694 default_mono_free_method = func;
698 * mono_runtime_free_method:
699 * @domain; domain where the method is hosted
700 * @method: method to release
702 * This routine is invoked to free the resources associated with
703 * a method that has been JIT compiled. This is used to discard
704 * methods that were used only temporarily (for example, used in marshalling)
708 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
710 MONO_REQ_GC_NEUTRAL_MODE
712 if (default_mono_free_method != NULL)
713 default_mono_free_method (domain, method);
715 mono_method_clear_object (domain, method);
717 mono_free_method (method);
721 * The vtables in the root appdomain are assumed to be reachable by other
722 * roots, and we don't use typed allocation in the other domains.
725 /* The sync block is no longer a GC pointer */
726 #define GC_HEADER_BITMAP (0)
728 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
731 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
733 MONO_REQ_GC_NEUTRAL_MODE;
735 MonoClassField *field;
741 max_size = mono_class_data_size (klass) / sizeof (gpointer);
743 max_size = klass->instance_size / sizeof (gpointer);
744 if (max_size > size) {
745 g_assert (offset <= 0);
746 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
751 /*An Ephemeron cannot be marked by sgen*/
752 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
754 memset (bitmap, 0, size / 8);
759 for (p = klass; p != NULL; p = p->parent) {
760 gpointer iter = NULL;
761 while ((field = mono_class_get_fields (p, &iter))) {
765 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
767 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
770 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
773 /* FIXME: should not happen, flag as type load error */
774 if (field->type->byref)
777 if (static_fields && field->offset == -1)
781 pos = field->offset / sizeof (gpointer);
784 type = mono_type_get_underlying_type (field->type);
785 switch (type->type) {
788 case MONO_TYPE_FNPTR:
790 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
795 if (klass->image != mono_defaults.corlib)
798 case MONO_TYPE_STRING:
799 case MONO_TYPE_SZARRAY:
800 case MONO_TYPE_CLASS:
801 case MONO_TYPE_OBJECT:
802 case MONO_TYPE_ARRAY:
803 g_assert ((field->offset % sizeof(gpointer)) == 0);
805 g_assert (pos < size || pos <= max_size);
806 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
807 *max_set = MAX (*max_set, pos);
809 case MONO_TYPE_GENERICINST:
810 if (!mono_type_generic_inst_is_valuetype (type)) {
811 g_assert ((field->offset % sizeof(gpointer)) == 0);
813 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
814 *max_set = MAX (*max_set, pos);
819 case MONO_TYPE_VALUETYPE: {
820 MonoClass *fclass = mono_class_from_mono_type (field->type);
821 if (fclass->has_references) {
822 /* remove the object header */
823 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
837 case MONO_TYPE_BOOLEAN:
841 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
852 * mono_class_compute_bitmap:
854 * Mono internal function to compute a bitmap of reference fields in a class.
857 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
859 MONO_REQ_GC_NEUTRAL_MODE;
861 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
866 * similar to the above, but sets the bits in the bitmap for any non-ref field
867 * and ignores static fields
870 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
872 MonoClassField *field;
877 max_size = class->instance_size / sizeof (gpointer);
878 if (max_size >= size) {
879 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
882 for (p = class; p != NULL; p = p->parent) {
883 gpointer iter = NULL;
884 while ((field = mono_class_get_fields (p, &iter))) {
887 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
889 /* FIXME: should not happen, flag as type load error */
890 if (field->type->byref)
893 pos = field->offset / sizeof (gpointer);
896 type = mono_type_get_underlying_type (field->type);
897 switch (type->type) {
898 #if SIZEOF_VOID_P == 8
902 case MONO_TYPE_FNPTR:
907 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
908 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
909 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
912 #if SIZEOF_VOID_P == 4
916 case MONO_TYPE_FNPTR:
921 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
922 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
923 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
929 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
930 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
931 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
934 case MONO_TYPE_BOOLEAN:
937 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
939 case MONO_TYPE_STRING:
940 case MONO_TYPE_SZARRAY:
941 case MONO_TYPE_CLASS:
942 case MONO_TYPE_OBJECT:
943 case MONO_TYPE_ARRAY:
945 case MONO_TYPE_GENERICINST:
946 if (!mono_type_generic_inst_is_valuetype (type)) {
951 case MONO_TYPE_VALUETYPE: {
952 MonoClass *fclass = mono_class_from_mono_type (field->type);
953 /* remove the object header */
954 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
958 g_assert_not_reached ();
967 * mono_class_insecure_overlapping:
968 * check if a class with explicit layout has references and non-references
969 * fields overlapping.
971 * Returns: TRUE if it is insecure to load the type.
974 mono_class_insecure_overlapping (MonoClass *klass)
978 gsize default_bitmap [4] = {0};
980 gsize default_nrbitmap [4] = {0};
981 int i, insecure = FALSE;
984 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
985 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
987 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
988 int idx = i % (sizeof (bitmap [0]) * 8);
989 if (bitmap [idx] & nrbitmap [idx]) {
994 if (bitmap != default_bitmap)
996 if (nrbitmap != default_nrbitmap)
999 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
1007 ves_icall_string_alloc (int length)
1010 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1011 mono_error_set_pending_exception (&error);
1017 mono_class_compute_gc_descriptor (MonoClass *klass)
1019 MONO_REQ_GC_NEUTRAL_MODE;
1023 gsize default_bitmap [4] = {0};
1024 static gboolean gcj_inited = FALSE;
1027 mono_loader_lock ();
1029 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
1030 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
1033 mono_loader_unlock ();
1037 mono_class_init (klass);
1039 if (klass->gc_descr_inited)
1042 klass->gc_descr_inited = TRUE;
1043 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1045 bitmap = default_bitmap;
1046 if (klass == mono_defaults.string_class) {
1047 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1048 } else if (klass->rank) {
1049 mono_class_compute_gc_descriptor (klass->element_class);
1050 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1052 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1053 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1054 class->name_space, class->name);*/
1056 /* remove the object header */
1057 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1058 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));
1059 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1060 class->name_space, class->name);*/
1061 if (bitmap != default_bitmap)
1065 /*static int count = 0;
1068 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1069 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1071 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1072 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1074 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1075 if (bitmap != default_bitmap)
1081 * field_is_special_static:
1082 * @fklass: The MonoClass to look up.
1083 * @field: The MonoClassField describing the field.
1085 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1086 * SPECIAL_STATIC_NONE otherwise.
1089 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1091 MONO_REQ_GC_NEUTRAL_MODE;
1094 MonoCustomAttrInfo *ainfo;
1096 ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1097 mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1100 for (i = 0; i < ainfo->num_attrs; ++i) {
1101 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1102 if (klass->image == mono_defaults.corlib) {
1103 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1104 mono_custom_attrs_free (ainfo);
1105 return SPECIAL_STATIC_THREAD;
1107 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1108 mono_custom_attrs_free (ainfo);
1109 return SPECIAL_STATIC_CONTEXT;
1113 mono_custom_attrs_free (ainfo);
1114 return SPECIAL_STATIC_NONE;
1117 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1118 #define mix(a,b,c) { \
1119 a -= c; a ^= rot(c, 4); c += b; \
1120 b -= a; b ^= rot(a, 6); a += c; \
1121 c -= b; c ^= rot(b, 8); b += a; \
1122 a -= c; a ^= rot(c,16); c += b; \
1123 b -= a; b ^= rot(a,19); a += c; \
1124 c -= b; c ^= rot(b, 4); b += a; \
1126 #define final(a,b,c) { \
1127 c ^= b; c -= rot(b,14); \
1128 a ^= c; a -= rot(c,11); \
1129 b ^= a; b -= rot(a,25); \
1130 c ^= b; c -= rot(b,16); \
1131 a ^= c; a -= rot(c,4); \
1132 b ^= a; b -= rot(a,14); \
1133 c ^= b; c -= rot(b,24); \
1137 * mono_method_get_imt_slot:
1139 * The IMT slot is embedded into AOTed code, so this must return the same value
1140 * for the same method across all executions. This means:
1141 * - pointers shouldn't be used as hash values.
1142 * - mono_metadata_str_hash () should be used for hashing strings.
1145 mono_method_get_imt_slot (MonoMethod *method)
1147 MONO_REQ_GC_NEUTRAL_MODE;
1149 MonoMethodSignature *sig;
1151 guint32 *hashes_start, *hashes;
1155 /* This can be used to stress tests the collision code */
1159 * We do this to simplify generic sharing. It will hurt
1160 * performance in cases where a class implements two different
1161 * instantiations of the same generic interface.
1162 * The code in build_imt_slots () depends on this.
1164 if (method->is_inflated)
1165 method = ((MonoMethodInflated*)method)->declaring;
1167 sig = mono_method_signature (method);
1168 hashes_count = sig->param_count + 4;
1169 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1170 hashes = hashes_start;
1172 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1173 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1174 method->klass->name_space, method->klass->name, method->name);
1177 /* Initialize hashes */
1178 hashes [0] = mono_metadata_str_hash (method->klass->name);
1179 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1180 hashes [2] = mono_metadata_str_hash (method->name);
1181 hashes [3] = mono_metadata_type_hash (sig->ret);
1182 for (i = 0; i < sig->param_count; i++) {
1183 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1186 /* Setup internal state */
1187 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1189 /* Handle most of the hashes */
1190 while (hashes_count > 3) {
1199 /* Handle the last 3 hashes (all the case statements fall through) */
1200 switch (hashes_count) {
1201 case 3 : c += hashes [2];
1202 case 2 : b += hashes [1];
1203 case 1 : a += hashes [0];
1205 case 0: /* nothing left to add */
1209 free (hashes_start);
1210 /* Report the result */
1211 return c % MONO_IMT_SIZE;
1220 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1221 MONO_REQ_GC_NEUTRAL_MODE;
1223 guint32 imt_slot = mono_method_get_imt_slot (method);
1224 MonoImtBuilderEntry *entry;
1226 if (slot_num >= 0 && imt_slot != slot_num) {
1227 /* we build just a single imt slot and this is not it */
1231 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1232 entry->key = method;
1233 entry->value.vtable_slot = vtable_slot;
1234 entry->next = imt_builder [imt_slot];
1235 if (imt_builder [imt_slot] != NULL) {
1236 entry->children = imt_builder [imt_slot]->children + 1;
1237 if (entry->children == 1) {
1238 mono_stats.imt_slots_with_collisions++;
1239 *imt_collisions_bitmap |= (1 << imt_slot);
1242 entry->children = 0;
1243 mono_stats.imt_used_slots++;
1245 imt_builder [imt_slot] = entry;
1248 char *method_name = mono_method_full_name (method, TRUE);
1249 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1250 method, method_name, imt_slot, vtable_slot, entry->children);
1251 g_free (method_name);
1258 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1260 MonoMethod *method = e->key;
1261 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1265 method->klass->name_space,
1266 method->klass->name,
1269 printf (" * %s: NULL\n", message);
1275 compare_imt_builder_entries (const void *p1, const void *p2) {
1276 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1277 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1279 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1283 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1285 MONO_REQ_GC_NEUTRAL_MODE;
1287 int count = end - start;
1288 int chunk_start = out_array->len;
1291 for (i = start; i < end; ++i) {
1292 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1293 item->key = sorted_array [i]->key;
1294 item->value = sorted_array [i]->value;
1295 item->has_target_code = sorted_array [i]->has_target_code;
1296 item->is_equals = TRUE;
1298 item->check_target_idx = out_array->len + 1;
1300 item->check_target_idx = 0;
1301 g_ptr_array_add (out_array, item);
1304 int middle = start + count / 2;
1305 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1307 item->key = sorted_array [middle]->key;
1308 item->is_equals = FALSE;
1309 g_ptr_array_add (out_array, item);
1310 imt_emit_ir (sorted_array, start, middle, out_array);
1311 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1317 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1318 MONO_REQ_GC_NEUTRAL_MODE;
1320 int number_of_entries = entries->children + 1;
1321 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1322 GPtrArray *result = g_ptr_array_new ();
1323 MonoImtBuilderEntry *current_entry;
1326 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1327 sorted_array [i] = current_entry;
1329 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1331 /*for (i = 0; i < number_of_entries; i++) {
1332 print_imt_entry (" sorted array:", sorted_array [i], i);
1335 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1337 free (sorted_array);
1342 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1344 MONO_REQ_GC_NEUTRAL_MODE;
1346 if (imt_builder_entry != NULL) {
1347 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1348 /* No collision, return the vtable slot contents */
1349 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1351 /* Collision, build the thunk */
1352 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1355 result = imt_thunk_builder (vtable, domain,
1356 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1357 for (i = 0; i < imt_ir->len; ++i)
1358 g_free (g_ptr_array_index (imt_ir, i));
1359 g_ptr_array_free (imt_ir, TRUE);
1371 static MonoImtBuilderEntry*
1372 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1375 * LOCKING: requires the loader and domain locks.
1379 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1381 MONO_REQ_GC_NEUTRAL_MODE;
1385 guint32 imt_collisions_bitmap = 0;
1386 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1387 int method_count = 0;
1388 gboolean record_method_count_for_max_collisions = FALSE;
1389 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1392 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1394 for (i = 0; i < klass->interface_offsets_count; ++i) {
1395 MonoClass *iface = klass->interfaces_packed [i];
1396 int interface_offset = klass->interface_offsets_packed [i];
1397 int method_slot_in_interface, vt_slot;
1399 if (mono_class_has_variant_generic_params (iface))
1400 has_variant_iface = TRUE;
1402 mono_class_setup_methods (iface);
1403 vt_slot = interface_offset;
1404 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1407 if (slot_num >= 0 && iface->is_inflated) {
1409 * The imt slot of the method is the same as for its declaring method,
1410 * see the comment in mono_method_get_imt_slot (), so we can
1411 * avoid inflating methods which will be discarded by
1412 * add_imt_builder_entry anyway.
1414 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1415 if (mono_method_get_imt_slot (method) != slot_num) {
1420 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1421 if (method->is_generic) {
1422 has_generic_virtual = TRUE;
1427 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1428 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1433 if (extra_interfaces) {
1434 int interface_offset = klass->vtable_size;
1436 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1437 MonoClass* iface = (MonoClass *)list_item->data;
1438 int method_slot_in_interface;
1439 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1440 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1442 if (method->is_generic)
1443 has_generic_virtual = TRUE;
1444 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1446 interface_offset += iface->method.count;
1449 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1450 /* overwrite the imt slot only if we're building all the entries or if
1451 * we're building this specific one
1453 if (slot_num < 0 || i == slot_num) {
1454 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1457 if (imt_builder [i]) {
1458 MonoImtBuilderEntry *entry;
1460 /* Link entries with imt_builder [i] */
1461 for (entry = entries; entry->next; entry = entry->next) {
1463 MonoMethod *method = (MonoMethod*)entry->key;
1464 char *method_name = mono_method_full_name (method, TRUE);
1465 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1466 g_free (method_name);
1469 entry->next = imt_builder [i];
1470 entries->children += imt_builder [i]->children + 1;
1472 imt_builder [i] = entries;
1475 if (has_generic_virtual || has_variant_iface) {
1477 * There might be collisions later when the the thunk is expanded.
1479 imt_collisions_bitmap |= (1 << i);
1482 * The IMT thunk might be called with an instance of one of the
1483 * generic virtual methods, so has to fallback to the IMT trampoline.
1485 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1487 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1490 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1494 if (imt_builder [i] != NULL) {
1495 int methods_in_slot = imt_builder [i]->children + 1;
1496 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1497 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1498 record_method_count_for_max_collisions = TRUE;
1500 method_count += methods_in_slot;
1504 mono_stats.imt_number_of_methods += method_count;
1505 if (record_method_count_for_max_collisions) {
1506 mono_stats.imt_method_count_when_max_collisions = method_count;
1509 for (i = 0; i < MONO_IMT_SIZE; i++) {
1510 MonoImtBuilderEntry* entry = imt_builder [i];
1511 while (entry != NULL) {
1512 MonoImtBuilderEntry* next = entry->next;
1518 /* we OR the bitmap since we may build just a single imt slot at a time */
1519 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1523 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1524 MONO_REQ_GC_NEUTRAL_MODE;
1526 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1530 * mono_vtable_build_imt_slot:
1531 * @vtable: virtual object table struct
1532 * @imt_slot: slot in the IMT table
1534 * Fill the given @imt_slot in the IMT table of @vtable with
1535 * a trampoline or a thunk for the case of collisions.
1536 * This is part of the internal mono API.
1538 * LOCKING: Take the domain lock.
1541 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1543 MONO_REQ_GC_NEUTRAL_MODE;
1545 gpointer *imt = (gpointer*)vtable;
1546 imt -= MONO_IMT_SIZE;
1547 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1549 /* no support for extra interfaces: the proxy objects will need
1550 * to build the complete IMT
1551 * Update and heck needs to ahppen inside the proper domain lock, as all
1552 * the changes made to a MonoVTable.
1554 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1555 mono_domain_lock (vtable->domain);
1556 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1557 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1558 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1559 mono_domain_unlock (vtable->domain);
1560 mono_loader_unlock ();
1565 * The first two free list entries both belong to the wait list: The
1566 * first entry is the pointer to the head of the list and the second
1567 * entry points to the last element. That way appending and removing
1568 * the first element are both O(1) operations.
1570 #ifdef MONO_SMALL_CONFIG
1571 #define NUM_FREE_LISTS 6
1573 #define NUM_FREE_LISTS 12
1575 #define FIRST_FREE_LIST_SIZE 64
1576 #define MAX_WAIT_LENGTH 50
1577 #define THUNK_THRESHOLD 10
1580 * LOCKING: The domain lock must be held.
1583 init_thunk_free_lists (MonoDomain *domain)
1585 MONO_REQ_GC_NEUTRAL_MODE;
1587 if (domain->thunk_free_lists)
1589 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1593 list_index_for_size (int item_size)
1596 int size = FIRST_FREE_LIST_SIZE;
1598 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1607 * mono_method_alloc_generic_virtual_thunk:
1609 * @size: size in bytes
1611 * Allocs size bytes to be used for the code of a generic virtual
1612 * thunk. It's either allocated from the domain's code manager or
1613 * reused from a previously invalidated piece.
1615 * LOCKING: The domain lock must be held.
1618 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1620 MONO_REQ_GC_NEUTRAL_MODE;
1622 static gboolean inited = FALSE;
1623 static int generic_virtual_thunks_size = 0;
1627 MonoThunkFreeList **l;
1629 init_thunk_free_lists (domain);
1631 size += sizeof (guint32);
1632 if (size < sizeof (MonoThunkFreeList))
1633 size = sizeof (MonoThunkFreeList);
1635 i = list_index_for_size (size);
1636 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1637 if ((*l)->size >= size) {
1638 MonoThunkFreeList *item = *l;
1640 return ((guint32*)item) + 1;
1644 /* no suitable item found - search lists of larger sizes */
1645 while (++i < NUM_FREE_LISTS) {
1646 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1649 g_assert (item->size > size);
1650 domain->thunk_free_lists [i] = item->next;
1651 return ((guint32*)item) + 1;
1654 /* still nothing found - allocate it */
1656 mono_counters_register ("Generic virtual thunk bytes",
1657 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1660 generic_virtual_thunks_size += size;
1662 p = (guint32 *)mono_domain_code_reserve (domain, size);
1665 mono_domain_lock (domain);
1666 if (!domain->generic_virtual_thunks)
1667 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1668 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1669 mono_domain_unlock (domain);
1675 * LOCKING: The domain lock must be held.
1678 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1680 MONO_REQ_GC_NEUTRAL_MODE;
1682 guint32 *p = (guint32 *)code;
1683 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1684 gboolean found = FALSE;
1686 mono_domain_lock (domain);
1687 if (!domain->generic_virtual_thunks)
1688 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1689 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1691 mono_domain_unlock (domain);
1694 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1696 init_thunk_free_lists (domain);
1698 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1699 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1700 int length = item->length;
1703 /* unlink the first item from the wait list */
1704 domain->thunk_free_lists [0] = item->next;
1705 domain->thunk_free_lists [0]->length = length - 1;
1707 i = list_index_for_size (item->size);
1709 /* put it in the free list */
1710 item->next = domain->thunk_free_lists [i];
1711 domain->thunk_free_lists [i] = item;
1715 if (domain->thunk_free_lists [1]) {
1716 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1717 domain->thunk_free_lists [0]->length++;
1719 g_assert (!domain->thunk_free_lists [0]);
1721 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1722 domain->thunk_free_lists [0]->length = 1;
1726 typedef struct _GenericVirtualCase {
1730 struct _GenericVirtualCase *next;
1731 } GenericVirtualCase;
1734 * get_generic_virtual_entries:
1736 * Return IMT entries for the generic virtual method instances and
1737 * variant interface methods for vtable slot
1740 static MonoImtBuilderEntry*
1741 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1743 MONO_REQ_GC_NEUTRAL_MODE;
1745 GenericVirtualCase *list;
1746 MonoImtBuilderEntry *entries;
1748 mono_domain_lock (domain);
1749 if (!domain->generic_virtual_cases)
1750 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1752 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1755 for (; list; list = list->next) {
1756 MonoImtBuilderEntry *entry;
1758 if (list->count < THUNK_THRESHOLD)
1761 entry = g_new0 (MonoImtBuilderEntry, 1);
1762 entry->key = list->method;
1763 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1764 entry->has_target_code = 1;
1766 entry->children = entries->children + 1;
1767 entry->next = entries;
1771 mono_domain_unlock (domain);
1773 /* FIXME: Leaking memory ? */
1778 * mono_method_add_generic_virtual_invocation:
1780 * @vtable_slot: pointer to the vtable slot
1781 * @method: the inflated generic virtual method
1782 * @code: the method's code
1784 * Registers a call via unmanaged code to a generic virtual method
1785 * instantiation or variant interface method. If the number of calls reaches a threshold
1786 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1787 * virtual method thunk.
1790 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1791 gpointer *vtable_slot,
1792 MonoMethod *method, gpointer code)
1794 MONO_REQ_GC_NEUTRAL_MODE;
1796 static gboolean inited = FALSE;
1797 static int num_added = 0;
1799 GenericVirtualCase *gvc, *list;
1800 MonoImtBuilderEntry *entries;
1804 mono_domain_lock (domain);
1805 if (!domain->generic_virtual_cases)
1806 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1808 /* Check whether the case was already added */
1809 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1812 if (gvc->method == method)
1817 /* If not found, make a new one */
1819 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1820 gvc->method = method;
1823 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1825 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1828 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1834 if (++gvc->count == THUNK_THRESHOLD) {
1835 gpointer *old_thunk = (void **)*vtable_slot;
1836 gpointer vtable_trampoline = NULL;
1837 gpointer imt_trampoline = NULL;
1839 if ((gpointer)vtable_slot < (gpointer)vtable) {
1840 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1841 int imt_slot = MONO_IMT_SIZE + displacement;
1843 /* Force the rebuild of the thunk at the next call */
1844 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1845 *vtable_slot = imt_trampoline;
1847 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1849 entries = get_generic_virtual_entries (domain, vtable_slot);
1851 sorted = imt_sort_slot_entries (entries);
1853 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1857 MonoImtBuilderEntry *next = entries->next;
1862 for (i = 0; i < sorted->len; ++i)
1863 g_free (g_ptr_array_index (sorted, i));
1864 g_ptr_array_free (sorted, TRUE);
1867 #ifndef __native_client__
1868 /* We don't re-use any thunks as there is a lot of overhead */
1869 /* to deleting and re-using code in Native Client. */
1870 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1871 invalidate_generic_virtual_thunk (domain, old_thunk);
1875 mono_domain_unlock (domain);
1878 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1881 * mono_class_vtable:
1882 * @domain: the application domain
1883 * @class: the class to initialize
1885 * VTables are domain specific because we create domain specific code, and
1886 * they contain the domain specific static class data.
1887 * On failure, NULL is returned, and class->exception_type is set.
1890 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1893 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1894 mono_error_cleanup (&error);
1899 * mono_class_vtable_full:
1900 * @domain: the application domain
1901 * @class: the class to initialize
1902 * @error set on failure.
1904 * VTables are domain specific because we create domain specific code, and
1905 * they contain the domain specific static class data.
1908 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1910 MONO_REQ_GC_UNSAFE_MODE;
1912 MonoClassRuntimeInfo *runtime_info;
1914 mono_error_init (error);
1918 if (mono_class_has_failure (klass)) {
1919 mono_error_set_for_class_failure (error, klass);
1923 /* this check can be inlined in jitted code, too */
1924 runtime_info = klass->runtime_info;
1925 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1926 return runtime_info->domain_vtables [domain->domain_id];
1927 return mono_class_create_runtime_vtable (domain, klass, error);
1931 * mono_class_try_get_vtable:
1932 * @domain: the application domain
1933 * @class: the class to initialize
1935 * This function tries to get the associated vtable from @class if
1936 * it was already created.
1939 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1941 MONO_REQ_GC_NEUTRAL_MODE;
1943 MonoClassRuntimeInfo *runtime_info;
1947 runtime_info = klass->runtime_info;
1948 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1949 return runtime_info->domain_vtables [domain->domain_id];
1954 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1956 MONO_REQ_GC_NEUTRAL_MODE;
1958 size_t alloc_offset;
1961 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1962 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1963 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1965 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1966 g_assert ((imt_table_bytes & 7) == 4);
1973 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1977 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1979 MONO_REQ_GC_UNSAFE_MODE;
1982 MonoClassRuntimeInfo *runtime_info, *old_info;
1983 MonoClassField *field;
1985 int i, vtable_slots;
1986 size_t imt_table_bytes;
1988 guint32 vtable_size, class_size;
1990 gpointer *interface_offsets;
1992 mono_error_init (error);
1994 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1995 mono_domain_lock (domain);
1996 runtime_info = klass->runtime_info;
1997 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1998 mono_domain_unlock (domain);
1999 mono_loader_unlock ();
2000 return runtime_info->domain_vtables [domain->domain_id];
2002 if (!klass->inited || mono_class_has_failure (klass)) {
2003 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
2004 mono_domain_unlock (domain);
2005 mono_loader_unlock ();
2006 mono_error_set_for_class_failure (error, klass);
2011 /* Array types require that their element type be valid*/
2012 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
2013 MonoClass *element_class = klass->element_class;
2014 if (!element_class->inited)
2015 mono_class_init (element_class);
2017 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
2018 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
2019 mono_class_setup_vtable (element_class);
2021 if (mono_class_has_failure (element_class)) {
2022 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
2023 if (!mono_class_has_failure (klass))
2024 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
2025 mono_domain_unlock (domain);
2026 mono_loader_unlock ();
2027 mono_error_set_for_class_failure (error, klass);
2033 * For some classes, mono_class_init () already computed klass->vtable_size, and
2034 * that is all that is needed because of the vtable trampolines.
2036 if (!klass->vtable_size)
2037 mono_class_setup_vtable (klass);
2039 if (klass->generic_class && !klass->vtable)
2040 mono_class_check_vtable_constraints (klass, NULL);
2042 /* Initialize klass->has_finalize */
2043 mono_class_has_finalizer (klass);
2045 if (mono_class_has_failure (klass)) {
2046 mono_domain_unlock (domain);
2047 mono_loader_unlock ();
2048 mono_error_set_for_class_failure (error, klass);
2052 vtable_slots = klass->vtable_size;
2053 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2054 class_size = mono_class_data_size (klass);
2058 if (klass->interface_offsets_count) {
2059 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2060 mono_stats.imt_number_of_tables++;
2061 mono_stats.imt_tables_size += imt_table_bytes;
2063 imt_table_bytes = 0;
2066 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2068 mono_stats.used_class_count++;
2069 mono_stats.class_vtable_size += vtable_size;
2071 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2072 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2073 g_assert (!((gsize)vt & 7));
2076 vt->rank = klass->rank;
2077 vt->domain = domain;
2079 mono_class_compute_gc_descriptor (klass);
2081 * We can't use typed allocation in the non-root domains, since the
2082 * collector needs the GC descriptor stored in the vtable even after
2083 * the mempool containing the vtable is destroyed when the domain is
2084 * unloaded. An alternative might be to allocate vtables in the GC
2085 * heap, but this does not seem to work (it leads to crashes inside
2086 * libgc). If that approach is tried, two gc descriptors need to be
2087 * allocated for each class: one for the root domain, and one for all
2088 * other domains. The second descriptor should contain a bit for the
2089 * vtable field in MonoObject, since we can no longer assume the
2090 * vtable is reachable by other roots after the appdomain is unloaded.
2092 #ifdef HAVE_BOEHM_GC
2093 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2094 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2097 vt->gc_descr = klass->gc_descr;
2099 gc_bits = mono_gc_get_vtable_bits (klass);
2100 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2102 vt->gc_bits = gc_bits;
2105 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2106 if (klass->has_static_refs) {
2107 MonoGCDescriptor statics_gc_descr;
2109 gsize default_bitmap [4] = {0};
2112 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2113 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2114 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2115 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2116 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2117 if (bitmap != default_bitmap)
2120 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2122 vt->has_static_fields = TRUE;
2123 mono_stats.class_static_data_size += class_size;
2127 while ((field = mono_class_get_fields (klass, &iter))) {
2128 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2130 if (mono_field_is_deleted (field))
2132 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2133 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2134 if (special_static != SPECIAL_STATIC_NONE) {
2135 guint32 size, offset;
2137 gsize default_bitmap [4] = {0};
2142 if (mono_type_is_reference (field->type)) {
2143 default_bitmap [0] = 1;
2145 bitmap = default_bitmap;
2146 } else if (mono_type_is_struct (field->type)) {
2147 fclass = mono_class_from_mono_type (field->type);
2148 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2149 numbits = max_set + 1;
2151 default_bitmap [0] = 0;
2153 bitmap = default_bitmap;
2155 size = mono_type_size (field->type, &align);
2156 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2157 if (!domain->special_static_fields)
2158 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2159 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2160 if (bitmap != default_bitmap)
2163 * This marks the field as special static to speed up the
2164 * checks in mono_field_static_get/set_value ().
2170 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2171 MonoClass *fklass = mono_class_from_mono_type (field->type);
2172 const char *data = mono_field_get_data (field);
2174 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2175 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2176 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2179 if (fklass->valuetype) {
2180 memcpy (t, data, mono_class_value_size (fklass, NULL));
2182 /* it's a pointer type: add check */
2183 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2190 vt->max_interface_id = klass->max_interface_id;
2191 vt->interface_bitmap = klass->interface_bitmap;
2193 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2194 // class->name, klass->interface_offsets_count);
2196 /* Initialize vtable */
2197 if (callbacks.get_vtable_trampoline) {
2198 // This also covers the AOT case
2199 for (i = 0; i < klass->vtable_size; ++i) {
2200 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2203 mono_class_setup_vtable (klass);
2205 for (i = 0; i < klass->vtable_size; ++i) {
2208 cm = klass->vtable [i];
2210 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2211 if (!is_ok (error)) {
2212 mono_domain_unlock (domain);
2213 mono_loader_unlock ();
2220 if (imt_table_bytes) {
2221 /* Now that the vtable is full, we can actually fill up the IMT */
2222 for (i = 0; i < MONO_IMT_SIZE; ++i)
2223 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2227 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2228 * re-acquire them and check if another thread has created the vtable in the meantime.
2230 /* Special case System.MonoType to avoid infinite recursion */
2231 if (klass != mono_defaults.runtimetype_class) {
2232 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2233 if (!is_ok (error)) {
2234 mono_domain_unlock (domain);
2235 mono_loader_unlock ();
2239 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2240 /* This is unregistered in
2241 unregister_vtable_reflection_type() in
2243 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2246 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2248 /* class_vtable_array keeps an array of created vtables
2250 g_ptr_array_add (domain->class_vtable_array, vt);
2251 /* klass->runtime_info is protected by the loader lock, both when
2252 * it it enlarged and when it is stored info.
2256 * Store the vtable in klass->runtime_info.
2257 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2259 mono_memory_barrier ();
2261 old_info = klass->runtime_info;
2262 if (old_info && old_info->max_domain >= domain->domain_id) {
2263 /* someone already created a large enough runtime info */
2264 old_info->domain_vtables [domain->domain_id] = vt;
2266 int new_size = domain->domain_id;
2268 new_size = MAX (new_size, old_info->max_domain);
2270 /* make the new size a power of two */
2272 while (new_size > i)
2275 /* this is a bounded memory retention issue: may want to
2276 * handle it differently when we'll have a rcu-like system.
2278 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2279 runtime_info->max_domain = new_size - 1;
2280 /* copy the stuff from the older info */
2282 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2284 runtime_info->domain_vtables [domain->domain_id] = vt;
2286 mono_memory_barrier ();
2287 klass->runtime_info = runtime_info;
2290 if (klass == mono_defaults.runtimetype_class) {
2291 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2292 if (!is_ok (error)) {
2293 mono_domain_unlock (domain);
2294 mono_loader_unlock ();
2298 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2299 /* This is unregistered in
2300 unregister_vtable_reflection_type() in
2302 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2305 mono_domain_unlock (domain);
2306 mono_loader_unlock ();
2308 /* make sure the parent is initialized */
2309 /*FIXME shouldn't this fail the current type?*/
2311 mono_class_vtable_full (domain, klass->parent, error);
2316 #ifndef DISABLE_REMOTING
2318 * mono_class_proxy_vtable:
2319 * @domain: the application domain
2320 * @remove_class: the remote class
2321 * @error: set on error
2323 * Creates a vtable for transparent proxies. It is basically
2324 * a copy of the real vtable of the class wrapped in @remote_class,
2325 * but all function pointers invoke the remoting functions, and
2326 * vtable->klass points to the transparent proxy class, and not to @class.
2328 * On failure returns NULL and sets @error
2331 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2333 MONO_REQ_GC_UNSAFE_MODE;
2335 MonoVTable *vt, *pvt;
2336 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2338 GSList *extra_interfaces = NULL;
2339 MonoClass *klass = remote_class->proxy_class;
2340 gpointer *interface_offsets;
2341 uint8_t *bitmap = NULL;
2343 size_t imt_table_bytes;
2345 #ifdef COMPRESSED_INTERFACE_BITMAP
2349 mono_error_init (error);
2351 vt = mono_class_vtable (domain, klass);
2352 g_assert (vt); /*FIXME property handle failure*/
2353 max_interface_id = vt->max_interface_id;
2355 /* Calculate vtable space for extra interfaces */
2356 for (j = 0; j < remote_class->interface_count; j++) {
2357 MonoClass* iclass = remote_class->interfaces[j];
2361 /*FIXME test for interfaces with variant generic arguments*/
2362 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2363 continue; /* interface implemented by the class */
2364 if (g_slist_find (extra_interfaces, iclass))
2367 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2369 method_count = mono_class_num_methods (iclass);
2371 ifaces = mono_class_get_implemented_interfaces (iclass, error);
2375 for (i = 0; i < ifaces->len; ++i) {
2376 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2377 /*FIXME test for interfaces with variant generic arguments*/
2378 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2379 continue; /* interface implemented by the class */
2380 if (g_slist_find (extra_interfaces, ic))
2382 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2383 method_count += mono_class_num_methods (ic);
2385 g_ptr_array_free (ifaces, TRUE);
2389 extra_interface_vtsize += method_count * sizeof (gpointer);
2390 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2393 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2394 mono_stats.imt_number_of_tables++;
2395 mono_stats.imt_tables_size += imt_table_bytes;
2397 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2399 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2401 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2402 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2403 g_assert (!((gsize)pvt & 7));
2405 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2407 pvt->klass = mono_defaults.transparent_proxy_class;
2408 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2409 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2411 /* initialize vtable */
2412 mono_class_setup_vtable (klass);
2413 for (i = 0; i < klass->vtable_size; ++i) {
2416 if ((cm = klass->vtable [i])) {
2417 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2421 pvt->vtable [i] = NULL;
2424 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2425 /* create trampolines for abstract methods */
2426 for (k = klass; k; k = k->parent) {
2428 gpointer iter = NULL;
2429 while ((m = mono_class_get_methods (k, &iter)))
2430 if (!pvt->vtable [m->slot]) {
2431 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type, error);
2438 pvt->max_interface_id = max_interface_id;
2439 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2440 #ifdef COMPRESSED_INTERFACE_BITMAP
2441 bitmap = (uint8_t *)g_malloc0 (bsize);
2443 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2446 for (i = 0; i < klass->interface_offsets_count; ++i) {
2447 int interface_id = klass->interfaces_packed [i]->interface_id;
2448 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2451 if (extra_interfaces) {
2452 int slot = klass->vtable_size;
2458 /* Create trampolines for the methods of the interfaces */
2459 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2460 interf = (MonoClass *)list_item->data;
2462 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2466 while ((cm = mono_class_get_methods (interf, &iter))) {
2467 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type, error);
2472 slot += mono_class_num_methods (interf);
2476 /* Now that the vtable is full, we can actually fill up the IMT */
2477 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2478 if (extra_interfaces) {
2479 g_slist_free (extra_interfaces);
2482 #ifdef COMPRESSED_INTERFACE_BITMAP
2483 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2484 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2485 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2488 pvt->interface_bitmap = bitmap;
2492 if (extra_interfaces)
2493 g_slist_free (extra_interfaces);
2494 #ifdef COMPRESSED_INTERFACE_BITMAP
2500 #endif /* DISABLE_REMOTING */
2503 * mono_class_field_is_special_static:
2505 * Returns whether @field is a thread/context static field.
2508 mono_class_field_is_special_static (MonoClassField *field)
2510 MONO_REQ_GC_NEUTRAL_MODE
2512 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2514 if (mono_field_is_deleted (field))
2516 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2517 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2524 * mono_class_field_get_special_static_type:
2525 * @field: The MonoClassField describing the field.
2527 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2528 * SPECIAL_STATIC_NONE otherwise.
2531 mono_class_field_get_special_static_type (MonoClassField *field)
2533 MONO_REQ_GC_NEUTRAL_MODE
2535 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2536 return SPECIAL_STATIC_NONE;
2537 if (mono_field_is_deleted (field))
2538 return SPECIAL_STATIC_NONE;
2539 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2540 return field_is_special_static (field->parent, field);
2541 return SPECIAL_STATIC_NONE;
2545 * mono_class_has_special_static_fields:
2547 * Returns whenever @klass has any thread/context static fields.
2550 mono_class_has_special_static_fields (MonoClass *klass)
2552 MONO_REQ_GC_NEUTRAL_MODE
2554 MonoClassField *field;
2558 while ((field = mono_class_get_fields (klass, &iter))) {
2559 g_assert (field->parent == klass);
2560 if (mono_class_field_is_special_static (field))
2567 #ifndef DISABLE_REMOTING
2569 * create_remote_class_key:
2570 * Creates an array of pointers that can be used as a hash key for a remote class.
2571 * The first element of the array is the number of pointers.
2574 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2576 MONO_REQ_GC_NEUTRAL_MODE;
2581 if (remote_class == NULL) {
2582 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2583 key = (void **)g_malloc (sizeof(gpointer) * 3);
2584 key [0] = GINT_TO_POINTER (2);
2585 key [1] = mono_defaults.marshalbyrefobject_class;
2586 key [2] = extra_class;
2588 key = (void **)g_malloc (sizeof(gpointer) * 2);
2589 key [0] = GINT_TO_POINTER (1);
2590 key [1] = extra_class;
2593 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2594 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2595 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2596 key [1] = remote_class->proxy_class;
2598 // Keep the list of interfaces sorted
2599 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2600 if (extra_class && remote_class->interfaces [i] > extra_class) {
2601 key [j++] = extra_class;
2604 key [j] = remote_class->interfaces [i];
2607 key [j] = extra_class;
2609 // Replace the old class. The interface list is the same
2610 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2611 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2612 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2613 for (i = 0; i < remote_class->interface_count; i++)
2614 key [2 + i] = remote_class->interfaces [i];
2622 * copy_remote_class_key:
2624 * Make a copy of KEY in the domain and return the copy.
2627 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2629 MONO_REQ_GC_NEUTRAL_MODE
2631 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2632 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2634 memcpy (mp_key, key, key_size);
2640 * mono_remote_class:
2641 * @domain: the application domain
2642 * @class_name: name of the remote class
2643 * @error: set on error
2645 * Creates and initializes a MonoRemoteClass object for a remote type.
2647 * On failure returns NULL and sets @error
2650 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class, MonoError *error)
2652 MONO_REQ_GC_UNSAFE_MODE;
2654 MonoRemoteClass *rc;
2655 gpointer* key, *mp_key;
2658 mono_error_init (error);
2660 key = create_remote_class_key (NULL, proxy_class);
2662 mono_domain_lock (domain);
2663 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2667 mono_domain_unlock (domain);
2671 name = mono_string_to_utf8_mp (domain->mp, class_name, error);
2672 if (!is_ok (error)) {
2674 mono_domain_unlock (domain);
2678 mp_key = copy_remote_class_key (domain, key);
2682 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2683 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2684 rc->interface_count = 1;
2685 rc->interfaces [0] = proxy_class;
2686 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2688 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2689 rc->interface_count = 0;
2690 rc->proxy_class = proxy_class;
2693 rc->default_vtable = NULL;
2694 rc->xdomain_vtable = NULL;
2695 rc->proxy_class_name = name;
2696 #ifndef DISABLE_PERFCOUNTERS
2697 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2700 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2702 mono_domain_unlock (domain);
2707 * clone_remote_class:
2708 * Creates a copy of the remote_class, adding the provided class or interface
2710 static MonoRemoteClass*
2711 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2713 MONO_REQ_GC_NEUTRAL_MODE;
2715 MonoRemoteClass *rc;
2716 gpointer* key, *mp_key;
2718 key = create_remote_class_key (remote_class, extra_class);
2719 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2725 mp_key = copy_remote_class_key (domain, key);
2729 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2731 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2732 rc->proxy_class = remote_class->proxy_class;
2733 rc->interface_count = remote_class->interface_count + 1;
2735 // Keep the list of interfaces sorted, since the hash key of
2736 // the remote class depends on this
2737 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2738 if (remote_class->interfaces [i] > extra_class && i == j)
2739 rc->interfaces [j++] = extra_class;
2740 rc->interfaces [j] = remote_class->interfaces [i];
2743 rc->interfaces [j] = extra_class;
2745 // Replace the old class. The interface array is the same
2746 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2747 rc->proxy_class = extra_class;
2748 rc->interface_count = remote_class->interface_count;
2749 if (rc->interface_count > 0)
2750 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2753 rc->default_vtable = NULL;
2754 rc->xdomain_vtable = NULL;
2755 rc->proxy_class_name = remote_class->proxy_class_name;
2757 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2763 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp, MonoError *error)
2765 MONO_REQ_GC_UNSAFE_MODE;
2767 mono_error_init (error);
2769 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2770 mono_domain_lock (domain);
2771 if (rp->target_domain_id != -1) {
2772 if (remote_class->xdomain_vtable == NULL)
2773 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2774 mono_domain_unlock (domain);
2775 mono_loader_unlock ();
2776 return_val_if_nok (error, NULL);
2777 return remote_class->xdomain_vtable;
2779 if (remote_class->default_vtable == NULL) {
2782 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2783 klass = mono_class_from_mono_type (type);
2785 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)))
2786 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2789 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2790 /* N.B. both branches of the if modify error */
2791 if (!is_ok (error)) {
2792 mono_domain_unlock (domain);
2793 mono_loader_unlock ();
2798 mono_domain_unlock (domain);
2799 mono_loader_unlock ();
2800 return remote_class->default_vtable;
2804 * mono_upgrade_remote_class:
2805 * @domain: the application domain
2806 * @tproxy: the proxy whose remote class has to be upgraded.
2807 * @klass: class to which the remote class can be casted.
2808 * @error: set on error
2810 * Updates the vtable of the remote class by adding the necessary method slots
2811 * and interface offsets so it can be safely casted to klass. klass can be a
2812 * class or an interface. On success returns TRUE, on failure returns FALSE and sets @error.
2815 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass, MonoError *error)
2817 MONO_REQ_GC_UNSAFE_MODE;
2819 MonoTransparentProxy *tproxy;
2820 MonoRemoteClass *remote_class;
2821 gboolean redo_vtable;
2823 mono_error_init (error);
2824 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2825 mono_domain_lock (domain);
2827 tproxy = (MonoTransparentProxy*) proxy_object;
2828 remote_class = tproxy->remote_class;
2830 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2833 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2834 if (remote_class->interfaces [i] == klass)
2835 redo_vtable = FALSE;
2838 redo_vtable = (remote_class->proxy_class != klass);
2842 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2843 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp, error);
2849 mono_domain_unlock (domain);
2850 mono_loader_unlock ();
2851 return is_ok (error);
2853 #endif /* DISABLE_REMOTING */
2857 * mono_object_get_virtual_method:
2858 * @obj: object to operate on.
2861 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2862 * the instance of a callvirt of method.
2865 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2867 MONO_REQ_GC_UNSAFE_MODE;
2870 MonoMethod **vtable;
2871 gboolean is_proxy = FALSE;
2872 MonoMethod *res = NULL;
2874 klass = mono_object_class (obj);
2875 #ifndef DISABLE_REMOTING
2876 if (klass == mono_defaults.transparent_proxy_class) {
2877 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2882 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2885 mono_class_setup_vtable (klass);
2886 vtable = klass->vtable;
2888 if (method->slot == -1) {
2889 /* method->slot might not be set for instances of generic methods */
2890 if (method->is_inflated) {
2891 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2892 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2895 g_assert_not_reached ();
2899 /* check method->slot is a valid index: perform isinstance? */
2900 if (method->slot != -1) {
2901 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2903 gboolean variance_used = FALSE;
2904 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2905 g_assert (iface_offset > 0);
2906 res = vtable [iface_offset + method->slot];
2909 res = vtable [method->slot];
2913 #ifndef DISABLE_REMOTING
2915 /* It may be an interface, abstract class method or generic method */
2916 if (!res || mono_method_signature (res)->generic_param_count)
2919 /* generic methods demand invoke_with_check */
2920 if (mono_method_signature (res)->generic_param_count)
2921 res = mono_marshal_get_remoting_invoke_with_check (res);
2924 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2925 res = mono_cominterop_get_invoke (res);
2928 res = mono_marshal_get_remoting_invoke (res);
2933 if (method->is_inflated) {
2935 /* Have to inflate the result */
2936 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2937 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2947 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2949 MONO_REQ_GC_UNSAFE_MODE;
2951 MonoObject *result = NULL;
2953 g_assert (callbacks.runtime_invoke);
2955 mono_error_init (error);
2957 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2958 mono_profiler_method_start_invoke (method);
2960 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2962 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2963 mono_profiler_method_end_invoke (method);
2965 if (!mono_error_ok (error))
2972 * mono_runtime_invoke:
2973 * @method: method to invoke
2974 * @obJ: object instance
2975 * @params: arguments to the method
2976 * @exc: exception information.
2978 * Invokes the method represented by @method on the object @obj.
2980 * obj is the 'this' pointer, it should be NULL for static
2981 * methods, a MonoObject* for object instances and a pointer to
2982 * the value type for value types.
2984 * The params array contains the arguments to the method with the
2985 * same convention: MonoObject* pointers for object instances and
2986 * pointers to the value type otherwise.
2988 * From unmanaged code you'll usually use the
2989 * mono_runtime_invoke() variant.
2991 * Note that this function doesn't handle virtual methods for
2992 * you, it will exec the exact method you pass: we still need to
2993 * expose a function to lookup the derived class implementation
2994 * of a virtual method (there are examples of this in the code,
2997 * You can pass NULL as the exc argument if you don't want to
2998 * catch exceptions, otherwise, *exc will be set to the exception
2999 * thrown, if any. if an exception is thrown, you can't use the
3000 * MonoObject* result from the function.
3002 * If the method returns a value type, it is boxed in an object
3006 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
3011 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
3012 if (*exc == NULL && !mono_error_ok(&error)) {
3013 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3015 mono_error_cleanup (&error);
3017 res = mono_runtime_invoke_checked (method, obj, params, &error);
3018 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
3024 * mono_runtime_try_invoke:
3025 * @method: method to invoke
3026 * @obJ: object instance
3027 * @params: arguments to the method
3028 * @exc: exception information.
3029 * @error: set on error
3031 * Invokes the method represented by @method on the object @obj.
3033 * obj is the 'this' pointer, it should be NULL for static
3034 * methods, a MonoObject* for object instances and a pointer to
3035 * the value type for value types.
3037 * The params array contains the arguments to the method with the
3038 * same convention: MonoObject* pointers for object instances and
3039 * pointers to the value type otherwise.
3041 * From unmanaged code you'll usually use the
3042 * mono_runtime_invoke() variant.
3044 * Note that this function doesn't handle virtual methods for
3045 * you, it will exec the exact method you pass: we still need to
3046 * expose a function to lookup the derived class implementation
3047 * of a virtual method (there are examples of this in the code,
3050 * For this function, you must not pass NULL as the exc argument if
3051 * you don't want to catch exceptions, use
3052 * mono_runtime_invoke_checked(). If an exception is thrown, you
3053 * can't use the MonoObject* result from the function.
3055 * If this method cannot be invoked, @error will be set and @exc and
3056 * the return value must not be used.
3058 * If the method returns a value type, it is boxed in an object
3062 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
3064 MONO_REQ_GC_UNSAFE_MODE;
3066 g_assert (exc != NULL);
3068 if (mono_runtime_get_no_exec ())
3069 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3071 return do_runtime_invoke (method, obj, params, exc, error);
3075 * mono_runtime_invoke_checked:
3076 * @method: method to invoke
3077 * @obJ: object instance
3078 * @params: arguments to the method
3079 * @error: set on error
3081 * Invokes the method represented by @method on the object @obj.
3083 * obj is the 'this' pointer, it should be NULL for static
3084 * methods, a MonoObject* for object instances and a pointer to
3085 * the value type for value types.
3087 * The params array contains the arguments to the method with the
3088 * same convention: MonoObject* pointers for object instances and
3089 * pointers to the value type otherwise.
3091 * From unmanaged code you'll usually use the
3092 * mono_runtime_invoke() variant.
3094 * Note that this function doesn't handle virtual methods for
3095 * you, it will exec the exact method you pass: we still need to
3096 * expose a function to lookup the derived class implementation
3097 * of a virtual method (there are examples of this in the code,
3100 * If an exception is thrown, you can't use the MonoObject* result
3101 * from the function.
3103 * If this method cannot be invoked, @error will be set. If the
3104 * method throws an exception (and we're in coop mode) the exception
3105 * will be set in @error.
3107 * If the method returns a value type, it is boxed in an object
3111 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3113 MONO_REQ_GC_UNSAFE_MODE;
3115 if (mono_runtime_get_no_exec ())
3116 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3118 return do_runtime_invoke (method, obj, params, NULL, error);
3122 * mono_method_get_unmanaged_thunk:
3123 * @method: method to generate a thunk for.
3125 * Returns an unmanaged->managed thunk that can be used to call
3126 * a managed method directly from C.
3128 * The thunk's C signature closely matches the managed signature:
3130 * C#: public bool Equals (object obj);
3131 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3132 * MonoObject*, MonoException**);
3134 * The 1st ("this") parameter must not be used with static methods:
3136 * C#: public static bool ReferenceEquals (object a, object b);
3137 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3140 * The last argument must be a non-null pointer of a MonoException* pointer.
3141 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3142 * exception has been thrown in managed code. Otherwise it will point
3143 * to the MonoException* caught by the thunk. In this case, the result of
3144 * the thunk is undefined:
3146 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3147 * MonoException *ex = NULL;
3148 * Equals func = mono_method_get_unmanaged_thunk (method);
3149 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3151 * // handle exception
3154 * The calling convention of the thunk matches the platform's default
3155 * convention. This means that under Windows, C declarations must
3156 * contain the __stdcall attribute:
3158 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3159 * MonoObject*, MonoException**);
3163 * Value type arguments and return values are treated as they were objects:
3165 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3166 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3168 * Arguments must be properly boxed upon trunk's invocation, while return
3169 * values must be unboxed.
3172 mono_method_get_unmanaged_thunk (MonoMethod *method)
3174 MONO_REQ_GC_NEUTRAL_MODE;
3175 MONO_REQ_API_ENTRYPOINT;
3180 g_assert (!mono_threads_is_coop_enabled ());
3182 MONO_ENTER_GC_UNSAFE;
3183 method = mono_marshal_get_thunk_invoke_wrapper (method);
3184 res = mono_compile_method_checked (method, &error);
3185 mono_error_cleanup (&error);
3186 MONO_EXIT_GC_UNSAFE;
3192 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3194 MONO_REQ_GC_UNSAFE_MODE;
3198 /* object fields cannot be byref, so we don't need a
3200 gpointer *p = (gpointer*)dest;
3207 case MONO_TYPE_BOOLEAN:
3209 case MONO_TYPE_U1: {
3210 guint8 *p = (guint8*)dest;
3211 *p = value ? *(guint8*)value : 0;
3216 case MONO_TYPE_CHAR: {
3217 guint16 *p = (guint16*)dest;
3218 *p = value ? *(guint16*)value : 0;
3221 #if SIZEOF_VOID_P == 4
3226 case MONO_TYPE_U4: {
3227 gint32 *p = (gint32*)dest;
3228 *p = value ? *(gint32*)value : 0;
3231 #if SIZEOF_VOID_P == 8
3236 case MONO_TYPE_U8: {
3237 gint64 *p = (gint64*)dest;
3238 *p = value ? *(gint64*)value : 0;
3241 case MONO_TYPE_R4: {
3242 float *p = (float*)dest;
3243 *p = value ? *(float*)value : 0;
3246 case MONO_TYPE_R8: {
3247 double *p = (double*)dest;
3248 *p = value ? *(double*)value : 0;
3251 case MONO_TYPE_STRING:
3252 case MONO_TYPE_SZARRAY:
3253 case MONO_TYPE_CLASS:
3254 case MONO_TYPE_OBJECT:
3255 case MONO_TYPE_ARRAY:
3256 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3258 case MONO_TYPE_FNPTR:
3259 case MONO_TYPE_PTR: {
3260 gpointer *p = (gpointer*)dest;
3261 *p = deref_pointer? *(gpointer*)value: value;
3264 case MONO_TYPE_VALUETYPE:
3265 /* note that 't' and 'type->type' can be different */
3266 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3267 t = mono_class_enum_basetype (type->data.klass)->type;
3270 MonoClass *klass = mono_class_from_mono_type (type);
3271 int size = mono_class_value_size (klass, NULL);
3273 mono_gc_bzero_atomic (dest, size);
3275 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3278 case MONO_TYPE_GENERICINST:
3279 t = type->data.generic_class->container_class->byval_arg.type;
3282 g_error ("got type %x", type->type);
3287 * mono_field_set_value:
3288 * @obj: Instance object
3289 * @field: MonoClassField describing the field to set
3290 * @value: The value to be set
3292 * Sets the value of the field described by @field in the object instance @obj
3293 * to the value passed in @value. This method should only be used for instance
3294 * fields. For static fields, use mono_field_static_set_value.
3296 * The value must be on the native format of the field type.
3299 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3301 MONO_REQ_GC_UNSAFE_MODE;
3305 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3307 dest = (char*)obj + field->offset;
3308 mono_copy_value (field->type, dest, value, FALSE);
3312 * mono_field_static_set_value:
3313 * @field: MonoClassField describing the field to set
3314 * @value: The value to be set
3316 * Sets the value of the static field described by @field
3317 * to the value passed in @value.
3319 * The value must be on the native format of the field type.
3322 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3324 MONO_REQ_GC_UNSAFE_MODE;
3328 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3329 /* you cant set a constant! */
3330 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3332 if (field->offset == -1) {
3333 /* Special static */
3336 mono_domain_lock (vt->domain);
3337 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3338 mono_domain_unlock (vt->domain);
3339 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3341 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3343 mono_copy_value (field->type, dest, value, FALSE);
3347 * mono_vtable_get_static_field_data:
3349 * Internal use function: return a pointer to the memory holding the static fields
3350 * for a class or NULL if there are no static fields.
3351 * This is exported only for use by the debugger.
3354 mono_vtable_get_static_field_data (MonoVTable *vt)
3356 MONO_REQ_GC_NEUTRAL_MODE
3358 if (!vt->has_static_fields)
3360 return vt->vtable [vt->klass->vtable_size];
3364 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3366 MONO_REQ_GC_UNSAFE_MODE;
3370 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3371 if (field->offset == -1) {
3372 /* Special static */
3375 mono_domain_lock (vt->domain);
3376 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3377 mono_domain_unlock (vt->domain);
3378 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3380 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3383 src = (guint8*)obj + field->offset;
3390 * mono_field_get_value:
3391 * @obj: Object instance
3392 * @field: MonoClassField describing the field to fetch information from
3393 * @value: pointer to the location where the value will be stored
3395 * Use this routine to get the value of the field @field in the object
3398 * The pointer provided by value must be of the field type, for reference
3399 * types this is a MonoObject*, for value types its the actual pointer to
3404 * mono_field_get_value (obj, int_field, &i);
3407 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3409 MONO_REQ_GC_UNSAFE_MODE;
3415 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3417 src = (char*)obj + field->offset;
3418 mono_copy_value (field->type, value, src, TRUE);
3422 * mono_field_get_value_object:
3423 * @domain: domain where the object will be created (if boxing)
3424 * @field: MonoClassField describing the field to fetch information from
3425 * @obj: The object instance for the field.
3427 * Returns: a new MonoObject with the value from the given field. If the
3428 * field represents a value type, the value is boxed.
3432 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3435 MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3436 mono_error_assert_ok (&error);
3441 * mono_field_get_value_object_checked:
3442 * @domain: domain where the object will be created (if boxing)
3443 * @field: MonoClassField describing the field to fetch information from
3444 * @obj: The object instance for the field.
3445 * @error: Set on error.
3447 * Returns: a new MonoObject with the value from the given field. If the
3448 * field represents a value type, the value is boxed. On error returns NULL and sets @error.
3452 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3454 MONO_REQ_GC_UNSAFE_MODE;
3456 mono_error_init (error);
3460 MonoVTable *vtable = NULL;
3462 gboolean is_static = FALSE;
3463 gboolean is_ref = FALSE;
3464 gboolean is_literal = FALSE;
3465 gboolean is_ptr = FALSE;
3466 MonoType *type = mono_field_get_type_checked (field, error);
3468 return_val_if_nok (error, NULL);
3470 switch (type->type) {
3471 case MONO_TYPE_STRING:
3472 case MONO_TYPE_OBJECT:
3473 case MONO_TYPE_CLASS:
3474 case MONO_TYPE_ARRAY:
3475 case MONO_TYPE_SZARRAY:
3480 case MONO_TYPE_BOOLEAN:
3483 case MONO_TYPE_CHAR:
3492 case MONO_TYPE_VALUETYPE:
3493 is_ref = type->byref;
3495 case MONO_TYPE_GENERICINST:
3496 is_ref = !mono_type_generic_inst_is_valuetype (type);
3502 g_error ("type 0x%x not handled in "
3503 "mono_field_get_value_object", type->type);
3507 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3510 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3514 vtable = mono_class_vtable_full (domain, field->parent, error);
3515 return_val_if_nok (error, NULL);
3517 if (!vtable->initialized) {
3518 mono_runtime_class_init_full (vtable, error);
3519 return_val_if_nok (error, NULL);
3528 get_default_field_value (domain, field, &o, error);
3529 return_val_if_nok (error, NULL);
3530 } else if (is_static) {
3531 mono_field_static_get_value_checked (vtable, field, &o, error);
3532 return_val_if_nok (error, NULL);
3534 mono_field_get_value (obj, field, &o);
3540 static MonoMethod *m;
3546 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3547 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3553 get_default_field_value (domain, field, v, error);
3554 return_val_if_nok (error, NULL);
3555 } else if (is_static) {
3556 mono_field_static_get_value_checked (vtable, field, v, error);
3557 return_val_if_nok (error, NULL);
3559 mono_field_get_value (obj, field, v);
3562 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3563 args [0] = ptr ? *ptr : NULL;
3564 args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3565 return_val_if_nok (error, NULL);
3567 o = mono_runtime_invoke_checked (m, NULL, args, error);
3568 return_val_if_nok (error, NULL);
3573 /* boxed value type */
3574 klass = mono_class_from_mono_type (type);
3576 if (mono_class_is_nullable (klass))
3577 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3579 o = mono_object_new_checked (domain, klass, error);
3580 return_val_if_nok (error, NULL);
3581 v = ((gchar *) o) + sizeof (MonoObject);
3584 get_default_field_value (domain, field, v, error);
3585 return_val_if_nok (error, NULL);
3586 } else if (is_static) {
3587 mono_field_static_get_value_checked (vtable, field, v, error);
3588 return_val_if_nok (error, NULL);
3590 mono_field_get_value (obj, field, v);
3597 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3599 MONO_REQ_GC_UNSAFE_MODE;
3601 mono_error_init (error);
3603 const char *p = blob;
3604 mono_metadata_decode_blob_size (p, &p);
3607 case MONO_TYPE_BOOLEAN:
3610 *(guint8 *) value = *p;
3612 case MONO_TYPE_CHAR:
3615 *(guint16*) value = read16 (p);
3619 *(guint32*) value = read32 (p);
3623 *(guint64*) value = read64 (p);
3626 readr4 (p, (float*) value);
3629 readr8 (p, (double*) value);
3631 case MONO_TYPE_STRING:
3632 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3634 case MONO_TYPE_CLASS:
3635 *(gpointer*) value = NULL;
3639 g_warning ("type 0x%02x should not be in constant table", type);
3645 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3647 MONO_REQ_GC_NEUTRAL_MODE;
3649 MonoTypeEnum def_type;
3652 mono_error_init (error);
3654 data = mono_class_get_field_default_value (field, &def_type);
3655 mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3659 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3661 MONO_REQ_GC_UNSAFE_MODE;
3665 mono_error_init (error);
3667 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3669 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3670 get_default_field_value (vt->domain, field, value, error);
3674 if (field->offset == -1) {
3675 /* Special static */
3676 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3677 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3679 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3681 mono_copy_value (field->type, value, src, TRUE);
3685 * mono_field_static_get_value:
3686 * @vt: vtable to the object
3687 * @field: MonoClassField describing the field to fetch information from
3688 * @value: where the value is returned
3690 * Use this routine to get the value of the static field @field value.
3692 * The pointer provided by value must be of the field type, for reference
3693 * types this is a MonoObject*, for value types its the actual pointer to
3698 * mono_field_static_get_value (vt, int_field, &i);
3701 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3703 MONO_REQ_GC_NEUTRAL_MODE;
3706 mono_field_static_get_value_checked (vt, field, value, &error);
3707 mono_error_cleanup (&error);
3711 * mono_field_static_get_value_checked:
3712 * @vt: vtable to the object
3713 * @field: MonoClassField describing the field to fetch information from
3714 * @value: where the value is returned
3715 * @error: set on error
3717 * Use this routine to get the value of the static field @field value.
3719 * The pointer provided by value must be of the field type, for reference
3720 * types this is a MonoObject*, for value types its the actual pointer to
3725 * mono_field_static_get_value_checked (vt, int_field, &i, error);
3726 * if (!is_ok (error)) { ... }
3728 * On failure sets @error.
3731 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3733 MONO_REQ_GC_NEUTRAL_MODE;
3735 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3739 * mono_property_set_value:
3740 * @prop: MonoProperty to set
3741 * @obj: instance object on which to act
3742 * @params: parameters to pass to the propery
3743 * @exc: optional exception
3745 * Invokes the property's set method with the given arguments on the
3746 * object instance obj (or NULL for static properties).
3748 * You can pass NULL as the exc argument if you don't want to
3749 * catch exceptions, otherwise, *exc will be set to the exception
3750 * thrown, if any. if an exception is thrown, you can't use the
3751 * MonoObject* result from the function.
3754 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3756 MONO_REQ_GC_UNSAFE_MODE;
3759 do_runtime_invoke (prop->set, obj, params, exc, &error);
3760 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3761 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3763 mono_error_cleanup (&error);
3768 * mono_property_set_value_checked:
3769 * @prop: MonoProperty to set
3770 * @obj: instance object on which to act
3771 * @params: parameters to pass to the propery
3772 * @error: set on error
3774 * Invokes the property's set method with the given arguments on the
3775 * object instance obj (or NULL for static properties).
3777 * Returns: TRUE on success. On failure returns FALSE and sets @error.
3778 * If an exception is thrown, it will be caught and returned via @error.
3781 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3783 MONO_REQ_GC_UNSAFE_MODE;
3787 mono_error_init (error);
3788 do_runtime_invoke (prop->set, obj, params, &exc, error);
3789 if (exc != NULL && is_ok (error))
3790 mono_error_set_exception_instance (error, (MonoException*)exc);
3791 return is_ok (error);
3795 * mono_property_get_value:
3796 * @prop: MonoProperty to fetch
3797 * @obj: instance object on which to act
3798 * @params: parameters to pass to the propery
3799 * @exc: optional exception
3801 * Invokes the property's get method with the given arguments on the
3802 * object instance obj (or NULL for static properties).
3804 * You can pass NULL as the exc argument if you don't want to
3805 * catch exceptions, otherwise, *exc will be set to the exception
3806 * thrown, if any. if an exception is thrown, you can't use the
3807 * MonoObject* result from the function.
3809 * Returns: the value from invoking the get method on the property.
3812 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3814 MONO_REQ_GC_UNSAFE_MODE;
3817 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3818 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3819 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3821 mono_error_cleanup (&error); /* FIXME don't raise here */
3828 * mono_property_get_value_checked:
3829 * @prop: MonoProperty to fetch
3830 * @obj: instance object on which to act
3831 * @params: parameters to pass to the propery
3832 * @error: set on error
3834 * Invokes the property's get method with the given arguments on the
3835 * object instance obj (or NULL for static properties).
3837 * If an exception is thrown, you can't use the
3838 * MonoObject* result from the function. The exception will be propagated via @error.
3840 * Returns: the value from invoking the get method on the property. On
3841 * failure returns NULL and sets @error.
3844 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3846 MONO_REQ_GC_UNSAFE_MODE;
3849 MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3850 if (exc != NULL && !is_ok (error))
3851 mono_error_set_exception_instance (error, (MonoException*) exc);
3859 * mono_nullable_init:
3860 * @buf: The nullable structure to initialize.
3861 * @value: the value to initialize from
3862 * @klass: the type for the object
3864 * Initialize the nullable structure pointed to by @buf from @value which
3865 * should be a boxed value type. The size of @buf should be able to hold
3866 * as much data as the @klass->instance_size (which is the number of bytes
3867 * that will be copies).
3869 * Since Nullables have variable structure, we can not define a C
3870 * structure for them.
3873 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3875 MONO_REQ_GC_UNSAFE_MODE;
3877 MonoClass *param_class = klass->cast_class;
3879 mono_class_setup_fields_locking (klass);
3880 g_assert (klass->fields_inited);
3882 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3883 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3885 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3887 if (param_class->has_references)
3888 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3890 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3892 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3897 * mono_nullable_box:
3898 * @buf: The buffer representing the data to be boxed
3899 * @klass: the type to box it as.
3900 * @error: set on oerr
3902 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3903 * @buf. On failure returns NULL and sets @error
3906 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3908 MONO_REQ_GC_UNSAFE_MODE;
3910 mono_error_init (error);
3911 MonoClass *param_class = klass->cast_class;
3913 mono_class_setup_fields_locking (klass);
3914 g_assert (klass->fields_inited);
3916 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3917 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3919 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3920 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3921 return_val_if_nok (error, NULL);
3922 if (param_class->has_references)
3923 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3925 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3933 * mono_get_delegate_invoke:
3934 * @klass: The delegate class
3936 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3939 mono_get_delegate_invoke (MonoClass *klass)
3941 MONO_REQ_GC_NEUTRAL_MODE;
3945 /* This is called at runtime, so avoid the slower search in metadata */
3946 mono_class_setup_methods (klass);
3947 if (mono_class_has_failure (klass))
3949 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3954 * mono_get_delegate_begin_invoke:
3955 * @klass: The delegate class
3957 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3960 mono_get_delegate_begin_invoke (MonoClass *klass)
3962 MONO_REQ_GC_NEUTRAL_MODE;
3966 /* This is called at runtime, so avoid the slower search in metadata */
3967 mono_class_setup_methods (klass);
3968 if (mono_class_has_failure (klass))
3970 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3975 * mono_get_delegate_end_invoke:
3976 * @klass: The delegate class
3978 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3981 mono_get_delegate_end_invoke (MonoClass *klass)
3983 MONO_REQ_GC_NEUTRAL_MODE;
3987 /* This is called at runtime, so avoid the slower search in metadata */
3988 mono_class_setup_methods (klass);
3989 if (mono_class_has_failure (klass))
3991 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3996 * mono_runtime_delegate_invoke:
3997 * @delegate: pointer to a delegate object.
3998 * @params: parameters for the delegate.
3999 * @exc: Pointer to the exception result.
4001 * Invokes the delegate method @delegate with the parameters provided.
4003 * You can pass NULL as the exc argument if you don't want to
4004 * catch exceptions, otherwise, *exc will be set to the exception
4005 * thrown, if any. if an exception is thrown, you can't use the
4006 * MonoObject* result from the function.
4009 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
4011 MONO_REQ_GC_UNSAFE_MODE;
4015 MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
4017 mono_error_cleanup (&error);
4020 if (!is_ok (&error))
4021 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
4025 MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
4026 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
4032 * mono_runtime_delegate_try_invoke:
4033 * @delegate: pointer to a delegate object.
4034 * @params: parameters for the delegate.
4035 * @exc: Pointer to the exception result.
4036 * @error: set on error
4038 * Invokes the delegate method @delegate with the parameters provided.
4040 * You can pass NULL as the exc argument if you don't want to
4041 * catch exceptions, otherwise, *exc will be set to the exception
4042 * thrown, if any. On failure to execute, @error will be set.
4043 * if an exception is thrown, you can't use the
4044 * MonoObject* result from the function.
4047 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4049 MONO_REQ_GC_UNSAFE_MODE;
4051 mono_error_init (error);
4053 MonoClass *klass = delegate->vtable->klass;
4056 im = mono_get_delegate_invoke (klass);
4058 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4061 o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4063 o = mono_runtime_invoke_checked (im, delegate, params, error);
4070 * mono_runtime_delegate_invoke_checked:
4071 * @delegate: pointer to a delegate object.
4072 * @params: parameters for the delegate.
4073 * @error: set on error
4075 * Invokes the delegate method @delegate with the parameters provided.
4077 * On failure @error will be set and you can't use the MonoObject*
4078 * result from the function.
4081 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4083 mono_error_init (error);
4084 return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4087 static char **main_args = NULL;
4088 static int num_main_args = 0;
4091 * mono_runtime_get_main_args:
4093 * Returns: a MonoArray with the arguments passed to the main program
4096 mono_runtime_get_main_args (void)
4098 MONO_REQ_GC_UNSAFE_MODE;
4100 MonoArray *result = mono_runtime_get_main_args_checked (&error);
4101 mono_error_assert_ok (&error);
4106 * mono_runtime_get_main_args:
4107 * @error: set on error
4109 * Returns: a MonoArray with the arguments passed to the main
4110 * program. On failure returns NULL and sets @error.
4113 mono_runtime_get_main_args_checked (MonoError *error)
4117 MonoDomain *domain = mono_domain_get ();
4119 mono_error_init (error);
4121 res = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, num_main_args, error);
4122 return_val_if_nok (error, NULL);
4124 for (i = 0; i < num_main_args; ++i)
4125 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
4131 free_main_args (void)
4133 MONO_REQ_GC_NEUTRAL_MODE;
4137 for (i = 0; i < num_main_args; ++i)
4138 g_free (main_args [i]);
4145 * mono_runtime_set_main_args:
4146 * @argc: number of arguments from the command line
4147 * @argv: array of strings from the command line
4149 * Set the command line arguments from an embedding application that doesn't otherwise call
4150 * mono_runtime_run_main ().
4153 mono_runtime_set_main_args (int argc, char* argv[])
4155 MONO_REQ_GC_NEUTRAL_MODE;
4160 main_args = g_new0 (char*, argc);
4161 num_main_args = argc;
4163 for (i = 0; i < argc; ++i) {
4166 utf8_arg = mono_utf8_from_external (argv[i]);
4167 if (utf8_arg == NULL) {
4168 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4169 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4173 main_args [i] = utf8_arg;
4180 * Prepare an array of arguments in order to execute a standard Main()
4181 * method (argc/argv contains the executable name). This method also
4182 * sets the command line argument value needed by System.Environment.
4186 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4188 MONO_REQ_GC_UNSAFE_MODE;
4192 MonoArray *args = NULL;
4193 MonoDomain *domain = mono_domain_get ();
4194 gchar *utf8_fullpath;
4195 MonoMethodSignature *sig;
4197 g_assert (method != NULL);
4199 mono_thread_set_main (mono_thread_current ());
4201 main_args = g_new0 (char*, argc);
4202 num_main_args = argc;
4204 if (!g_path_is_absolute (argv [0])) {
4205 gchar *basename = g_path_get_basename (argv [0]);
4206 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4210 utf8_fullpath = mono_utf8_from_external (fullpath);
4211 if(utf8_fullpath == NULL) {
4212 /* Printing the arg text will cause glib to
4213 * whinge about "Invalid UTF-8", but at least
4214 * its relevant, and shows the problem text
4217 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4218 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4225 utf8_fullpath = mono_utf8_from_external (argv[0]);
4226 if(utf8_fullpath == NULL) {
4227 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4228 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4233 main_args [0] = utf8_fullpath;
4235 for (i = 1; i < argc; ++i) {
4238 utf8_arg=mono_utf8_from_external (argv[i]);
4239 if(utf8_arg==NULL) {
4240 /* Ditto the comment about Invalid UTF-8 here */
4241 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4242 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4246 main_args [i] = utf8_arg;
4251 sig = mono_method_signature (method);
4253 g_print ("Unable to load Main method.\n");
4257 if (sig->param_count) {
4258 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4259 mono_error_assert_ok (&error);
4260 for (i = 0; i < argc; ++i) {
4261 /* The encodings should all work, given that
4262 * we've checked all these args for the
4265 gchar *str = mono_utf8_from_external (argv [i]);
4266 MonoString *arg = mono_string_new (domain, str);
4267 mono_array_setref (args, i, arg);
4271 args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4272 mono_error_assert_ok (&error);
4275 mono_assembly_set_main (method->klass->image->assembly);
4281 * mono_runtime_run_main:
4282 * @method: the method to start the application with (usually Main)
4283 * @argc: number of arguments from the command line
4284 * @argv: array of strings from the command line
4285 * @exc: excetption results
4287 * Execute a standard Main() method (argc/argv contains the
4288 * executable name). This method also sets the command line argument value
4289 * needed by System.Environment.
4294 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4297 MONO_REQ_GC_UNSAFE_MODE;
4300 MonoArray *args = prepare_run_main (method, argc, argv);
4303 res = mono_runtime_try_exec_main (method, args, exc);
4305 res = mono_runtime_exec_main_checked (method, args, &error);
4306 mono_error_raise_exception (&error); /* OK to throw, external only without a better alternative */
4312 * mono_runtime_run_main_checked:
4313 * @method: the method to start the application with (usually Main)
4314 * @argc: number of arguments from the command line
4315 * @argv: array of strings from the command line
4316 * @error: set on error
4318 * Execute a standard Main() method (argc/argv contains the
4319 * executable name). This method also sets the command line argument value
4320 * needed by System.Environment. On failure sets @error.
4325 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4328 mono_error_init (error);
4329 MonoArray *args = prepare_run_main (method, argc, argv);
4330 return mono_runtime_exec_main_checked (method, args, error);
4334 * mono_runtime_try_run_main:
4335 * @method: the method to start the application with (usually Main)
4336 * @argc: number of arguments from the command line
4337 * @argv: array of strings from the command line
4338 * @exc: set if Main throws an exception
4339 * @error: set if Main can't be executed
4341 * Execute a standard Main() method (argc/argv contains the executable
4342 * name). This method also sets the command line argument value needed
4343 * by System.Environment. On failure sets @error if Main can't be
4344 * executed or @exc if it threw and exception.
4349 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4353 MonoArray *args = prepare_run_main (method, argc, argv);
4354 return mono_runtime_try_exec_main (method, args, exc);
4359 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4361 static MonoMethod *serialize_method;
4367 if (!serialize_method) {
4368 MonoClass *klass = mono_class_get_remoting_services_class ();
4369 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4372 if (!serialize_method) {
4377 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4382 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4383 if (*exc == NULL && !mono_error_ok (&error))
4384 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4386 mono_error_cleanup (&error);
4395 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4397 MONO_REQ_GC_UNSAFE_MODE;
4399 static MonoMethod *deserialize_method;
4405 if (!deserialize_method) {
4406 MonoClass *klass = mono_class_get_remoting_services_class ();
4407 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4409 if (!deserialize_method) {
4417 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4418 if (*exc == NULL && !mono_error_ok (&error))
4419 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4421 mono_error_cleanup (&error);
4429 #ifndef DISABLE_REMOTING
4431 make_transparent_proxy (MonoObject *obj, MonoError *error)
4433 MONO_REQ_GC_UNSAFE_MODE;
4435 static MonoMethod *get_proxy_method;
4437 MonoDomain *domain = mono_domain_get ();
4438 MonoRealProxy *real_proxy;
4439 MonoReflectionType *reflection_type;
4440 MonoTransparentProxy *transparent_proxy;
4442 mono_error_init (error);
4444 if (!get_proxy_method)
4445 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4447 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4449 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4450 return_val_if_nok (error, NULL);
4451 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4452 return_val_if_nok (error, NULL);
4454 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4455 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4457 MonoObject *exc = NULL;
4459 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4460 if (exc != NULL && is_ok (error))
4461 mono_error_set_exception_instance (error, (MonoException*)exc);
4463 return (MonoObject*) transparent_proxy;
4465 #endif /* DISABLE_REMOTING */
4468 * mono_object_xdomain_representation
4470 * @target_domain: a domain
4471 * @error: set on error.
4473 * Creates a representation of obj in the domain target_domain. This
4474 * is either a copy of obj arrived through via serialization and
4475 * deserialization or a proxy, depending on whether the object is
4476 * serializable or marshal by ref. obj must not be in target_domain.
4478 * If the object cannot be represented in target_domain, NULL is
4479 * returned and @error is set appropriately.
4482 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4484 MONO_REQ_GC_UNSAFE_MODE;
4486 mono_error_init (error);
4487 MonoObject *deserialized = NULL;
4489 #ifndef DISABLE_REMOTING
4490 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4491 deserialized = make_transparent_proxy (obj, error);
4496 gboolean failure = FALSE;
4497 MonoDomain *domain = mono_domain_get ();
4498 MonoObject *serialized;
4499 MonoObject *exc = NULL;
4501 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4502 serialized = serialize_object (obj, &failure, &exc);
4503 mono_domain_set_internal_with_options (target_domain, FALSE);
4505 deserialized = deserialize_object (serialized, &failure, &exc);
4506 if (domain != target_domain)
4507 mono_domain_set_internal_with_options (domain, FALSE);
4509 mono_error_set_exception_instance (error, (MonoException*)exc);
4512 return deserialized;
4515 /* Used in call_unhandled_exception_delegate */
4517 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4519 MONO_REQ_GC_UNSAFE_MODE;
4521 mono_error_init (error);
4524 MonoMethod *method = NULL;
4525 MonoBoolean is_terminating = TRUE;
4528 klass = mono_class_get_unhandled_exception_event_args_class ();
4529 mono_class_init (klass);
4531 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4532 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4536 args [1] = &is_terminating;
4538 obj = mono_object_new_checked (mono_domain_get (), klass, error);
4539 return_val_if_nok (error, NULL);
4541 mono_runtime_invoke_checked (method, obj, args, error);
4542 return_val_if_nok (error, NULL);
4547 /* Used in mono_unhandled_exception */
4549 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4550 MONO_REQ_GC_UNSAFE_MODE;
4553 MonoObject *e = NULL;
4555 MonoDomain *current_domain = mono_domain_get ();
4557 if (domain != current_domain)
4558 mono_domain_set_internal_with_options (domain, FALSE);
4560 g_assert (domain == mono_object_domain (domain->domain));
4562 if (mono_object_domain (exc) != domain) {
4564 exc = mono_object_xdomain_representation (exc, domain, &error);
4566 if (!is_ok (&error)) {
4567 MonoError inner_error;
4568 MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4569 exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4570 mono_error_assert_ok (&inner_error);
4572 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4573 "System.Runtime.Serialization", "SerializationException",
4574 "Could not serialize unhandled exception.");
4578 g_assert (mono_object_domain (exc) == domain);
4580 pa [0] = domain->domain;
4581 pa [1] = create_unhandled_exception_eventargs (exc, &error);
4582 mono_error_assert_ok (&error);
4583 mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4584 if (!is_ok (&error)) {
4586 e = (MonoObject*)mono_error_convert_to_exception (&error);
4588 mono_error_cleanup (&error);
4591 if (domain != current_domain)
4592 mono_domain_set_internal_with_options (current_domain, FALSE);
4595 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4596 if (!mono_error_ok (&error)) {
4597 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4598 mono_error_cleanup (&error);
4600 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4606 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4609 * mono_runtime_unhandled_exception_policy_set:
4610 * @policy: the new policy
4612 * This is a VM internal routine.
4614 * Sets the runtime policy for handling unhandled exceptions.
4617 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4618 runtime_unhandled_exception_policy = policy;
4622 * mono_runtime_unhandled_exception_policy_get:
4624 * This is a VM internal routine.
4626 * Gets the runtime policy for handling unhandled exceptions.
4628 MonoRuntimeUnhandledExceptionPolicy
4629 mono_runtime_unhandled_exception_policy_get (void) {
4630 return runtime_unhandled_exception_policy;
4634 * mono_unhandled_exception:
4635 * @exc: exception thrown
4637 * This is a VM internal routine.
4639 * We call this function when we detect an unhandled exception
4640 * in the default domain.
4642 * It invokes the * UnhandledException event in AppDomain or prints
4643 * a warning to the console
4646 mono_unhandled_exception (MonoObject *exc)
4648 MONO_REQ_GC_UNSAFE_MODE;
4651 MonoClassField *field;
4652 MonoDomain *current_domain, *root_domain;
4653 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4655 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4658 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4661 current_domain = mono_domain_get ();
4662 root_domain = mono_get_root_domain ();
4664 root_appdomain_delegate = mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, &error);
4665 mono_error_assert_ok (&error);
4666 if (current_domain != root_domain) {
4667 current_appdomain_delegate = mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, &error);
4668 mono_error_assert_ok (&error);
4671 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4672 mono_print_unhandled_exception (exc);
4674 /* unhandled exception callbacks must not be aborted */
4675 mono_threads_begin_abort_protected_block ();
4676 if (root_appdomain_delegate)
4677 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4678 if (current_appdomain_delegate)
4679 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4680 mono_threads_end_abort_protected_block ();
4683 /* set exitcode only if we will abort the process */
4684 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4685 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4687 mono_environment_exitcode_set (1);
4692 * mono_runtime_exec_managed_code:
4693 * @domain: Application domain
4694 * @main_func: function to invoke from the execution thread
4695 * @main_args: parameter to the main_func
4697 * Launch a new thread to execute a function
4699 * main_func is called back from the thread with main_args as the
4700 * parameter. The callback function is expected to start Main()
4701 * eventually. This function then waits for all managed threads to
4703 * It is not necesseray anymore to execute managed code in a subthread,
4704 * so this function should not be used anymore by default: just
4705 * execute the code and then call mono_thread_manage ().
4708 mono_runtime_exec_managed_code (MonoDomain *domain,
4709 MonoMainThreadFunc main_func,
4713 mono_thread_create_checked (domain, main_func, main_args, &error);
4714 mono_error_assert_ok (&error);
4716 mono_thread_manage ();
4720 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4722 MonoInternalThread* thread = mono_thread_internal_current ();
4723 MonoCustomAttrInfo* cinfo;
4724 gboolean has_stathread_attribute;
4726 if (!domain->entry_assembly) {
4728 MonoAssembly *assembly;
4730 assembly = method->klass->image->assembly;
4731 domain->entry_assembly = assembly;
4732 /* Domains created from another domain already have application_base and configuration_file set */
4733 if (domain->setup->application_base == NULL) {
4734 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4737 if (domain->setup->configuration_file == NULL) {
4738 str = g_strconcat (assembly->image->name, ".config", NULL);
4739 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4741 mono_domain_set_options_from_config (domain);
4745 MonoError cattr_error;
4746 cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4747 mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4749 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4751 mono_custom_attrs_free (cinfo);
4753 has_stathread_attribute = FALSE;
4755 if (has_stathread_attribute) {
4756 thread->apartment_state = ThreadApartmentState_STA;
4758 thread->apartment_state = ThreadApartmentState_MTA;
4760 mono_thread_init_apartment_state ();
4765 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4767 MONO_REQ_GC_UNSAFE_MODE;
4772 mono_error_init (error);
4777 /* FIXME: check signature of method */
4778 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4780 res = mono_runtime_invoke_checked (method, NULL, pa, error);
4782 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4785 mono_environment_exitcode_set (rval);
4787 mono_runtime_invoke_checked (method, NULL, pa, error);
4799 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4801 MONO_REQ_GC_UNSAFE_MODE;
4811 /* FIXME: check signature of method */
4812 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4813 MonoError inner_error;
4815 res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4816 if (*exc == NULL && !mono_error_ok (&inner_error))
4817 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4819 mono_error_cleanup (&inner_error);
4822 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4826 mono_environment_exitcode_set (rval);
4828 MonoError inner_error;
4829 mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4830 if (*exc == NULL && !mono_error_ok (&inner_error))
4831 *exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4833 mono_error_cleanup (&inner_error);
4838 /* If the return type of Main is void, only
4839 * set the exitcode if an exception was thrown
4840 * (we don't want to blow away an
4841 * explicitly-set exit code)
4844 mono_environment_exitcode_set (rval);
4852 * Execute a standard Main() method (args doesn't contain the
4856 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4859 prepare_thread_to_exec_main (mono_object_domain (args), method);
4861 int rval = do_try_exec_main (method, args, exc);
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)
4893 prepare_thread_to_exec_main (mono_object_domain (args), method);
4894 return do_try_exec_main (method, args, exc);
4899 /** invoke_array_extract_argument:
4900 * @params: array of arguments to the method.
4901 * @i: the index of the argument to extract.
4902 * @t: ith type from the method signature.
4903 * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4904 * @error: set on error.
4906 * Given an array of method arguments, return the ith one using the corresponding type
4907 * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4909 * On failure sets @error and returns NULL.
4912 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4914 MonoType *t_orig = t;
4915 gpointer result = NULL;
4916 mono_error_init (error);
4921 case MONO_TYPE_BOOLEAN:
4924 case MONO_TYPE_CHAR:
4933 case MONO_TYPE_VALUETYPE:
4934 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4935 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4936 result = mono_array_get (params, MonoObject*, i);
4938 *has_byref_nullables = TRUE;
4940 /* MS seems to create the objects if a null is passed in */
4941 if (!mono_array_get (params, MonoObject*, i)) {
4942 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4943 return_val_if_nok (error, NULL);
4944 mono_array_setref (params, i, o);
4949 * We can't pass the unboxed vtype byref to the callee, since
4950 * that would mean the callee would be able to modify boxed
4951 * primitive types. So we (and MS) make a copy of the boxed
4952 * object, pass that to the callee, and replace the original
4953 * boxed object in the arg array with the copy.
4955 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4956 MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4957 return_val_if_nok (error, NULL);
4958 mono_array_setref (params, i, copy);
4961 result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4964 case MONO_TYPE_STRING:
4965 case MONO_TYPE_OBJECT:
4966 case MONO_TYPE_CLASS:
4967 case MONO_TYPE_ARRAY:
4968 case MONO_TYPE_SZARRAY:
4970 result = mono_array_addr (params, MonoObject*, i);
4971 // FIXME: I need to check this code path
4973 result = mono_array_get (params, MonoObject*, i);
4975 case MONO_TYPE_GENERICINST:
4977 t = &t->data.generic_class->container_class->this_arg;
4979 t = &t->data.generic_class->container_class->byval_arg;
4981 case MONO_TYPE_PTR: {
4984 /* The argument should be an IntPtr */
4985 arg = mono_array_get (params, MonoObject*, i);
4989 g_assert (arg->vtable->klass == mono_defaults.int_class);
4990 result = ((MonoIntPtr*)arg)->m_value;
4995 g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
5000 * mono_runtime_invoke_array:
5001 * @method: method to invoke
5002 * @obJ: object instance
5003 * @params: arguments to the method
5004 * @exc: exception information.
5006 * Invokes the method represented by @method on the object @obj.
5008 * obj is the 'this' pointer, it should be NULL for static
5009 * methods, a MonoObject* for object instances and a pointer to
5010 * the value type for value types.
5012 * The params array contains the arguments to the method with the
5013 * same convention: MonoObject* pointers for object instances and
5014 * pointers to the value type otherwise. The _invoke_array
5015 * variant takes a C# object[] as the params argument (MonoArray
5016 * *params): in this case the value types are boxed inside the
5017 * respective reference representation.
5019 * From unmanaged code you'll usually use the
5020 * mono_runtime_invoke_checked() variant.
5022 * Note that this function doesn't handle virtual methods for
5023 * you, it will exec the exact method you pass: we still need to
5024 * expose a function to lookup the derived class implementation
5025 * of a virtual method (there are examples of this in the code,
5028 * You can pass NULL as the exc argument if you don't want to
5029 * catch exceptions, otherwise, *exc will be set to the exception
5030 * thrown, if any. if an exception is thrown, you can't use the
5031 * MonoObject* result from the function.
5033 * If the method returns a value type, it is boxed in an object
5037 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5042 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
5044 mono_error_cleanup (&error);
5047 if (!is_ok (&error))
5048 *exc = (MonoObject*)mono_error_convert_to_exception (&error);
5052 MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
5053 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
5059 * mono_runtime_invoke_array_checked:
5060 * @method: method to invoke
5061 * @obJ: object instance
5062 * @params: arguments to the method
5063 * @error: set on failure.
5065 * Invokes the method represented by @method on the object @obj.
5067 * obj is the 'this' pointer, it should be NULL for static
5068 * methods, a MonoObject* for object instances and a pointer to
5069 * the value type for value types.
5071 * The params array contains the arguments to the method with the
5072 * same convention: MonoObject* pointers for object instances and
5073 * pointers to the value type otherwise. The _invoke_array
5074 * variant takes a C# object[] as the params argument (MonoArray
5075 * *params): in this case the value types are boxed inside the
5076 * respective reference representation.
5078 * From unmanaged code you'll usually use the
5079 * mono_runtime_invoke_checked() variant.
5081 * Note that this function doesn't handle virtual methods for
5082 * you, it will exec the exact method you pass: we still need to
5083 * expose a function to lookup the derived class implementation
5084 * of a virtual method (there are examples of this in the code,
5087 * On failure or exception, @error will be set. In that case, you
5088 * can't use the MonoObject* result from the function.
5090 * If the method returns a value type, it is boxed in an object
5094 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5097 mono_error_init (error);
5098 return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5102 * mono_runtime_try_invoke_array:
5103 * @method: method to invoke
5104 * @obJ: object instance
5105 * @params: arguments to the method
5106 * @exc: exception information.
5107 * @error: set on failure.
5109 * Invokes the method represented by @method on the object @obj.
5111 * obj is the 'this' pointer, it should be NULL for static
5112 * methods, a MonoObject* for object instances and a pointer to
5113 * the value type for value types.
5115 * The params array contains the arguments to the method with the
5116 * same convention: MonoObject* pointers for object instances and
5117 * pointers to the value type otherwise. The _invoke_array
5118 * variant takes a C# object[] as the params argument (MonoArray
5119 * *params): in this case the value types are boxed inside the
5120 * respective reference representation.
5122 * From unmanaged code you'll usually use the
5123 * mono_runtime_invoke_checked() variant.
5125 * Note that this function doesn't handle virtual methods for
5126 * you, it will exec the exact method you pass: we still need to
5127 * expose a function to lookup the derived class implementation
5128 * of a virtual method (there are examples of this in the code,
5131 * You can pass NULL as the exc argument if you don't want to catch
5132 * exceptions, otherwise, *exc will be set to the exception thrown, if
5133 * any. On other failures, @error will be set. If an exception is
5134 * thrown or there's an error, you can't use the MonoObject* result
5135 * from the function.
5137 * If the method returns a value type, it is boxed in an object
5141 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5142 MonoObject **exc, MonoError *error)
5144 MONO_REQ_GC_UNSAFE_MODE;
5146 mono_error_init (error);
5148 MonoMethodSignature *sig = mono_method_signature (method);
5149 gpointer *pa = NULL;
5152 gboolean has_byref_nullables = FALSE;
5154 if (NULL != params) {
5155 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5156 for (i = 0; i < mono_array_length (params); i++) {
5157 MonoType *t = sig->params [i];
5158 pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5159 return_val_if_nok (error, NULL);
5163 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5166 if (mono_class_is_nullable (method->klass)) {
5167 /* Need to create a boxed vtype instead */
5173 return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5178 obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5179 mono_error_assert_ok (error);
5180 g_assert (obj); /*maybe we should raise a TLE instead?*/
5181 #ifndef DISABLE_REMOTING
5182 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
5183 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5186 if (method->klass->valuetype)
5187 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5190 } else if (method->klass->valuetype) {
5191 obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5192 return_val_if_nok (error, NULL);
5196 mono_runtime_try_invoke (method, o, pa, exc, error);
5198 mono_runtime_invoke_checked (method, o, pa, error);
5201 return (MonoObject *)obj;
5203 if (mono_class_is_nullable (method->klass)) {
5204 MonoObject *nullable;
5206 /* Convert the unboxed vtype into a Nullable structure */
5207 nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5208 return_val_if_nok (error, NULL);
5210 MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5211 return_val_if_nok (error, NULL);
5212 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5213 obj = mono_object_unbox (nullable);
5216 /* obj must be already unboxed if needed */
5218 res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5220 res = mono_runtime_invoke_checked (method, obj, pa, error);
5222 return_val_if_nok (error, NULL);
5224 if (sig->ret->type == MONO_TYPE_PTR) {
5225 MonoClass *pointer_class;
5226 static MonoMethod *box_method;
5228 MonoObject *box_exc;
5231 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5232 * convert it to a Pointer object.
5234 pointer_class = mono_class_get_pointer_class ();
5236 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5238 g_assert (res->vtable->klass == mono_defaults.int_class);
5239 box_args [0] = ((MonoIntPtr*)res)->m_value;
5240 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5241 return_val_if_nok (error, NULL);
5243 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5244 g_assert (box_exc == NULL);
5245 mono_error_assert_ok (error);
5248 if (has_byref_nullables) {
5250 * The runtime invoke wrapper already converted byref nullables back,
5251 * and stored them in pa, we just need to copy them back to the
5254 for (i = 0; i < mono_array_length (params); i++) {
5255 MonoType *t = sig->params [i];
5257 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5258 mono_array_setref (params, i, pa [i]);
5268 * @klass: the class of the object that we want to create
5270 * Returns: a newly created object whose definition is
5271 * looked up using @klass. This will not invoke any constructors,
5272 * so the consumer of this routine has to invoke any constructors on
5273 * its own to initialize the object.
5275 * It returns NULL on failure.
5278 mono_object_new (MonoDomain *domain, MonoClass *klass)
5280 MONO_REQ_GC_UNSAFE_MODE;
5284 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5286 mono_error_cleanup (&error);
5291 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5293 MONO_REQ_GC_UNSAFE_MODE;
5297 MonoObject * result = mono_object_new_checked (domain, klass, &error);
5299 mono_error_set_pending_exception (&error);
5304 * mono_object_new_checked:
5305 * @klass: the class of the object that we want to create
5306 * @error: set on error
5308 * Returns: a newly created object whose definition is
5309 * looked up using @klass. This will not invoke any constructors,
5310 * so the consumer of this routine has to invoke any constructors on
5311 * its own to initialize the object.
5313 * It returns NULL on failure and sets @error.
5316 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5318 MONO_REQ_GC_UNSAFE_MODE;
5322 vtable = mono_class_vtable (domain, klass);
5323 g_assert (vtable); /* FIXME don't swallow the error */
5325 MonoObject *o = mono_object_new_specific_checked (vtable, error);
5330 * mono_object_new_pinned:
5332 * Same as mono_object_new, but the returned object will be pinned.
5333 * For SGEN, these objects will only be freed at appdomain unload.
5336 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5338 MONO_REQ_GC_UNSAFE_MODE;
5342 mono_error_init (error);
5344 vtable = mono_class_vtable (domain, klass);
5345 g_assert (vtable); /* FIXME don't swallow the error */
5347 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5349 if (G_UNLIKELY (!o))
5350 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5351 else if (G_UNLIKELY (vtable->klass->has_finalize))
5352 mono_object_register_finalizer (o);
5358 * mono_object_new_specific:
5359 * @vtable: the vtable of the object that we want to create
5361 * Returns: A newly created object with class and domain specified
5365 mono_object_new_specific (MonoVTable *vtable)
5368 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5369 mono_error_cleanup (&error);
5375 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5377 MONO_REQ_GC_UNSAFE_MODE;
5381 mono_error_init (error);
5383 /* check for is_com_object for COM Interop */
5384 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5387 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5390 MonoClass *klass = mono_class_get_activation_services_class ();
5393 mono_class_init (klass);
5395 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5397 mono_error_set_not_supported (error, "Linked away.");
5400 vtable->domain->create_proxy_for_type_method = im;
5403 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5404 if (!mono_error_ok (error))
5407 o = mono_runtime_invoke_checked (im, NULL, pa, error);
5408 if (!mono_error_ok (error))
5415 return mono_object_new_alloc_specific_checked (vtable, error);
5419 ves_icall_object_new_specific (MonoVTable *vtable)
5422 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5423 mono_error_set_pending_exception (&error);
5429 * mono_object_new_alloc_specific:
5430 * @vtable: virtual table for the object.
5432 * This function allocates a new `MonoObject` with the type derived
5433 * from the @vtable information. If the class of this object has a
5434 * finalizer, then the object will be tracked for finalization.
5436 * This method might raise an exception on errors. Use the
5437 * `mono_object_new_fast_checked` method if you want to manually raise
5440 * Returns: the allocated object.
5443 mono_object_new_alloc_specific (MonoVTable *vtable)
5446 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5447 mono_error_cleanup (&error);
5453 * mono_object_new_alloc_specific_checked:
5454 * @vtable: virtual table for the object.
5455 * @error: holds the error return value.
5457 * This function allocates a new `MonoObject` with the type derived
5458 * from the @vtable information. If the class of this object has a
5459 * finalizer, then the object will be tracked for finalization.
5461 * If there is not enough memory, the @error parameter will be set
5462 * and will contain a user-visible message with the amount of bytes
5463 * that were requested.
5465 * Returns: the allocated object, or NULL if there is not enough memory
5469 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5471 MONO_REQ_GC_UNSAFE_MODE;
5475 mono_error_init (error);
5477 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5479 if (G_UNLIKELY (!o))
5480 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5481 else if (G_UNLIKELY (vtable->klass->has_finalize))
5482 mono_object_register_finalizer (o);
5488 * mono_object_new_fast:
5489 * @vtable: virtual table for the object.
5491 * This function allocates a new `MonoObject` with the type derived
5492 * from the @vtable information. The returned object is not tracked
5493 * for finalization. If your object implements a finalizer, you should
5494 * use `mono_object_new_alloc_specific` instead.
5496 * This method might raise an exception on errors. Use the
5497 * `mono_object_new_fast_checked` method if you want to manually raise
5500 * Returns: the allocated object.
5503 mono_object_new_fast (MonoVTable *vtable)
5506 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5507 mono_error_cleanup (&error);
5513 * mono_object_new_fast_checked:
5514 * @vtable: virtual table for the object.
5515 * @error: holds the error return value.
5517 * This function allocates a new `MonoObject` with the type derived
5518 * from the @vtable information. The returned object is not tracked
5519 * for finalization. If your object implements a finalizer, you should
5520 * use `mono_object_new_alloc_specific_checked` instead.
5522 * If there is not enough memory, the @error parameter will be set
5523 * and will contain a user-visible message with the amount of bytes
5524 * that were requested.
5526 * Returns: the allocated object, or NULL if there is not enough memory
5530 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5532 MONO_REQ_GC_UNSAFE_MODE;
5536 mono_error_init (error);
5538 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5540 if (G_UNLIKELY (!o))
5541 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5547 ves_icall_object_new_fast (MonoVTable *vtable)
5550 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5551 mono_error_set_pending_exception (&error);
5557 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5559 MONO_REQ_GC_UNSAFE_MODE;
5563 mono_error_init (error);
5565 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5567 if (G_UNLIKELY (!o))
5568 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5569 else if (G_UNLIKELY (vtable->klass->has_finalize))
5570 mono_object_register_finalizer (o);
5576 * mono_class_get_allocation_ftn:
5578 * @for_box: the object will be used for boxing
5579 * @pass_size_in_words:
5581 * Return the allocation function appropriate for the given class.
5585 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5587 MONO_REQ_GC_NEUTRAL_MODE;
5589 *pass_size_in_words = FALSE;
5591 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5592 return ves_icall_object_new_specific;
5594 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5596 return ves_icall_object_new_fast;
5599 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5600 * of the overhead of parameter passing.
5603 *pass_size_in_words = TRUE;
5604 #ifdef GC_REDIRECT_TO_LOCAL
5605 return GC_local_gcj_fast_malloc;
5607 return GC_gcj_fast_malloc;
5612 return ves_icall_object_new_specific;
5616 * mono_object_new_from_token:
5617 * @image: Context where the type_token is hosted
5618 * @token: a token of the type that we want to create
5620 * Returns: A newly created object whose definition is
5621 * looked up using @token in the @image image
5624 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5626 MONO_REQ_GC_UNSAFE_MODE;
5632 klass = mono_class_get_checked (image, token, &error);
5633 mono_error_assert_ok (&error);
5635 result = mono_object_new_checked (domain, klass, &error);
5637 mono_error_cleanup (&error);
5644 * mono_object_clone:
5645 * @obj: the object to clone
5647 * Returns: A newly created object who is a shallow copy of @obj
5650 mono_object_clone (MonoObject *obj)
5653 MonoObject *o = mono_object_clone_checked (obj, &error);
5654 mono_error_cleanup (&error);
5660 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5662 MONO_REQ_GC_UNSAFE_MODE;
5667 mono_error_init (error);
5669 size = obj->vtable->klass->instance_size;
5671 if (obj->vtable->klass->rank)
5672 return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5674 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5676 if (G_UNLIKELY (!o)) {
5677 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5681 /* If the object doesn't contain references this will do a simple memmove. */
5682 mono_gc_wbarrier_object_copy (o, obj);
5684 if (obj->vtable->klass->has_finalize)
5685 mono_object_register_finalizer (o);
5690 * mono_array_full_copy:
5691 * @src: source array to copy
5692 * @dest: destination array
5694 * Copies the content of one array to another with exactly the same type and size.
5697 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5699 MONO_REQ_GC_UNSAFE_MODE;
5702 MonoClass *klass = src->obj.vtable->klass;
5704 g_assert (klass == dest->obj.vtable->klass);
5706 size = mono_array_length (src);
5707 g_assert (size == mono_array_length (dest));
5708 size *= mono_array_element_size (klass);
5710 if (klass->element_class->valuetype) {
5711 if (klass->element_class->has_references)
5712 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5714 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5716 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5719 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5724 * mono_array_clone_in_domain:
5725 * @domain: the domain in which the array will be cloned into
5726 * @array: the array to clone
5727 * @error: set on error
5729 * This routine returns a copy of the array that is hosted on the
5730 * specified MonoDomain. On failure returns NULL and sets @error.
5733 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array, MonoError *error)
5735 MONO_REQ_GC_UNSAFE_MODE;
5740 MonoClass *klass = array->obj.vtable->klass;
5742 mono_error_init (error);
5744 if (array->bounds == NULL) {
5745 size = mono_array_length (array);
5746 o = mono_array_new_full_checked (domain, klass, &size, NULL, error);
5747 return_val_if_nok (error, NULL);
5749 size *= mono_array_element_size (klass);
5751 if (klass->element_class->valuetype) {
5752 if (klass->element_class->has_references)
5753 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5755 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5757 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5760 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5765 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5766 size = mono_array_element_size (klass);
5767 for (i = 0; i < klass->rank; ++i) {
5768 sizes [i] = array->bounds [i].length;
5769 size *= array->bounds [i].length;
5770 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5772 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, error);
5773 return_val_if_nok (error, NULL);
5775 if (klass->element_class->valuetype) {
5776 if (klass->element_class->has_references)
5777 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5779 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5781 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5784 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5792 * @array: the array to clone
5794 * Returns: A newly created array who is a shallow copy of @array
5797 mono_array_clone (MonoArray *array)
5799 MONO_REQ_GC_UNSAFE_MODE;
5802 MonoArray *result = mono_array_clone_checked (array, &error);
5803 mono_error_cleanup (&error);
5808 * mono_array_clone_checked:
5809 * @array: the array to clone
5810 * @error: set on error
5812 * Returns: A newly created array who is a shallow copy of @array. On
5813 * failure returns NULL and sets @error.
5816 mono_array_clone_checked (MonoArray *array, MonoError *error)
5819 MONO_REQ_GC_UNSAFE_MODE;
5820 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array, error);
5823 /* helper macros to check for overflow when calculating the size of arrays */
5824 #ifdef MONO_BIG_ARRAYS
5825 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5826 #define MYGUINT_MAX MYGUINT64_MAX
5827 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5828 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5829 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5830 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5831 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5833 #define MYGUINT32_MAX 4294967295U
5834 #define MYGUINT_MAX MYGUINT32_MAX
5835 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5836 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5837 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5838 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5839 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5843 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5845 MONO_REQ_GC_NEUTRAL_MODE;
5849 byte_len = mono_array_element_size (klass);
5850 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5853 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5855 byte_len += MONO_SIZEOF_MONO_ARRAY;
5863 * mono_array_new_full:
5864 * @domain: domain where the object is created
5865 * @array_class: array class
5866 * @lengths: lengths for each dimension in the array
5867 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5869 * This routine creates a new array objects with the given dimensions,
5870 * lower bounds and type.
5873 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5876 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5877 mono_error_cleanup (&error);
5883 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5885 MONO_REQ_GC_UNSAFE_MODE;
5887 uintptr_t byte_len = 0, len, bounds_size;
5890 MonoArrayBounds *bounds;
5894 mono_error_init (error);
5896 if (!array_class->inited)
5897 mono_class_init (array_class);
5901 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5902 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5904 if (len > MONO_ARRAY_MAX_INDEX) {
5905 mono_error_set_generic_error (error, "System", "OverflowException", "");
5910 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5912 for (i = 0; i < array_class->rank; ++i) {
5913 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5914 mono_error_set_generic_error (error, "System", "OverflowException", "");
5917 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5918 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5925 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5926 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5932 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5933 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5936 byte_len = (byte_len + 3) & ~3;
5937 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5938 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5941 byte_len += bounds_size;
5944 * Following three lines almost taken from mono_object_new ():
5945 * they need to be kept in sync.
5947 vtable = mono_class_vtable_full (domain, array_class, error);
5948 return_val_if_nok (error, NULL);
5951 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5953 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5955 if (G_UNLIKELY (!o)) {
5956 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5960 array = (MonoArray*)o;
5962 bounds = array->bounds;
5965 for (i = 0; i < array_class->rank; ++i) {
5966 bounds [i].length = lengths [i];
5968 bounds [i].lower_bound = lower_bounds [i];
5977 * @domain: domain where the object is created
5978 * @eclass: element class
5979 * @n: number of array elements
5981 * This routine creates a new szarray with @n elements of type @eclass.
5984 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5986 MONO_REQ_GC_UNSAFE_MODE;
5989 MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5990 mono_error_cleanup (&error);
5995 * mono_array_new_checked:
5996 * @domain: domain where the object is created
5997 * @eclass: element class
5998 * @n: number of array elements
5999 * @error: set on error
6001 * This routine creates a new szarray with @n elements of type @eclass.
6002 * On failure returns NULL and sets @error.
6005 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
6009 mono_error_init (error);
6011 ac = mono_array_class_get (eclass, 1);
6014 MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
6015 return_val_if_nok (error, NULL);
6017 return mono_array_new_specific_checked (vtable, n, error);
6021 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
6024 MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
6025 mono_error_set_pending_exception (&error);
6031 * mono_array_new_specific:
6032 * @vtable: a vtable in the appropriate domain for an initialized class
6033 * @n: number of array elements
6035 * This routine is a fast alternative to mono_array_new() for code which
6036 * can be sure about the domain it operates in.
6039 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
6042 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6043 mono_error_cleanup (&error);
6049 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
6051 MONO_REQ_GC_UNSAFE_MODE;
6056 mono_error_init (error);
6058 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6059 mono_error_set_generic_error (error, "System", "OverflowException", "");
6063 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6064 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6067 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6069 if (G_UNLIKELY (!o)) {
6070 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
6074 return (MonoArray*)o;
6078 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6081 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6082 mono_error_set_pending_exception (&error);
6088 * mono_string_new_utf16:
6089 * @text: a pointer to an utf16 string
6090 * @len: the length of the string
6092 * Returns: A newly created string object which contains @text.
6095 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6097 MONO_REQ_GC_UNSAFE_MODE;
6100 MonoString *res = NULL;
6101 res = mono_string_new_utf16_checked (domain, text, len, &error);
6102 mono_error_cleanup (&error);
6108 * mono_string_new_utf16_checked:
6109 * @text: a pointer to an utf16 string
6110 * @len: the length of the string
6111 * @error: written on error.
6113 * Returns: A newly created string object which contains @text.
6114 * On error, returns NULL and sets @error.
6117 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6119 MONO_REQ_GC_UNSAFE_MODE;
6123 mono_error_init (error);
6125 s = mono_string_new_size_checked (domain, len, error);
6127 memcpy (mono_string_chars (s), text, len * 2);
6133 * mono_string_new_utf32:
6134 * @text: a pointer to an utf32 string
6135 * @len: the length of the string
6136 * @error: set on failure.
6138 * Returns: A newly created string object which contains @text. On failure returns NULL and sets @error.
6141 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6143 MONO_REQ_GC_UNSAFE_MODE;
6146 mono_unichar2 *utf16_output = NULL;
6147 gint32 utf16_len = 0;
6148 GError *gerror = NULL;
6149 glong items_written;
6151 mono_error_init (error);
6152 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6155 g_error_free (gerror);
6157 while (utf16_output [utf16_len]) utf16_len++;
6159 s = mono_string_new_size_checked (domain, utf16_len, error);
6160 return_val_if_nok (error, NULL);
6162 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6164 g_free (utf16_output);
6170 * mono_string_new_utf32:
6171 * @text: a pointer to an utf32 string
6172 * @len: the length of the string
6174 * Returns: A newly created string object which contains @text.
6177 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6180 MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6181 mono_error_cleanup (&error);
6186 * mono_string_new_size:
6187 * @text: a pointer to an utf16 string
6188 * @len: the length of the string
6190 * Returns: A newly created string object of @len
6193 mono_string_new_size (MonoDomain *domain, gint32 len)
6196 MonoString *str = mono_string_new_size_checked (domain, len, &error);
6197 mono_error_cleanup (&error);
6203 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6205 MONO_REQ_GC_UNSAFE_MODE;
6211 mono_error_init (error);
6213 /* check for overflow */
6214 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6215 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6219 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6220 g_assert (size > 0);
6222 vtable = mono_class_vtable (domain, mono_defaults.string_class);
6225 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6227 if (G_UNLIKELY (!s)) {
6228 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6236 * mono_string_new_len:
6237 * @text: a pointer to an utf8 string
6238 * @length: number of bytes in @text to consider
6240 * Returns: A newly created string object which contains @text.
6243 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6245 MONO_REQ_GC_UNSAFE_MODE;
6248 MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6249 mono_error_cleanup (&error);
6254 * mono_string_new_len_checked:
6255 * @text: a pointer to an utf8 string
6256 * @length: number of bytes in @text to consider
6257 * @error: set on error
6259 * Returns: A newly created string object which contains @text. On
6260 * failure returns NULL and sets @error.
6263 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6265 MONO_REQ_GC_UNSAFE_MODE;
6267 mono_error_init (error);
6269 GError *eg_error = NULL;
6270 MonoString *o = NULL;
6272 glong items_written;
6274 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6277 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6279 g_error_free (eg_error);
6288 * @text: a pointer to an utf8 string
6290 * Returns: A newly created string object which contains @text.
6292 * This function asserts if it cannot allocate a new string.
6294 * @deprecated Use mono_string_new_checked in new code.
6297 mono_string_new (MonoDomain *domain, const char *text)
6300 MonoString *res = NULL;
6301 res = mono_string_new_checked (domain, text, &error);
6302 mono_error_assert_ok (&error);
6307 * mono_string_new_checked:
6308 * @text: a pointer to an utf8 string
6309 * @merror: set on error
6311 * Returns: A newly created string object which contains @text.
6312 * On error returns NULL and sets @merror.
6315 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6317 MONO_REQ_GC_UNSAFE_MODE;
6319 GError *eg_error = NULL;
6320 MonoString *o = NULL;
6322 glong items_written;
6325 mono_error_init (error);
6329 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6332 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6334 g_error_free (eg_error);
6338 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6343 MonoString *o = NULL;
6345 if (!g_utf8_validate (text, -1, &end)) {
6346 mono_error_set_argument (error, "text", "Not a valid utf8 string");
6350 len = g_utf8_strlen (text, -1);
6351 o = mono_string_new_size_checked (domain, len, error);
6354 str = mono_string_chars (o);
6356 while (text < end) {
6357 *str++ = g_utf8_get_char (text);
6358 text = g_utf8_next_char (text);
6367 * mono_string_new_wrapper:
6368 * @text: pointer to utf8 characters.
6370 * Helper function to create a string object from @text in the current domain.
6373 mono_string_new_wrapper (const char *text)
6375 MONO_REQ_GC_UNSAFE_MODE;
6377 MonoDomain *domain = mono_domain_get ();
6380 return mono_string_new (domain, text);
6387 * @class: the class of the value
6388 * @value: a pointer to the unboxed data
6390 * Returns: A newly created object which contains @value.
6393 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6396 MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6397 mono_error_cleanup (&error);
6402 * mono_value_box_checked:
6403 * @domain: the domain of the new object
6404 * @class: the class of the value
6405 * @value: a pointer to the unboxed data
6406 * @error: set on error
6408 * Returns: A newly created object which contains @value. On failure
6409 * returns NULL and sets @error.
6412 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6414 MONO_REQ_GC_UNSAFE_MODE;
6419 mono_error_init (error);
6421 g_assert (klass->valuetype);
6422 if (mono_class_is_nullable (klass))
6423 return mono_nullable_box ((guint8 *)value, klass, error);
6425 vtable = mono_class_vtable (domain, klass);
6428 size = mono_class_instance_size (klass);
6429 res = mono_object_new_alloc_specific_checked (vtable, error);
6430 return_val_if_nok (error, NULL);
6432 size = size - sizeof (MonoObject);
6435 g_assert (size == mono_class_value_size (klass, NULL));
6436 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6438 #if NO_UNALIGNED_ACCESS
6439 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6443 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6446 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6449 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6452 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6455 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6459 if (klass->has_finalize) {
6460 mono_object_register_finalizer (res);
6461 return_val_if_nok (error, NULL);
6468 * @dest: destination pointer
6469 * @src: source pointer
6470 * @klass: a valuetype class
6472 * Copy a valuetype from @src to @dest. This function must be used
6473 * when @klass contains references fields.
6476 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6478 MONO_REQ_GC_UNSAFE_MODE;
6480 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6484 * mono_value_copy_array:
6485 * @dest: destination array
6486 * @dest_idx: index in the @dest array
6487 * @src: source pointer
6488 * @count: number of items
6490 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
6491 * This function must be used when @klass contains references fields.
6492 * Overlap is handled.
6495 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6497 MONO_REQ_GC_UNSAFE_MODE;
6499 int size = mono_array_element_size (dest->obj.vtable->klass);
6500 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6501 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6502 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6506 * mono_object_get_domain:
6507 * @obj: object to query
6509 * Returns: the MonoDomain where the object is hosted
6512 mono_object_get_domain (MonoObject *obj)
6514 MONO_REQ_GC_UNSAFE_MODE;
6516 return mono_object_domain (obj);
6520 * mono_object_get_class:
6521 * @obj: object to query
6523 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
6525 * Returns: the MonoClass of the object.
6528 mono_object_get_class (MonoObject *obj)
6530 MONO_REQ_GC_UNSAFE_MODE;
6532 return mono_object_class (obj);
6535 * mono_object_get_size:
6536 * @o: object to query
6538 * Returns: the size, in bytes, of @o
6541 mono_object_get_size (MonoObject* o)
6543 MONO_REQ_GC_UNSAFE_MODE;
6545 MonoClass* klass = mono_object_class (o);
6546 if (klass == mono_defaults.string_class) {
6547 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6548 } else if (o->vtable->rank) {
6549 MonoArray *array = (MonoArray*)o;
6550 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6551 if (array->bounds) {
6554 size += sizeof (MonoArrayBounds) * o->vtable->rank;
6558 return mono_class_instance_size (klass);
6563 * mono_object_unbox:
6564 * @obj: object to unbox
6566 * Returns: a pointer to the start of the valuetype boxed in this
6569 * This method will assert if the object passed is not a valuetype.
6572 mono_object_unbox (MonoObject *obj)
6574 MONO_REQ_GC_UNSAFE_MODE;
6576 /* add assert for valuetypes? */
6577 g_assert (obj->vtable->klass->valuetype);
6578 return ((char*)obj) + sizeof (MonoObject);
6582 * mono_object_isinst:
6584 * @klass: a pointer to a class
6586 * Returns: @obj if @obj is derived from @klass or NULL otherwise.
6589 mono_object_isinst (MonoObject *obj, MonoClass *klass)
6591 MONO_REQ_GC_UNSAFE_MODE;
6594 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
6595 mono_error_cleanup (&error);
6601 * mono_object_isinst_checked:
6603 * @klass: a pointer to a class
6604 * @error: set on error
6606 * Returns: @obj if @obj is derived from @klass or NULL if it isn't.
6607 * On failure returns NULL and sets @error.
6610 mono_object_isinst_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6612 MONO_REQ_GC_UNSAFE_MODE;
6614 mono_error_init (error);
6616 MonoObject *result = NULL;
6619 mono_class_init (klass);
6621 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6622 result = mono_object_isinst_mbyref_checked (obj, klass, error);
6629 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
6633 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
6635 MONO_REQ_GC_UNSAFE_MODE;
6638 MonoObject *result = mono_object_isinst_mbyref_checked (obj, klass, &error);
6639 mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6644 mono_object_isinst_mbyref_checked (MonoObject *obj, MonoClass *klass, MonoError *error)
6646 MONO_REQ_GC_UNSAFE_MODE;
6650 mono_error_init (error);
6657 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
6658 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6662 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6663 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
6666 MonoClass *oklass = vt->klass;
6667 if (mono_class_is_transparent_proxy (oklass))
6668 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
6670 mono_class_setup_supertypes (klass);
6671 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
6674 #ifndef DISABLE_REMOTING
6675 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
6677 MonoDomain *domain = mono_domain_get ();
6679 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
6680 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6681 MonoMethod *im = NULL;
6684 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6686 mono_error_set_not_supported (error, "Linked away.");
6689 im = mono_object_get_virtual_method (rp, im);
6692 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, error);
6693 return_val_if_nok (error, NULL);
6696 res = mono_runtime_invoke_checked (im, rp, pa, error);
6697 return_val_if_nok (error, NULL);
6699 if (*(MonoBoolean *) mono_object_unbox(res)) {
6700 /* Update the vtable of the remote type, so it can safely cast to this new type */
6701 mono_upgrade_remote_class (domain, obj, klass, error);
6702 return_val_if_nok (error, NULL);
6706 #endif /* DISABLE_REMOTING */
6711 * mono_object_castclass_mbyref:
6713 * @klass: a pointer to a class
6715 * Returns: @obj if @obj is derived from @klass, returns NULL otherwise.
6718 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6720 MONO_REQ_GC_UNSAFE_MODE;
6723 if (!obj) return NULL;
6724 if (mono_object_isinst_mbyref_checked (obj, klass, &error)) return obj;
6725 mono_error_cleanup (&error);
6730 MonoDomain *orig_domain;
6736 str_lookup (MonoDomain *domain, gpointer user_data)
6738 MONO_REQ_GC_UNSAFE_MODE;
6740 LDStrInfo *info = (LDStrInfo *)user_data;
6741 if (info->res || domain == info->orig_domain)
6743 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6747 mono_string_get_pinned (MonoString *str, MonoError *error)
6749 MONO_REQ_GC_UNSAFE_MODE;
6751 mono_error_init (error);
6753 /* We only need to make a pinned version of a string if this is a moving GC */
6754 if (!mono_gc_is_moving ())
6758 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6759 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6761 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6762 news->length = mono_string_length (str);
6764 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6770 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6772 MONO_REQ_GC_UNSAFE_MODE;
6774 MonoGHashTable *ldstr_table;
6775 MonoString *s, *res;
6778 mono_error_init (error);
6780 domain = ((MonoObject *)str)->vtable->domain;
6781 ldstr_table = domain->ldstr_table;
6783 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6789 /* Allocate outside the lock */
6791 s = mono_string_get_pinned (str, error);
6792 return_val_if_nok (error, NULL);
6795 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6800 mono_g_hash_table_insert (ldstr_table, s, s);
6805 LDStrInfo ldstr_info;
6806 ldstr_info.orig_domain = domain;
6807 ldstr_info.ins = str;
6808 ldstr_info.res = NULL;
6810 mono_domain_foreach (str_lookup, &ldstr_info);
6811 if (ldstr_info.res) {
6813 * the string was already interned in some other domain:
6814 * intern it in the current one as well.
6816 mono_g_hash_table_insert (ldstr_table, str, str);
6826 * mono_string_is_interned:
6827 * @o: String to probe
6829 * Returns whether the string has been interned.
6832 mono_string_is_interned (MonoString *o)
6835 MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6836 /* This function does not fail. */
6837 mono_error_assert_ok (&error);
6842 * mono_string_intern:
6843 * @o: String to intern
6845 * Interns the string passed.
6846 * Returns: The interned string.
6849 mono_string_intern (MonoString *str)
6852 MonoString *result = mono_string_intern_checked (str, &error);
6853 mono_error_assert_ok (&error);
6858 * mono_string_intern_checked:
6859 * @o: String to intern
6860 * @error: set on error.
6862 * Interns the string passed.
6863 * Returns: The interned string. On failure returns NULL and sets @error
6866 mono_string_intern_checked (MonoString *str, MonoError *error)
6868 MONO_REQ_GC_UNSAFE_MODE;
6870 mono_error_init (error);
6872 return mono_string_is_interned_lookup (str, TRUE, error);
6877 * @domain: the domain where the string will be used.
6878 * @image: a metadata context
6879 * @idx: index into the user string table.
6881 * Implementation for the ldstr opcode.
6882 * Returns: a loaded string from the @image/@idx combination.
6885 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6888 MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6889 mono_error_cleanup (&error);
6894 * mono_ldstr_checked:
6895 * @domain: the domain where the string will be used.
6896 * @image: a metadata context
6897 * @idx: index into the user string table.
6898 * @error: set on error.
6900 * Implementation for the ldstr opcode.
6901 * Returns: a loaded string from the @image/@idx combination.
6902 * On failure returns NULL and sets @error.
6905 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6907 MONO_REQ_GC_UNSAFE_MODE;
6908 mono_error_init (error);
6910 if (image->dynamic) {
6911 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6914 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6915 return NULL; /*FIXME we should probably be raising an exception here*/
6916 MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6922 * mono_ldstr_metadata_sig
6923 * @domain: the domain for the string
6924 * @sig: the signature of a metadata string
6925 * @error: set on error
6927 * Returns: a MonoString for a string stored in the metadata. On
6928 * failure returns NULL and sets @error.
6931 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6933 MONO_REQ_GC_UNSAFE_MODE;
6935 mono_error_init (error);
6936 const char *str = sig;
6937 MonoString *o, *interned;
6940 len2 = mono_metadata_decode_blob_size (str, &str);
6943 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6944 return_val_if_nok (error, NULL);
6945 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6948 guint16 *p2 = (guint16*)mono_string_chars (o);
6949 for (i = 0; i < len2; ++i) {
6950 *p2 = GUINT16_FROM_LE (*p2);
6956 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6959 return interned; /* o will get garbage collected */
6961 o = mono_string_get_pinned (o, error);
6964 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6966 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6978 * Same as mono_ldstr, but return a NULL terminated utf8 string instead
6982 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6988 GError *gerror = NULL;
6990 mono_error_init (error);
6992 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6993 return NULL; /*FIXME we should probably be raising an exception here*/
6994 str = mono_metadata_user_string (image, idx);
6996 len2 = mono_metadata_decode_blob_size (str, &str);
6999 as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
7001 mono_error_set_argument (error, "string", "%s", gerror->message);
7002 g_error_free (gerror);
7005 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7006 if (len2 > written) {
7007 /* allocate the total length and copy the part of the string that has been converted */
7008 char *as2 = (char *)g_malloc0 (len2);
7009 memcpy (as2, as, written);
7018 * mono_string_to_utf8:
7019 * @s: a System.String
7021 * Returns the UTF8 representation for @s.
7022 * The resulting buffer needs to be freed with mono_free().
7024 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
7027 mono_string_to_utf8 (MonoString *s)
7029 MONO_REQ_GC_UNSAFE_MODE;
7032 char *result = mono_string_to_utf8_checked (s, &error);
7034 if (!is_ok (&error)) {
7035 mono_error_cleanup (&error);
7042 * mono_string_to_utf8_checked:
7043 * @s: a System.String
7044 * @error: a MonoError.
7046 * Converts a MonoString to its UTF8 representation. May fail; check
7047 * @error to determine whether the conversion was successful.
7048 * The resulting buffer should be freed with mono_free().
7051 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7053 MONO_REQ_GC_UNSAFE_MODE;
7057 GError *gerror = NULL;
7059 mono_error_init (error);
7065 return g_strdup ("");
7067 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7069 mono_error_set_argument (error, "string", "%s", gerror->message);
7070 g_error_free (gerror);
7073 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7074 if (s->length > written) {
7075 /* allocate the total length and copy the part of the string that has been converted */
7076 char *as2 = (char *)g_malloc0 (s->length);
7077 memcpy (as2, as, written);
7086 * mono_string_to_utf8_ignore:
7089 * Converts a MonoString to its UTF8 representation. Will ignore
7090 * invalid surrogate pairs.
7091 * The resulting buffer should be freed with mono_free().
7095 mono_string_to_utf8_ignore (MonoString *s)
7097 MONO_REQ_GC_UNSAFE_MODE;
7106 return g_strdup ("");
7108 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7110 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7111 if (s->length > written) {
7112 /* allocate the total length and copy the part of the string that has been converted */
7113 char *as2 = (char *)g_malloc0 (s->length);
7114 memcpy (as2, as, written);
7123 * mono_string_to_utf8_image_ignore:
7124 * @s: a System.String
7126 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7129 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7131 MONO_REQ_GC_UNSAFE_MODE;
7133 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7137 * mono_string_to_utf8_mp_ignore:
7138 * @s: a System.String
7140 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
7143 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7145 MONO_REQ_GC_UNSAFE_MODE;
7147 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7152 * mono_string_to_utf16:
7155 * Return an null-terminated array of the utf-16 chars
7156 * contained in @s. The result must be freed with g_free().
7157 * This is a temporary helper until our string implementation
7158 * is reworked to always include the null terminating char.
7161 mono_string_to_utf16 (MonoString *s)
7163 MONO_REQ_GC_UNSAFE_MODE;
7170 as = (char *)g_malloc ((s->length * 2) + 2);
7171 as [(s->length * 2)] = '\0';
7172 as [(s->length * 2) + 1] = '\0';
7175 return (gunichar2 *)(as);
7178 memcpy (as, mono_string_chars(s), s->length * 2);
7179 return (gunichar2 *)(as);
7183 * mono_string_to_utf32:
7186 * Return an null-terminated array of the UTF-32 (UCS-4) chars
7187 * contained in @s. The result must be freed with g_free().
7190 mono_string_to_utf32 (MonoString *s)
7192 MONO_REQ_GC_UNSAFE_MODE;
7194 mono_unichar4 *utf32_output = NULL;
7195 GError *error = NULL;
7196 glong items_written;
7201 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7204 g_error_free (error);
7206 return utf32_output;
7210 * mono_string_from_utf16:
7211 * @data: the UTF16 string (LPWSTR) to convert
7213 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7215 * Returns: a MonoString.
7218 mono_string_from_utf16 (gunichar2 *data)
7221 MonoString *result = mono_string_from_utf16_checked (data, &error);
7222 mono_error_cleanup (&error);
7227 * mono_string_from_utf16_checked:
7228 * @data: the UTF16 string (LPWSTR) to convert
7229 * @error: set on error
7231 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
7233 * Returns: a MonoString. On failure sets @error and returns NULL.
7236 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7239 MONO_REQ_GC_UNSAFE_MODE;
7241 mono_error_init (error);
7242 MonoDomain *domain = mono_domain_get ();
7248 while (data [len]) len++;
7250 return mono_string_new_utf16_checked (domain, data, len, error);
7254 * mono_string_from_utf32:
7255 * @data: the UTF32 string (LPWSTR) to convert
7257 * Converts a UTF32 (UCS-4)to a MonoString.
7259 * Returns: a MonoString.
7262 mono_string_from_utf32 (mono_unichar4 *data)
7265 MonoString *result = mono_string_from_utf32_checked (data, &error);
7266 mono_error_cleanup (&error);
7271 * mono_string_from_utf32_checked:
7272 * @data: the UTF32 string (LPWSTR) to convert
7273 * @error: set on error
7275 * Converts a UTF32 (UCS-4)to a MonoString.
7277 * Returns: a MonoString. On failure returns NULL and sets @error.
7280 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7282 MONO_REQ_GC_UNSAFE_MODE;
7284 mono_error_init (error);
7285 MonoString* result = NULL;
7286 mono_unichar2 *utf16_output = NULL;
7287 GError *gerror = NULL;
7288 glong items_written;
7294 while (data [len]) len++;
7296 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7299 g_error_free (gerror);
7301 result = mono_string_from_utf16_checked (utf16_output, error);
7302 g_free (utf16_output);
7307 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7309 MONO_REQ_GC_UNSAFE_MODE;
7316 r = mono_string_to_utf8_ignore (s);
7318 r = mono_string_to_utf8_checked (s, error);
7319 if (!mono_error_ok (error))
7326 len = strlen (r) + 1;
7328 mp_s = (char *)mono_mempool_alloc (mp, len);
7330 mp_s = (char *)mono_image_alloc (image, len);
7332 memcpy (mp_s, r, len);
7340 * mono_string_to_utf8_image:
7341 * @s: a System.String
7343 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
7346 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
7348 MONO_REQ_GC_UNSAFE_MODE;
7350 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
7354 * mono_string_to_utf8_mp:
7355 * @s: a System.String
7357 * Same as mono_string_to_utf8, but allocate the string from a mempool.
7360 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7362 MONO_REQ_GC_UNSAFE_MODE;
7364 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7368 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7371 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7373 eh_callbacks = *cbs;
7376 MonoRuntimeExceptionHandlingCallbacks *
7377 mono_get_eh_callbacks (void)
7379 return &eh_callbacks;
7383 * mono_raise_exception:
7384 * @ex: exception object
7386 * Signal the runtime that the exception @ex has been raised in unmanaged code.
7389 mono_raise_exception (MonoException *ex)
7391 MONO_REQ_GC_UNSAFE_MODE;
7394 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
7395 * that will cause gcc to omit the function epilog, causing problems when
7396 * the JIT tries to walk the stack, since the return address on the stack
7397 * will point into the next function in the executable, not this one.
7399 eh_callbacks.mono_raise_exception (ex);
7403 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7405 MONO_REQ_GC_UNSAFE_MODE;
7407 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7411 * mono_wait_handle_new:
7412 * @domain: Domain where the object will be created
7413 * @handle: Handle for the wait handle
7414 * @error: set on error.
7416 * Returns: A new MonoWaitHandle created in the given domain for the
7417 * given handle. On failure returns NULL and sets @rror.
7420 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7422 MONO_REQ_GC_UNSAFE_MODE;
7424 MonoWaitHandle *res;
7425 gpointer params [1];
7426 static MonoMethod *handle_set;
7428 mono_error_init (error);
7429 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7430 return_val_if_nok (error, NULL);
7432 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
7434 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7436 params [0] = &handle;
7438 mono_runtime_invoke_checked (handle_set, res, params, error);
7443 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7445 MONO_REQ_GC_UNSAFE_MODE;
7447 static MonoClassField *f_safe_handle = NULL;
7450 if (!f_safe_handle) {
7451 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7452 g_assert (f_safe_handle);
7455 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7461 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7463 MONO_REQ_GC_UNSAFE_MODE;
7465 RuntimeInvokeFunction runtime_invoke;
7467 mono_error_init (error);
7469 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7470 MonoMethod *method = mono_get_context_capture_method ();
7471 MonoMethod *wrapper;
7474 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7475 domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7476 return_val_if_nok (error, NULL);
7477 domain->capture_context_method = mono_compile_method_checked (method, error);
7478 return_val_if_nok (error, NULL);
7481 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7483 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7486 * mono_async_result_new:
7487 * @domain:domain where the object will be created.
7488 * @handle: wait handle.
7489 * @state: state to pass to AsyncResult
7490 * @data: C closure data.
7491 * @error: set on error.
7493 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
7494 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
7495 * On failure returns NULL and sets @error.
7499 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7501 MONO_REQ_GC_UNSAFE_MODE;
7503 mono_error_init (error);
7504 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7505 return_val_if_nok (error, NULL);
7506 MonoObject *context = mono_runtime_capture_context (domain, error);
7507 return_val_if_nok (error, NULL);
7508 /* we must capture the execution context from the original thread */
7510 MONO_OBJECT_SETREF (res, execution_context, context);
7511 /* note: result may be null if the flow is suppressed */
7514 res->data = (void **)data;
7515 MONO_OBJECT_SETREF (res, object_data, object_data);
7516 MONO_OBJECT_SETREF (res, async_state, state);
7517 MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7518 return_val_if_nok (error, NULL);
7520 MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7522 res->sync_completed = FALSE;
7523 res->completed = FALSE;
7529 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7531 MONO_REQ_GC_UNSAFE_MODE;
7538 g_assert (ares->async_delegate);
7540 ac = (MonoAsyncCall*) ares->object_data;
7542 res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7543 if (mono_error_set_pending_exception (&error))
7546 gpointer wait_event = NULL;
7548 ac->msg->exc = NULL;
7550 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7552 /* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7553 mono_threads_begin_abort_protected_block ();
7555 if (!ac->msg->exc) {
7556 MonoException *ex = mono_error_convert_to_exception (&error);
7557 ac->msg->exc = (MonoObject *)ex;
7559 mono_error_cleanup (&error);
7562 MONO_OBJECT_SETREF (ac, res, res);
7564 mono_monitor_enter ((MonoObject*) ares);
7565 ares->completed = 1;
7567 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7568 mono_monitor_exit ((MonoObject*) ares);
7570 if (wait_event != NULL)
7571 SetEvent (wait_event);
7573 mono_error_init (&error); //the else branch would leave it in an undefined state
7575 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7577 mono_threads_end_abort_protected_block ();
7579 if (mono_error_set_pending_exception (&error))
7587 mono_message_init (MonoDomain *domain,
7588 MonoMethodMessage *this_obj,
7589 MonoReflectionMethod *method,
7590 MonoArray *out_args,
7593 MONO_REQ_GC_UNSAFE_MODE;
7595 static MonoMethod *init_message_method = NULL;
7597 if (!init_message_method) {
7598 init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7599 g_assert (init_message_method != NULL);
7602 mono_error_init (error);
7603 /* FIXME set domain instead? */
7604 g_assert (domain == mono_domain_get ());
7611 mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7612 return is_ok (error);
7615 #ifndef DISABLE_REMOTING
7617 * mono_remoting_invoke:
7618 * @real_proxy: pointer to a RealProxy object
7619 * @msg: The MonoMethodMessage to execute
7620 * @exc: used to store exceptions
7621 * @out_args: used to store output arguments
7623 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
7624 * IMessage interface and it is not trivial to extract results from there. So
7625 * we call an helper method PrivateInvoke instead of calling
7626 * RealProxy::Invoke() directly.
7628 * Returns: the result object.
7631 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7633 MONO_REQ_GC_UNSAFE_MODE;
7636 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7641 mono_error_init (error);
7643 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7646 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7648 mono_error_set_not_supported (error, "Linked away.");
7651 real_proxy->vtable->domain->private_invoke_method = im;
7654 pa [0] = real_proxy;
7659 o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7660 return_val_if_nok (error, NULL);
7667 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7668 MonoObject **exc, MonoArray **out_args, MonoError *error)
7670 MONO_REQ_GC_UNSAFE_MODE;
7672 static MonoClass *object_array_klass;
7673 mono_error_init (error);
7677 MonoMethodSignature *sig;
7679 int i, j, outarg_count = 0;
7681 #ifndef DISABLE_REMOTING
7682 if (target && mono_object_is_transparent_proxy (target)) {
7683 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7684 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7685 target = tp->rp->unwrapped_server;
7687 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7692 domain = mono_domain_get ();
7693 method = msg->method->method;
7694 sig = mono_method_signature (method);
7696 for (i = 0; i < sig->param_count; i++) {
7697 if (sig->params [i]->byref)
7701 if (!object_array_klass) {
7704 klass = mono_array_class_get (mono_defaults.object_class, 1);
7707 mono_memory_barrier ();
7708 object_array_klass = klass;
7711 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7712 return_val_if_nok (error, NULL);
7714 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7717 MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7718 return_val_if_nok (error, NULL);
7720 for (i = 0, j = 0; i < sig->param_count; i++) {
7721 if (sig->params [i]->byref) {
7723 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7724 mono_array_setref (*out_args, j, arg);
7733 * prepare_to_string_method:
7735 * @target: Set to @obj or unboxed value if a valuetype
7737 * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7740 prepare_to_string_method (MonoObject *obj, void **target)
7742 MONO_REQ_GC_UNSAFE_MODE;
7744 static MonoMethod *to_string = NULL;
7752 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7754 method = mono_object_get_virtual_method (obj, to_string);
7756 // Unbox value type if needed
7757 if (mono_class_is_valuetype (mono_method_get_class (method))) {
7758 *target = mono_object_unbox (obj);
7764 * mono_object_to_string:
7766 * @exc: Any exception thrown by ToString (). May be NULL.
7768 * Returns: the result of calling ToString () on an object.
7771 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7774 MonoString *s = NULL;
7776 MonoMethod *method = prepare_to_string_method (obj, &target);
7778 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7779 if (*exc == NULL && !mono_error_ok (&error))
7780 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
7782 mono_error_cleanup (&error);
7784 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7785 mono_error_raise_exception (&error); /* OK to throw, external only without a good alternative */
7792 * mono_object_to_string_checked:
7794 * @error: Set on error.
7796 * Returns: the result of calling ToString () on an object. If the
7797 * method cannot be invoked or if it raises an exception, sets @error
7801 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7803 mono_error_init (error);
7805 MonoMethod *method = prepare_to_string_method (obj, &target);
7806 return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7810 * mono_object_try_to_string:
7812 * @exc: Any exception thrown by ToString (). Must not be NULL.
7813 * @error: Set if method cannot be invoked.
7815 * Returns: the result of calling ToString () on an object. If the
7816 * method cannot be invoked sets @error, if it raises an exception sets @exc,
7820 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7823 mono_error_init (error);
7825 MonoMethod *method = prepare_to_string_method (obj, &target);
7826 return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7832 * mono_print_unhandled_exception:
7833 * @exc: The exception
7835 * Prints the unhandled exception.
7838 mono_print_unhandled_exception (MonoObject *exc)
7840 MONO_REQ_GC_UNSAFE_MODE;
7843 char *message = (char*)"";
7844 gboolean free_message = FALSE;
7847 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7848 message = g_strdup ("OutOfMemoryException");
7849 free_message = TRUE;
7850 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7851 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7852 free_message = TRUE;
7855 if (((MonoException*)exc)->native_trace_ips) {
7856 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7857 free_message = TRUE;
7859 MonoObject *other_exc = NULL;
7860 str = mono_object_try_to_string (exc, &other_exc, &error);
7861 if (other_exc == NULL && !is_ok (&error))
7862 other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7864 mono_error_cleanup (&error);
7866 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7867 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7869 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7870 original_backtrace, nested_backtrace);
7872 g_free (original_backtrace);
7873 g_free (nested_backtrace);
7874 free_message = TRUE;
7876 message = mono_string_to_utf8_checked (str, &error);
7877 if (!mono_error_ok (&error)) {
7878 mono_error_cleanup (&error);
7879 message = (char *) "";
7881 free_message = TRUE;
7888 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7889 * exc->vtable->klass->name, message);
7891 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7898 * mono_delegate_ctor_with_method:
7899 * @this: pointer to an uninitialized delegate object
7900 * @target: target object
7901 * @addr: pointer to native code
7903 * @error: set on error.
7905 * Initialize a delegate and sets a specific method, not the one
7906 * associated with addr. This is useful when sharing generic code.
7907 * In that case addr will most probably not be associated with the
7908 * correct instantiation of the method.
7909 * On failure returns FALSE and sets @error.
7912 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method, MonoError *error)
7914 MONO_REQ_GC_UNSAFE_MODE;
7916 mono_error_init (error);
7917 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7919 g_assert (this_obj);
7922 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7925 delegate->method = method;
7927 mono_stats.delegate_creations++;
7929 #ifndef DISABLE_REMOTING
7930 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7932 method = mono_marshal_get_remoting_invoke (method);
7933 delegate->method_ptr = mono_compile_method_checked (method, error);
7934 return_val_if_nok (error, FALSE);
7935 MONO_OBJECT_SETREF (delegate, target, target);
7939 delegate->method_ptr = addr;
7940 MONO_OBJECT_SETREF (delegate, target, target);
7943 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7944 if (callbacks.init_delegate)
7945 callbacks.init_delegate (delegate);
7950 * mono_delegate_ctor:
7951 * @this: pointer to an uninitialized delegate object
7952 * @target: target object
7953 * @addr: pointer to native code
7954 * @error: set on error.
7956 * This is used to initialize a delegate.
7957 * On failure returns FALSE and sets @error.
7960 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoError *error)
7962 MONO_REQ_GC_UNSAFE_MODE;
7964 mono_error_init (error);
7965 MonoDomain *domain = mono_domain_get ();
7967 MonoMethod *method = NULL;
7971 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7973 if (!ji && domain != mono_get_root_domain ())
7974 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7976 method = mono_jit_info_get_method (ji);
7977 g_assert (!method->klass->generic_container);
7980 return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
7984 * mono_method_call_message_new:
7985 * @method: method to encapsulate
7986 * @params: parameters to the method
7987 * @invoke: optional, delegate invoke.
7988 * @cb: async callback delegate.
7989 * @state: state passed to the async callback.
7990 * @error: set on error.
7992 * Translates arguments pointers into a MonoMethodMessage.
7993 * On failure returns NULL and sets @error.
7996 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7997 MonoDelegate **cb, MonoObject **state, MonoError *error)
7999 MONO_REQ_GC_UNSAFE_MODE;
8001 mono_error_init (error);
8003 MonoDomain *domain = mono_domain_get ();
8004 MonoMethodSignature *sig = mono_method_signature (method);
8005 MonoMethodMessage *msg;
8008 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8009 return_val_if_nok (error, NULL);
8012 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8013 return_val_if_nok (error, NULL);
8014 mono_message_init (domain, msg, rm, NULL, error);
8015 return_val_if_nok (error, NULL);
8016 count = sig->param_count - 2;
8018 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8019 return_val_if_nok (error, NULL);
8020 mono_message_init (domain, msg, rm, NULL, error);
8021 return_val_if_nok (error, NULL);
8022 count = sig->param_count;
8025 for (i = 0; i < count; i++) {
8030 if (sig->params [i]->byref)
8031 vpos = *((gpointer *)params [i]);
8035 klass = mono_class_from_mono_type (sig->params [i]);
8037 if (klass->valuetype) {
8038 arg = mono_value_box_checked (domain, klass, vpos, error);
8039 return_val_if_nok (error, NULL);
8041 arg = *((MonoObject **)vpos);
8043 mono_array_setref (msg->args, i, arg);
8046 if (cb != NULL && state != NULL) {
8047 *cb = *((MonoDelegate **)params [i]);
8049 *state = *((MonoObject **)params [i]);
8056 * mono_method_return_message_restore:
8058 * Restore results from message based processing back to arguments pointers
8061 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8063 MONO_REQ_GC_UNSAFE_MODE;
8065 mono_error_init (error);
8067 MonoMethodSignature *sig = mono_method_signature (method);
8068 int i, j, type, size, out_len;
8070 if (out_args == NULL)
8072 out_len = mono_array_length (out_args);
8076 for (i = 0, j = 0; i < sig->param_count; i++) {
8077 MonoType *pt = sig->params [i];
8082 mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8086 arg = (char *)mono_array_get (out_args, gpointer, j);
8089 g_assert (type != MONO_TYPE_VOID);
8091 if (MONO_TYPE_IS_REFERENCE (pt)) {
8092 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8095 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8096 size = mono_class_value_size (klass, NULL);
8097 if (klass->has_references)
8098 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8100 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8102 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8103 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8112 #ifndef DISABLE_REMOTING
8115 * mono_load_remote_field:
8116 * @this: pointer to an object
8117 * @klass: klass of the object containing @field
8118 * @field: the field to load
8119 * @res: a storage to store the result
8121 * This method is called by the runtime on attempts to load fields of
8122 * transparent proxy objects. @this points to such TP, @klass is the class of
8123 * the object containing @field. @res is a storage location which can be
8124 * used to store the result.
8126 * Returns: an address pointing to the value of field.
8129 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8132 gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8133 mono_error_cleanup (&error);
8138 * mono_load_remote_field_checked:
8139 * @this: pointer to an object
8140 * @klass: klass of the object containing @field
8141 * @field: the field to load
8142 * @res: a storage to store the result
8143 * @error: set on error
8145 * This method is called by the runtime on attempts to load fields of
8146 * transparent proxy objects. @this points to such TP, @klass is the class of
8147 * the object containing @field. @res is a storage location which can be
8148 * used to store the result.
8150 * Returns: an address pointing to the value of field. On failure returns NULL and sets @error.
8153 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8155 MONO_REQ_GC_UNSAFE_MODE;
8157 static MonoMethod *getter = NULL;
8159 mono_error_init (error);
8161 MonoDomain *domain = mono_domain_get ();
8162 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8163 MonoClass *field_class;
8164 MonoMethodMessage *msg;
8165 MonoArray *out_args;
8169 g_assert (mono_object_is_transparent_proxy (this_obj));
8170 g_assert (res != NULL);
8172 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8173 mono_field_get_value (tp->rp->unwrapped_server, field, res);
8178 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8180 mono_error_set_not_supported (error, "Linked away.");
8185 field_class = mono_class_from_mono_type (field->type);
8187 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8188 return_val_if_nok (error, NULL);
8189 out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8190 return_val_if_nok (error, NULL);
8191 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8192 return_val_if_nok (error, NULL);
8193 mono_message_init (domain, msg, rm, out_args, error);
8194 return_val_if_nok (error, NULL);
8196 full_name = mono_type_get_full_name (klass);
8197 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
8198 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
8201 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8202 return_val_if_nok (error, NULL);
8205 mono_error_set_exception_instance (error, (MonoException *)exc);
8209 if (mono_array_length (out_args) == 0)
8212 mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8214 if (field_class->valuetype) {
8215 return ((char *)*res) + sizeof (MonoObject);
8221 * mono_load_remote_field_new:
8226 * Missing documentation.
8229 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8233 MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8234 mono_error_cleanup (&error);
8239 * mono_load_remote_field_new_checked:
8240 * @this: pointer to an object
8241 * @klass: klass of the object containing @field
8242 * @field: the field to load
8243 * @error: set on error.
8245 * This method is called by the runtime on attempts to load fields of
8246 * transparent proxy objects. @this points to such TP, @klass is the class of
8247 * the object containing @field.
8249 * Returns: a freshly allocated object containing the value of the field. On failure returns NULL and sets @error.
8252 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8254 MONO_REQ_GC_UNSAFE_MODE;
8256 mono_error_init (error);
8258 static MonoMethod *tp_load = NULL;
8260 g_assert (mono_object_is_transparent_proxy (this_obj));
8263 tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8265 mono_error_set_not_supported (error, "Linked away.");
8270 /* MonoType *type = mono_class_get_type (klass); */
8276 return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8280 * mono_store_remote_field:
8281 * @this_obj: pointer to an object
8282 * @klass: klass of the object containing @field
8283 * @field: the field to load
8284 * @val: the value/object to store
8286 * This method is called by the runtime on attempts to store fields of
8287 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8288 * the object containing @field. @val is the new value to store in @field.
8291 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8294 (void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8295 mono_error_cleanup (&error);
8299 * mono_store_remote_field_checked:
8300 * @this_obj: pointer to an object
8301 * @klass: klass of the object containing @field
8302 * @field: the field to load
8303 * @val: the value/object to store
8304 * @error: set on error
8306 * This method is called by the runtime on attempts to store fields of
8307 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
8308 * the object containing @field. @val is the new value to store in @field.
8310 * Returns: on success returns TRUE, on failure returns FALSE and sets @error.
8313 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8316 MONO_REQ_GC_UNSAFE_MODE;
8318 mono_error_init (error);
8320 MonoDomain *domain = mono_domain_get ();
8321 MonoClass *field_class;
8324 g_assert (mono_object_is_transparent_proxy (this_obj));
8326 field_class = mono_class_from_mono_type (field->type);
8328 if (field_class->valuetype) {
8329 arg = mono_value_box_checked (domain, field_class, val, error);
8330 return_val_if_nok (error, FALSE);
8332 arg = *((MonoObject**)val);
8335 return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8339 * mono_store_remote_field_new:
8345 * Missing documentation
8348 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8351 (void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8352 mono_error_cleanup (&error);
8356 * mono_store_remote_field_new_checked:
8363 * Missing documentation
8366 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8368 MONO_REQ_GC_UNSAFE_MODE;
8370 static MonoMethod *tp_store = NULL;
8372 mono_error_init (error);
8374 g_assert (mono_object_is_transparent_proxy (this_obj));
8377 tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8379 mono_error_set_not_supported (error, "Linked away.");
8389 mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8390 return is_ok (error);
8395 * mono_create_ftnptr:
8397 * Given a function address, create a function descriptor for it.
8398 * This is only needed on some platforms.
8401 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8403 return callbacks.create_ftnptr (domain, addr);
8407 * mono_get_addr_from_ftnptr:
8409 * Given a pointer to a function descriptor, return the function address.
8410 * This is only needed on some platforms.
8413 mono_get_addr_from_ftnptr (gpointer descr)
8415 return callbacks.get_addr_from_ftnptr (descr);
8419 * mono_string_chars:
8422 * Returns a pointer to the UCS16 characters stored in the MonoString
8425 mono_string_chars (MonoString *s)
8427 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8433 * mono_string_length:
8436 * Returns the lenght in characters of the string
8439 mono_string_length (MonoString *s)
8441 MONO_REQ_GC_UNSAFE_MODE;
8447 * mono_array_length:
8448 * @array: a MonoArray*
8450 * Returns the total number of elements in the array. This works for
8451 * both vectors and multidimensional arrays.
8454 mono_array_length (MonoArray *array)
8456 MONO_REQ_GC_UNSAFE_MODE;
8458 return array->max_length;
8462 * mono_array_addr_with_size:
8463 * @array: a MonoArray*
8464 * @size: size of the array elements
8465 * @idx: index into the array
8467 * Use this function to obtain the address for the @idx item on the
8468 * @array containing elements of size @size.
8470 * This method performs no bounds checking or type checking.
8472 * Returns the address of the @idx element in the array.
8475 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8477 MONO_REQ_GC_UNSAFE_MODE;
8479 return ((char*)(array)->vector) + size * idx;
8484 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8486 MonoDomain *domain = mono_domain_get ();
8490 mono_error_init (error);
8494 len = g_list_length (list);
8495 res = mono_array_new_checked (domain, eclass, len, error);
8496 return_val_if_nok (error, NULL);
8498 for (i = 0; list; list = list->next, i++)
8499 mono_array_set (res, gpointer, i, list->data);
8506 * The following section is purely to declare prototypes and
8507 * document the API, as these C files are processed by our
8513 * @array: array to alter
8514 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
8515 * @index: index into the array
8516 * @value: value to set
8518 * Value Type version: This sets the @index's element of the @array
8519 * with elements of size sizeof(type) to the provided @value.
8521 * This macro does not attempt to perform type checking or bounds checking.
8523 * Use this to set value types in a `MonoArray`.
8525 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8530 * mono_array_setref:
8531 * @array: array to alter
8532 * @index: index into the array
8533 * @value: value to set
8535 * Reference Type version: This sets the @index's element of the
8536 * @array with elements of size sizeof(type) to the provided @value.
8538 * This macro does not attempt to perform type checking or bounds checking.
8540 * Use this to reference types in a `MonoArray`.
8542 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8548 * @array: array on which to operate on
8549 * @element_type: C element type (example: MonoString *, int, MonoObject *)
8550 * @index: index into the array
8552 * Use this macro to retrieve the @index element of an @array and
8553 * extract the value assuming that the elements of the array match
8554 * the provided type value.
8556 * This method can be used with both arrays holding value types and
8557 * reference types. For reference types, the @type parameter should
8558 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
8560 * This macro does not attempt to perform type checking or bounds checking.
8562 * Returns: The element at the @index position in the @array.
8564 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)