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)
19 #include <mono/metadata/mono-endian.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/loader.h>
23 #include <mono/metadata/object.h>
24 #include <mono/metadata/gc-internals.h>
25 #include <mono/metadata/exception.h>
26 #include <mono/metadata/domain-internals.h>
27 #include "mono/metadata/metadata-internals.h"
28 #include "mono/metadata/class-internals.h"
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/marshal.h>
31 #include "mono/metadata/debug-helpers.h"
32 #include "mono/metadata/marshal.h"
33 #include <mono/metadata/threads.h>
34 #include <mono/metadata/threads-types.h>
35 #include <mono/metadata/environment.h>
36 #include "mono/metadata/profiler-private.h"
37 #include "mono/metadata/security-manager.h"
38 #include "mono/metadata/mono-debug-debugger.h"
39 #include <mono/metadata/gc-internals.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/utils/strenc.h>
43 #include <mono/utils/mono-counters.h>
44 #include <mono/utils/mono-error-internals.h>
45 #include <mono/utils/mono-memory-model.h>
46 #include <mono/utils/checked-build.h>
47 #include <mono/utils/mono-threads.h>
48 #include "cominterop.h"
51 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
54 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig);
57 free_main_args (void);
60 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
62 /* Class lazy loading functions */
63 static GENERATE_GET_CLASS_WITH_CACHE (pointer, System.Reflection, Pointer)
64 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, System.Runtime.Remoting, RemotingServices)
65 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, System, UnhandledExceptionEventArgs)
66 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, System, STAThreadAttribute)
67 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, System.Runtime.Remoting.Activation, ActivationServices)
70 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
71 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
72 static mono_mutex_t ldstr_section;
75 mono_runtime_object_init (MonoObject *this_obj)
77 MONO_REQ_GC_UNSAFE_MODE;
80 MonoMethod *method = NULL;
81 MonoClass *klass = this_obj->vtable->klass;
83 method = mono_class_get_method_from_name (klass, ".ctor", 0);
85 g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
87 if (method->klass->valuetype)
88 this_obj = (MonoObject *)mono_object_unbox (this_obj);
90 mono_runtime_invoke_checked (method, this_obj, NULL, &error);
91 mono_error_raise_exception (&error); /* FIXME don't raise here */
94 /* The pseudo algorithm for type initialization from the spec
95 Note it doesn't say anything about domains - only threads.
97 2. If the type is initialized you are done.
98 2.1. If the type is not yet initialized, try to take an
100 2.2. If successful, record this thread as responsible for
101 initializing the type and proceed to step 2.3.
102 2.2.1. If not, see whether this thread or any thread
103 waiting for this thread to complete already holds the lock.
104 2.2.2. If so, return since blocking would create a deadlock. This thread
105 will now see an incompletely initialized state for the type,
106 but no deadlock will arise.
107 2.2.3 If not, block until the type is initialized then return.
108 2.3 Initialize the parent type and then all interfaces implemented
110 2.4 Execute the type initialization code for this type.
111 2.5 Mark the type as initialized, release the initialization lock,
112 awaken any threads waiting for this type to be initialized,
119 MonoNativeThreadId initializing_tid;
120 guint32 waiting_count;
122 MonoCoopMutex initialization_section;
123 } TypeInitializationLock;
125 /* for locking access to type_initialization_hash and blocked_thread_hash */
126 static MonoCoopMutex type_initialization_section;
129 mono_type_initialization_lock (void)
131 /* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
132 mono_coop_mutex_lock (&type_initialization_section);
136 mono_type_initialization_unlock (void)
138 mono_coop_mutex_unlock (&type_initialization_section);
142 mono_type_init_lock (TypeInitializationLock *lock)
144 MONO_REQ_GC_NEUTRAL_MODE;
146 mono_coop_mutex_lock (&lock->initialization_section);
150 mono_type_init_unlock (TypeInitializationLock *lock)
152 mono_coop_mutex_unlock (&lock->initialization_section);
155 /* from vtable to lock */
156 static GHashTable *type_initialization_hash;
158 /* from thread id to thread id being waited on */
159 static GHashTable *blocked_thread_hash;
162 static MonoThread *main_thread;
164 /* Functions supplied by the runtime */
165 static MonoRuntimeCallbacks callbacks;
168 * mono_thread_set_main:
169 * @thread: thread to set as the main thread
171 * This function can be used to instruct the runtime to treat @thread
172 * as the main thread, ie, the thread that would normally execute the Main()
173 * method. This basically means that at the end of @thread, the runtime will
174 * wait for the existing foreground threads to quit and other such details.
177 mono_thread_set_main (MonoThread *thread)
179 MONO_REQ_GC_UNSAFE_MODE;
181 static gboolean registered = FALSE;
184 MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
188 main_thread = thread;
192 mono_thread_get_main (void)
194 MONO_REQ_GC_UNSAFE_MODE;
200 mono_type_initialization_init (void)
202 mono_coop_mutex_init_recursive (&type_initialization_section);
203 type_initialization_hash = g_hash_table_new (NULL, NULL);
204 blocked_thread_hash = g_hash_table_new (NULL, NULL);
205 mono_os_mutex_init_recursive (&ldstr_section);
209 mono_type_initialization_cleanup (void)
212 /* This is causing race conditions with
213 * mono_release_type_locks
215 mono_coop_mutex_destroy (&type_initialization_section);
216 g_hash_table_destroy (type_initialization_hash);
217 type_initialization_hash = NULL;
219 mono_os_mutex_destroy (&ldstr_section);
220 g_hash_table_destroy (blocked_thread_hash);
221 blocked_thread_hash = NULL;
227 * get_type_init_exception_for_vtable:
229 * Return the stored type initialization exception for VTABLE.
231 static MonoException*
232 get_type_init_exception_for_vtable (MonoVTable *vtable)
234 MONO_REQ_GC_UNSAFE_MODE;
236 MonoDomain *domain = vtable->domain;
237 MonoClass *klass = vtable->klass;
241 if (!vtable->init_failed)
242 g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
245 * If the initializing thread was rudely aborted, the exception is not stored
249 mono_domain_lock (domain);
250 if (domain->type_init_exception_hash)
251 ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
252 mono_domain_unlock (domain);
255 if (klass->name_space && *klass->name_space)
256 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
258 full_name = g_strdup (klass->name);
259 ex = mono_get_exception_type_initialization (full_name, NULL);
267 * mono_runtime_class_init:
268 * @vtable: vtable that needs to be initialized
270 * This routine calls the class constructor for @vtable.
273 mono_runtime_class_init (MonoVTable *vtable)
275 MONO_REQ_GC_UNSAFE_MODE;
278 mono_runtime_class_init_full (vtable, &error);
279 mono_error_assert_ok (&error);
283 * mono_runtime_class_init_full:
284 * @vtable that neeeds to be initialized
285 * @error set on error
287 * returns TRUE if class constructor .cctor has been initialized successfully, or FALSE otherwise and sets @error.
291 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
293 MONO_REQ_GC_UNSAFE_MODE;
295 MonoMethod *method = NULL;
298 MonoDomain *domain = vtable->domain;
299 TypeInitializationLock *lock;
300 MonoNativeThreadId tid;
301 int do_initialization = 0;
302 MonoDomain *last_domain = NULL;
304 mono_error_init (error);
306 if (vtable->initialized)
309 klass = vtable->klass;
311 if (!klass->image->checked_module_cctor) {
312 mono_image_check_for_module_cctor (klass->image);
313 if (klass->image->has_module_cctor) {
314 MonoClass *module_klass;
315 MonoVTable *module_vtable;
317 module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
322 module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
325 if (!mono_runtime_class_init_full (module_vtable, error))
329 method = mono_class_get_cctor (klass);
331 vtable->initialized = 1;
335 tid = mono_native_thread_id_get ();
337 mono_type_initialization_lock ();
338 /* double check... */
339 if (vtable->initialized) {
340 mono_type_initialization_unlock ();
343 if (vtable->init_failed) {
344 mono_type_initialization_unlock ();
346 /* The type initialization already failed once, rethrow the same exception */
347 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
350 lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
352 /* This thread will get to do the initialization */
353 if (mono_domain_get () != domain) {
354 /* Transfer into the target domain */
355 last_domain = mono_domain_get ();
356 if (!mono_domain_set (domain, FALSE)) {
357 vtable->initialized = 1;
358 mono_type_initialization_unlock ();
359 mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
363 lock = (TypeInitializationLock *)g_malloc (sizeof (TypeInitializationLock));
364 mono_coop_mutex_init_recursive (&lock->initialization_section);
365 lock->initializing_tid = tid;
366 lock->waiting_count = 1;
368 /* grab the vtable lock while this thread still owns type_initialization_section */
369 /* This is why type_initialization_lock needs to enter blocking mode */
370 mono_type_init_lock (lock);
371 g_hash_table_insert (type_initialization_hash, vtable, lock);
372 do_initialization = 1;
375 TypeInitializationLock *pending_lock;
377 if (mono_native_thread_id_equals (lock->initializing_tid, tid) || lock->done) {
378 mono_type_initialization_unlock ();
381 /* see if the thread doing the initialization is already blocked on this thread */
382 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
383 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
384 if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
385 if (!pending_lock->done) {
386 mono_type_initialization_unlock ();
389 /* the thread doing the initialization is blocked on this thread,
390 but on a lock that has already been freed. It just hasn't got
395 blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
397 ++lock->waiting_count;
398 /* record the fact that we are waiting on the initializing thread */
399 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
401 mono_type_initialization_unlock ();
403 if (do_initialization) {
404 MonoException *exc = NULL;
405 mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
406 if (exc != NULL && mono_error_ok (error)) {
407 mono_error_set_exception_instance (error, exc);
410 /* If the initialization failed, mark the class as unusable. */
411 /* Avoid infinite loops */
412 if (!(mono_error_ok(error) ||
413 (klass->image == mono_defaults.corlib &&
414 !strcmp (klass->name_space, "System") &&
415 !strcmp (klass->name, "TypeInitializationException")))) {
416 vtable->init_failed = 1;
418 if (klass->name_space && *klass->name_space)
419 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
421 full_name = g_strdup (klass->name);
422 mono_error_set_exception_instance (error, mono_get_exception_type_initialization (full_name, exc));
425 MonoException *exc_to_store = mono_error_convert_to_exception (error);
426 /* What we really want to do here is clone the error object and store one copy in the
427 * domain's exception hash and use the other one to error out here. */
428 mono_error_set_exception_instance (error, exc_to_store);
430 * Store the exception object so it could be thrown on subsequent
433 mono_domain_lock (domain);
434 if (!domain->type_init_exception_hash)
435 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");
436 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_store);
437 mono_domain_unlock (domain);
441 mono_domain_set (last_domain, TRUE);
443 mono_type_init_unlock (lock);
445 /* this just blocks until the initializing thread is done */
446 mono_type_init_lock (lock);
447 mono_type_init_unlock (lock);
450 mono_type_initialization_lock ();
451 if (!mono_native_thread_id_equals (lock->initializing_tid, tid))
452 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
453 --lock->waiting_count;
454 if (lock->waiting_count == 0) {
455 mono_coop_mutex_destroy (&lock->initialization_section);
456 g_hash_table_remove (type_initialization_hash, vtable);
459 mono_memory_barrier ();
460 if (!vtable->init_failed)
461 vtable->initialized = 1;
462 mono_type_initialization_unlock ();
464 if (vtable->init_failed) {
465 /* Either we were the initializing thread or we waited for the initialization */
466 mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
473 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
475 MONO_REQ_GC_NEUTRAL_MODE;
477 MonoVTable *vtable = (MonoVTable*)key;
479 TypeInitializationLock *lock = (TypeInitializationLock*) value;
480 if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
483 * Have to set this since it cannot be set by the normal code in
484 * mono_runtime_class_init (). In this case, the exception object is not stored,
485 * and get_type_init_exception_for_class () needs to be aware of this.
487 vtable->init_failed = 1;
488 mono_type_init_unlock (lock);
489 --lock->waiting_count;
490 if (lock->waiting_count == 0) {
491 mono_coop_mutex_destroy (&lock->initialization_section);
500 mono_release_type_locks (MonoInternalThread *thread)
502 MONO_REQ_GC_UNSAFE_MODE;
504 mono_type_initialization_lock ();
505 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
506 mono_type_initialization_unlock ();
510 default_trampoline (MonoMethod *method)
516 default_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
518 g_assert_not_reached ();
523 #ifndef DISABLE_REMOTING
526 default_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
528 g_error ("remoting not installed");
532 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
536 default_delegate_trampoline (MonoDomain *domain, MonoClass *klass)
538 g_assert_not_reached ();
542 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
543 static MonoJumpTrampoline arch_create_jump_trampoline = default_jump_trampoline;
544 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
545 static MonoImtThunkBuilder imt_thunk_builder;
546 static gboolean always_build_imt_thunks;
548 #if (MONO_IMT_SIZE > 32)
549 #error "MONO_IMT_SIZE cannot be larger than 32"
553 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
555 memcpy (&callbacks, cbs, sizeof (*cbs));
558 MonoRuntimeCallbacks*
559 mono_get_runtime_callbacks (void)
565 mono_install_trampoline (MonoTrampoline func)
567 arch_create_jit_trampoline = func? func: default_trampoline;
571 mono_install_jump_trampoline (MonoJumpTrampoline func)
573 arch_create_jump_trampoline = func? func: default_jump_trampoline;
576 #ifndef DISABLE_REMOTING
578 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
580 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
585 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
587 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
591 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
592 imt_thunk_builder = func;
596 mono_set_always_build_imt_thunks (gboolean value)
598 always_build_imt_thunks = value;
602 * mono_compile_method:
603 * @method: The method to compile.
605 * This JIT-compiles the method, and returns the pointer to the native code
609 mono_compile_method (MonoMethod *method)
614 MONO_REQ_GC_NEUTRAL_MODE
616 if (!callbacks.compile_method) {
617 g_error ("compile method called on uninitialized runtime");
620 res = callbacks.compile_method (method, &error);
621 if (!mono_error_ok (&error))
622 mono_error_raise_exception (&error);
627 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
629 MONO_REQ_GC_NEUTRAL_MODE
631 return arch_create_jump_trampoline (domain, method, add_sync_wrapper);
635 mono_runtime_create_delegate_trampoline (MonoClass *klass)
637 MONO_REQ_GC_NEUTRAL_MODE
639 return arch_create_delegate_trampoline (mono_domain_get (), klass);
642 static MonoFreeMethodFunc default_mono_free_method = NULL;
645 * mono_install_free_method:
646 * @func: pointer to the MonoFreeMethodFunc used to release a method
648 * This is an internal VM routine, it is used for the engines to
649 * register a handler to release the resources associated with a method.
651 * Methods are freed when no more references to the delegate that holds
655 mono_install_free_method (MonoFreeMethodFunc func)
657 default_mono_free_method = func;
661 * mono_runtime_free_method:
662 * @domain; domain where the method is hosted
663 * @method: method to release
665 * This routine is invoked to free the resources associated with
666 * a method that has been JIT compiled. This is used to discard
667 * methods that were used only temporarily (for example, used in marshalling)
671 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
673 MONO_REQ_GC_NEUTRAL_MODE
675 if (default_mono_free_method != NULL)
676 default_mono_free_method (domain, method);
678 mono_method_clear_object (domain, method);
680 mono_free_method (method);
684 * The vtables in the root appdomain are assumed to be reachable by other
685 * roots, and we don't use typed allocation in the other domains.
688 /* The sync block is no longer a GC pointer */
689 #define GC_HEADER_BITMAP (0)
691 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
694 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
696 MONO_REQ_GC_NEUTRAL_MODE;
698 MonoClassField *field;
704 max_size = mono_class_data_size (klass) / sizeof (gpointer);
706 max_size = klass->instance_size / sizeof (gpointer);
707 if (max_size > size) {
708 g_assert (offset <= 0);
709 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
714 /*An Ephemeron cannot be marked by sgen*/
715 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
717 memset (bitmap, 0, size / 8);
722 for (p = klass; p != NULL; p = p->parent) {
723 gpointer iter = NULL;
724 while ((field = mono_class_get_fields (p, &iter))) {
728 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
730 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
733 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
736 /* FIXME: should not happen, flag as type load error */
737 if (field->type->byref)
740 if (static_fields && field->offset == -1)
744 pos = field->offset / sizeof (gpointer);
747 type = mono_type_get_underlying_type (field->type);
748 switch (type->type) {
751 case MONO_TYPE_FNPTR:
753 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
758 if (klass->image != mono_defaults.corlib)
761 case MONO_TYPE_STRING:
762 case MONO_TYPE_SZARRAY:
763 case MONO_TYPE_CLASS:
764 case MONO_TYPE_OBJECT:
765 case MONO_TYPE_ARRAY:
766 g_assert ((field->offset % sizeof(gpointer)) == 0);
768 g_assert (pos < size || pos <= max_size);
769 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
770 *max_set = MAX (*max_set, pos);
772 case MONO_TYPE_GENERICINST:
773 if (!mono_type_generic_inst_is_valuetype (type)) {
774 g_assert ((field->offset % sizeof(gpointer)) == 0);
776 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
777 *max_set = MAX (*max_set, pos);
782 case MONO_TYPE_VALUETYPE: {
783 MonoClass *fclass = mono_class_from_mono_type (field->type);
784 if (fclass->has_references) {
785 /* remove the object header */
786 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
800 case MONO_TYPE_BOOLEAN:
804 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
815 * mono_class_compute_bitmap:
817 * Mono internal function to compute a bitmap of reference fields in a class.
820 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
822 MONO_REQ_GC_NEUTRAL_MODE;
824 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
829 * similar to the above, but sets the bits in the bitmap for any non-ref field
830 * and ignores static fields
833 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
835 MonoClassField *field;
840 max_size = class->instance_size / sizeof (gpointer);
841 if (max_size >= size) {
842 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
845 for (p = class; p != NULL; p = p->parent) {
846 gpointer iter = NULL;
847 while ((field = mono_class_get_fields (p, &iter))) {
850 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
852 /* FIXME: should not happen, flag as type load error */
853 if (field->type->byref)
856 pos = field->offset / sizeof (gpointer);
859 type = mono_type_get_underlying_type (field->type);
860 switch (type->type) {
861 #if SIZEOF_VOID_P == 8
865 case MONO_TYPE_FNPTR:
870 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
871 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
872 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
875 #if SIZEOF_VOID_P == 4
879 case MONO_TYPE_FNPTR:
884 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
885 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
886 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
892 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
893 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
894 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
897 case MONO_TYPE_BOOLEAN:
900 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
902 case MONO_TYPE_STRING:
903 case MONO_TYPE_SZARRAY:
904 case MONO_TYPE_CLASS:
905 case MONO_TYPE_OBJECT:
906 case MONO_TYPE_ARRAY:
908 case MONO_TYPE_GENERICINST:
909 if (!mono_type_generic_inst_is_valuetype (type)) {
914 case MONO_TYPE_VALUETYPE: {
915 MonoClass *fclass = mono_class_from_mono_type (field->type);
916 /* remove the object header */
917 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
921 g_assert_not_reached ();
930 * mono_class_insecure_overlapping:
931 * check if a class with explicit layout has references and non-references
932 * fields overlapping.
934 * Returns: TRUE if it is insecure to load the type.
937 mono_class_insecure_overlapping (MonoClass *klass)
941 gsize default_bitmap [4] = {0};
943 gsize default_nrbitmap [4] = {0};
944 int i, insecure = FALSE;
947 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
948 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
950 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
951 int idx = i % (sizeof (bitmap [0]) * 8);
952 if (bitmap [idx] & nrbitmap [idx]) {
957 if (bitmap != default_bitmap)
959 if (nrbitmap != default_nrbitmap)
962 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
970 ves_icall_string_alloc (int length)
973 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
974 mono_error_raise_exception (&error);
980 mono_class_compute_gc_descriptor (MonoClass *klass)
982 MONO_REQ_GC_NEUTRAL_MODE;
986 gsize default_bitmap [4] = {0};
987 static gboolean gcj_inited = FALSE;
992 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
993 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
996 mono_loader_unlock ();
1000 mono_class_init (klass);
1002 if (klass->gc_descr_inited)
1005 klass->gc_descr_inited = TRUE;
1006 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1008 bitmap = default_bitmap;
1009 if (klass == mono_defaults.string_class) {
1010 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1011 } else if (klass->rank) {
1012 mono_class_compute_gc_descriptor (klass->element_class);
1013 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1015 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1016 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1017 class->name_space, class->name);*/
1019 /* remove the object header */
1020 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1021 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));
1022 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1023 class->name_space, class->name);*/
1024 if (bitmap != default_bitmap)
1028 /*static int count = 0;
1031 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1032 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1034 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1035 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1037 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1038 if (bitmap != default_bitmap)
1044 * field_is_special_static:
1045 * @fklass: The MonoClass to look up.
1046 * @field: The MonoClassField describing the field.
1048 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1049 * SPECIAL_STATIC_NONE otherwise.
1052 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1054 MONO_REQ_GC_NEUTRAL_MODE;
1056 MonoCustomAttrInfo *ainfo;
1058 ainfo = mono_custom_attrs_from_field (fklass, field);
1061 for (i = 0; i < ainfo->num_attrs; ++i) {
1062 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1063 if (klass->image == mono_defaults.corlib) {
1064 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1065 mono_custom_attrs_free (ainfo);
1066 return SPECIAL_STATIC_THREAD;
1068 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1069 mono_custom_attrs_free (ainfo);
1070 return SPECIAL_STATIC_CONTEXT;
1074 mono_custom_attrs_free (ainfo);
1075 return SPECIAL_STATIC_NONE;
1078 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1079 #define mix(a,b,c) { \
1080 a -= c; a ^= rot(c, 4); c += b; \
1081 b -= a; b ^= rot(a, 6); a += c; \
1082 c -= b; c ^= rot(b, 8); b += a; \
1083 a -= c; a ^= rot(c,16); c += b; \
1084 b -= a; b ^= rot(a,19); a += c; \
1085 c -= b; c ^= rot(b, 4); b += a; \
1087 #define final(a,b,c) { \
1088 c ^= b; c -= rot(b,14); \
1089 a ^= c; a -= rot(c,11); \
1090 b ^= a; b -= rot(a,25); \
1091 c ^= b; c -= rot(b,16); \
1092 a ^= c; a -= rot(c,4); \
1093 b ^= a; b -= rot(a,14); \
1094 c ^= b; c -= rot(b,24); \
1098 * mono_method_get_imt_slot:
1100 * The IMT slot is embedded into AOTed code, so this must return the same value
1101 * for the same method across all executions. This means:
1102 * - pointers shouldn't be used as hash values.
1103 * - mono_metadata_str_hash () should be used for hashing strings.
1106 mono_method_get_imt_slot (MonoMethod *method)
1108 MONO_REQ_GC_NEUTRAL_MODE;
1110 MonoMethodSignature *sig;
1112 guint32 *hashes_start, *hashes;
1116 /* This can be used to stress tests the collision code */
1120 * We do this to simplify generic sharing. It will hurt
1121 * performance in cases where a class implements two different
1122 * instantiations of the same generic interface.
1123 * The code in build_imt_slots () depends on this.
1125 if (method->is_inflated)
1126 method = ((MonoMethodInflated*)method)->declaring;
1128 sig = mono_method_signature (method);
1129 hashes_count = sig->param_count + 4;
1130 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1131 hashes = hashes_start;
1133 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1134 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1135 method->klass->name_space, method->klass->name, method->name);
1138 /* Initialize hashes */
1139 hashes [0] = mono_metadata_str_hash (method->klass->name);
1140 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1141 hashes [2] = mono_metadata_str_hash (method->name);
1142 hashes [3] = mono_metadata_type_hash (sig->ret);
1143 for (i = 0; i < sig->param_count; i++) {
1144 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1147 /* Setup internal state */
1148 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1150 /* Handle most of the hashes */
1151 while (hashes_count > 3) {
1160 /* Handle the last 3 hashes (all the case statements fall through) */
1161 switch (hashes_count) {
1162 case 3 : c += hashes [2];
1163 case 2 : b += hashes [1];
1164 case 1 : a += hashes [0];
1166 case 0: /* nothing left to add */
1170 free (hashes_start);
1171 /* Report the result */
1172 return c % MONO_IMT_SIZE;
1181 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1182 MONO_REQ_GC_NEUTRAL_MODE;
1184 guint32 imt_slot = mono_method_get_imt_slot (method);
1185 MonoImtBuilderEntry *entry;
1187 if (slot_num >= 0 && imt_slot != slot_num) {
1188 /* we build just a single imt slot and this is not it */
1192 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1193 entry->key = method;
1194 entry->value.vtable_slot = vtable_slot;
1195 entry->next = imt_builder [imt_slot];
1196 if (imt_builder [imt_slot] != NULL) {
1197 entry->children = imt_builder [imt_slot]->children + 1;
1198 if (entry->children == 1) {
1199 mono_stats.imt_slots_with_collisions++;
1200 *imt_collisions_bitmap |= (1 << imt_slot);
1203 entry->children = 0;
1204 mono_stats.imt_used_slots++;
1206 imt_builder [imt_slot] = entry;
1209 char *method_name = mono_method_full_name (method, TRUE);
1210 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1211 method, method_name, imt_slot, vtable_slot, entry->children);
1212 g_free (method_name);
1219 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1221 MonoMethod *method = e->key;
1222 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1226 method->klass->name_space,
1227 method->klass->name,
1230 printf (" * %s: NULL\n", message);
1236 compare_imt_builder_entries (const void *p1, const void *p2) {
1237 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1238 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1240 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1244 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1246 MONO_REQ_GC_NEUTRAL_MODE;
1248 int count = end - start;
1249 int chunk_start = out_array->len;
1252 for (i = start; i < end; ++i) {
1253 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1254 item->key = sorted_array [i]->key;
1255 item->value = sorted_array [i]->value;
1256 item->has_target_code = sorted_array [i]->has_target_code;
1257 item->is_equals = TRUE;
1259 item->check_target_idx = out_array->len + 1;
1261 item->check_target_idx = 0;
1262 g_ptr_array_add (out_array, item);
1265 int middle = start + count / 2;
1266 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1268 item->key = sorted_array [middle]->key;
1269 item->is_equals = FALSE;
1270 g_ptr_array_add (out_array, item);
1271 imt_emit_ir (sorted_array, start, middle, out_array);
1272 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1278 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1279 MONO_REQ_GC_NEUTRAL_MODE;
1281 int number_of_entries = entries->children + 1;
1282 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1283 GPtrArray *result = g_ptr_array_new ();
1284 MonoImtBuilderEntry *current_entry;
1287 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1288 sorted_array [i] = current_entry;
1290 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1292 /*for (i = 0; i < number_of_entries; i++) {
1293 print_imt_entry (" sorted array:", sorted_array [i], i);
1296 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1298 free (sorted_array);
1303 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1305 MONO_REQ_GC_NEUTRAL_MODE;
1307 if (imt_builder_entry != NULL) {
1308 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1309 /* No collision, return the vtable slot contents */
1310 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1312 /* Collision, build the thunk */
1313 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1316 result = imt_thunk_builder (vtable, domain,
1317 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1318 for (i = 0; i < imt_ir->len; ++i)
1319 g_free (g_ptr_array_index (imt_ir, i));
1320 g_ptr_array_free (imt_ir, TRUE);
1332 static MonoImtBuilderEntry*
1333 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1336 * LOCKING: requires the loader and domain locks.
1340 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1342 MONO_REQ_GC_NEUTRAL_MODE;
1346 guint32 imt_collisions_bitmap = 0;
1347 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1348 int method_count = 0;
1349 gboolean record_method_count_for_max_collisions = FALSE;
1350 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1353 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1355 for (i = 0; i < klass->interface_offsets_count; ++i) {
1356 MonoClass *iface = klass->interfaces_packed [i];
1357 int interface_offset = klass->interface_offsets_packed [i];
1358 int method_slot_in_interface, vt_slot;
1360 if (mono_class_has_variant_generic_params (iface))
1361 has_variant_iface = TRUE;
1363 mono_class_setup_methods (iface);
1364 vt_slot = interface_offset;
1365 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1368 if (slot_num >= 0 && iface->is_inflated) {
1370 * The imt slot of the method is the same as for its declaring method,
1371 * see the comment in mono_method_get_imt_slot (), so we can
1372 * avoid inflating methods which will be discarded by
1373 * add_imt_builder_entry anyway.
1375 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1376 if (mono_method_get_imt_slot (method) != slot_num) {
1381 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1382 if (method->is_generic) {
1383 has_generic_virtual = TRUE;
1388 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1389 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1394 if (extra_interfaces) {
1395 int interface_offset = klass->vtable_size;
1397 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1398 MonoClass* iface = (MonoClass *)list_item->data;
1399 int method_slot_in_interface;
1400 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1401 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1403 if (method->is_generic)
1404 has_generic_virtual = TRUE;
1405 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1407 interface_offset += iface->method.count;
1410 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1411 /* overwrite the imt slot only if we're building all the entries or if
1412 * we're building this specific one
1414 if (slot_num < 0 || i == slot_num) {
1415 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1418 if (imt_builder [i]) {
1419 MonoImtBuilderEntry *entry;
1421 /* Link entries with imt_builder [i] */
1422 for (entry = entries; entry->next; entry = entry->next) {
1424 MonoMethod *method = (MonoMethod*)entry->key;
1425 char *method_name = mono_method_full_name (method, TRUE);
1426 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1427 g_free (method_name);
1430 entry->next = imt_builder [i];
1431 entries->children += imt_builder [i]->children + 1;
1433 imt_builder [i] = entries;
1436 if (has_generic_virtual || has_variant_iface) {
1438 * There might be collisions later when the the thunk is expanded.
1440 imt_collisions_bitmap |= (1 << i);
1443 * The IMT thunk might be called with an instance of one of the
1444 * generic virtual methods, so has to fallback to the IMT trampoline.
1446 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1448 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1451 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1455 if (imt_builder [i] != NULL) {
1456 int methods_in_slot = imt_builder [i]->children + 1;
1457 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1458 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1459 record_method_count_for_max_collisions = TRUE;
1461 method_count += methods_in_slot;
1465 mono_stats.imt_number_of_methods += method_count;
1466 if (record_method_count_for_max_collisions) {
1467 mono_stats.imt_method_count_when_max_collisions = method_count;
1470 for (i = 0; i < MONO_IMT_SIZE; i++) {
1471 MonoImtBuilderEntry* entry = imt_builder [i];
1472 while (entry != NULL) {
1473 MonoImtBuilderEntry* next = entry->next;
1479 /* we OR the bitmap since we may build just a single imt slot at a time */
1480 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1484 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1485 MONO_REQ_GC_NEUTRAL_MODE;
1487 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1491 * mono_vtable_build_imt_slot:
1492 * @vtable: virtual object table struct
1493 * @imt_slot: slot in the IMT table
1495 * Fill the given @imt_slot in the IMT table of @vtable with
1496 * a trampoline or a thunk for the case of collisions.
1497 * This is part of the internal mono API.
1499 * LOCKING: Take the domain lock.
1502 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1504 MONO_REQ_GC_NEUTRAL_MODE;
1506 gpointer *imt = (gpointer*)vtable;
1507 imt -= MONO_IMT_SIZE;
1508 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1510 /* no support for extra interfaces: the proxy objects will need
1511 * to build the complete IMT
1512 * Update and heck needs to ahppen inside the proper domain lock, as all
1513 * the changes made to a MonoVTable.
1515 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1516 mono_domain_lock (vtable->domain);
1517 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1518 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1519 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1520 mono_domain_unlock (vtable->domain);
1521 mono_loader_unlock ();
1526 * The first two free list entries both belong to the wait list: The
1527 * first entry is the pointer to the head of the list and the second
1528 * entry points to the last element. That way appending and removing
1529 * the first element are both O(1) operations.
1531 #ifdef MONO_SMALL_CONFIG
1532 #define NUM_FREE_LISTS 6
1534 #define NUM_FREE_LISTS 12
1536 #define FIRST_FREE_LIST_SIZE 64
1537 #define MAX_WAIT_LENGTH 50
1538 #define THUNK_THRESHOLD 10
1541 * LOCKING: The domain lock must be held.
1544 init_thunk_free_lists (MonoDomain *domain)
1546 MONO_REQ_GC_NEUTRAL_MODE;
1548 if (domain->thunk_free_lists)
1550 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1554 list_index_for_size (int item_size)
1557 int size = FIRST_FREE_LIST_SIZE;
1559 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1568 * mono_method_alloc_generic_virtual_thunk:
1570 * @size: size in bytes
1572 * Allocs size bytes to be used for the code of a generic virtual
1573 * thunk. It's either allocated from the domain's code manager or
1574 * reused from a previously invalidated piece.
1576 * LOCKING: The domain lock must be held.
1579 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1581 MONO_REQ_GC_NEUTRAL_MODE;
1583 static gboolean inited = FALSE;
1584 static int generic_virtual_thunks_size = 0;
1588 MonoThunkFreeList **l;
1590 init_thunk_free_lists (domain);
1592 size += sizeof (guint32);
1593 if (size < sizeof (MonoThunkFreeList))
1594 size = sizeof (MonoThunkFreeList);
1596 i = list_index_for_size (size);
1597 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1598 if ((*l)->size >= size) {
1599 MonoThunkFreeList *item = *l;
1601 return ((guint32*)item) + 1;
1605 /* no suitable item found - search lists of larger sizes */
1606 while (++i < NUM_FREE_LISTS) {
1607 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1610 g_assert (item->size > size);
1611 domain->thunk_free_lists [i] = item->next;
1612 return ((guint32*)item) + 1;
1615 /* still nothing found - allocate it */
1617 mono_counters_register ("Generic virtual thunk bytes",
1618 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1621 generic_virtual_thunks_size += size;
1623 p = (guint32 *)mono_domain_code_reserve (domain, size);
1626 mono_domain_lock (domain);
1627 if (!domain->generic_virtual_thunks)
1628 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1629 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1630 mono_domain_unlock (domain);
1636 * LOCKING: The domain lock must be held.
1639 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1641 MONO_REQ_GC_NEUTRAL_MODE;
1643 guint32 *p = (guint32 *)code;
1644 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1645 gboolean found = FALSE;
1647 mono_domain_lock (domain);
1648 if (!domain->generic_virtual_thunks)
1649 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1650 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1652 mono_domain_unlock (domain);
1655 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1657 init_thunk_free_lists (domain);
1659 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1660 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1661 int length = item->length;
1664 /* unlink the first item from the wait list */
1665 domain->thunk_free_lists [0] = item->next;
1666 domain->thunk_free_lists [0]->length = length - 1;
1668 i = list_index_for_size (item->size);
1670 /* put it in the free list */
1671 item->next = domain->thunk_free_lists [i];
1672 domain->thunk_free_lists [i] = item;
1676 if (domain->thunk_free_lists [1]) {
1677 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1678 domain->thunk_free_lists [0]->length++;
1680 g_assert (!domain->thunk_free_lists [0]);
1682 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1683 domain->thunk_free_lists [0]->length = 1;
1687 typedef struct _GenericVirtualCase {
1691 struct _GenericVirtualCase *next;
1692 } GenericVirtualCase;
1695 * get_generic_virtual_entries:
1697 * Return IMT entries for the generic virtual method instances and
1698 * variant interface methods for vtable slot
1701 static MonoImtBuilderEntry*
1702 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1704 MONO_REQ_GC_NEUTRAL_MODE;
1706 GenericVirtualCase *list;
1707 MonoImtBuilderEntry *entries;
1709 mono_domain_lock (domain);
1710 if (!domain->generic_virtual_cases)
1711 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1713 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1716 for (; list; list = list->next) {
1717 MonoImtBuilderEntry *entry;
1719 if (list->count < THUNK_THRESHOLD)
1722 entry = g_new0 (MonoImtBuilderEntry, 1);
1723 entry->key = list->method;
1724 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1725 entry->has_target_code = 1;
1727 entry->children = entries->children + 1;
1728 entry->next = entries;
1732 mono_domain_unlock (domain);
1734 /* FIXME: Leaking memory ? */
1739 * mono_method_add_generic_virtual_invocation:
1741 * @vtable_slot: pointer to the vtable slot
1742 * @method: the inflated generic virtual method
1743 * @code: the method's code
1745 * Registers a call via unmanaged code to a generic virtual method
1746 * instantiation or variant interface method. If the number of calls reaches a threshold
1747 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1748 * virtual method thunk.
1751 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1752 gpointer *vtable_slot,
1753 MonoMethod *method, gpointer code)
1755 MONO_REQ_GC_NEUTRAL_MODE;
1757 static gboolean inited = FALSE;
1758 static int num_added = 0;
1760 GenericVirtualCase *gvc, *list;
1761 MonoImtBuilderEntry *entries;
1765 mono_domain_lock (domain);
1766 if (!domain->generic_virtual_cases)
1767 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1769 /* Check whether the case was already added */
1770 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1773 if (gvc->method == method)
1778 /* If not found, make a new one */
1780 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1781 gvc->method = method;
1784 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1786 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1789 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1795 if (++gvc->count == THUNK_THRESHOLD) {
1796 gpointer *old_thunk = (void **)*vtable_slot;
1797 gpointer vtable_trampoline = NULL;
1798 gpointer imt_trampoline = NULL;
1800 if ((gpointer)vtable_slot < (gpointer)vtable) {
1801 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1802 int imt_slot = MONO_IMT_SIZE + displacement;
1804 /* Force the rebuild of the thunk at the next call */
1805 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1806 *vtable_slot = imt_trampoline;
1808 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1810 entries = get_generic_virtual_entries (domain, vtable_slot);
1812 sorted = imt_sort_slot_entries (entries);
1814 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1818 MonoImtBuilderEntry *next = entries->next;
1823 for (i = 0; i < sorted->len; ++i)
1824 g_free (g_ptr_array_index (sorted, i));
1825 g_ptr_array_free (sorted, TRUE);
1828 #ifndef __native_client__
1829 /* We don't re-use any thunks as there is a lot of overhead */
1830 /* to deleting and re-using code in Native Client. */
1831 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1832 invalidate_generic_virtual_thunk (domain, old_thunk);
1836 mono_domain_unlock (domain);
1839 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1842 * mono_class_vtable:
1843 * @domain: the application domain
1844 * @class: the class to initialize
1846 * VTables are domain specific because we create domain specific code, and
1847 * they contain the domain specific static class data.
1848 * On failure, NULL is returned, and class->exception_type is set.
1851 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1854 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1855 mono_error_cleanup (&error);
1860 * mono_class_vtable_full:
1861 * @domain: the application domain
1862 * @class: the class to initialize
1863 * @error set on failure.
1865 * VTables are domain specific because we create domain specific code, and
1866 * they contain the domain specific static class data.
1869 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1871 MONO_REQ_GC_UNSAFE_MODE;
1873 MonoClassRuntimeInfo *runtime_info;
1875 mono_error_init (error);
1879 if (mono_class_has_failure (klass)) {
1880 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1884 /* this check can be inlined in jitted code, too */
1885 runtime_info = klass->runtime_info;
1886 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1887 return runtime_info->domain_vtables [domain->domain_id];
1888 return mono_class_create_runtime_vtable (domain, klass, error);
1892 * mono_class_try_get_vtable:
1893 * @domain: the application domain
1894 * @class: the class to initialize
1896 * This function tries to get the associated vtable from @class if
1897 * it was already created.
1900 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1902 MONO_REQ_GC_NEUTRAL_MODE;
1904 MonoClassRuntimeInfo *runtime_info;
1908 runtime_info = klass->runtime_info;
1909 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1910 return runtime_info->domain_vtables [domain->domain_id];
1915 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1917 MONO_REQ_GC_NEUTRAL_MODE;
1919 size_t alloc_offset;
1922 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1923 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1924 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1926 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1927 g_assert ((imt_table_bytes & 7) == 4);
1934 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1938 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1940 MONO_REQ_GC_UNSAFE_MODE;
1943 MonoClassRuntimeInfo *runtime_info, *old_info;
1944 MonoClassField *field;
1946 int i, vtable_slots;
1947 size_t imt_table_bytes;
1949 guint32 vtable_size, class_size;
1951 gpointer *interface_offsets;
1953 mono_error_init (error);
1955 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1956 mono_domain_lock (domain);
1957 runtime_info = klass->runtime_info;
1958 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1959 mono_domain_unlock (domain);
1960 mono_loader_unlock ();
1961 return runtime_info->domain_vtables [domain->domain_id];
1963 if (!klass->inited || mono_class_has_failure (klass)) {
1964 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1965 mono_domain_unlock (domain);
1966 mono_loader_unlock ();
1967 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1972 /* Array types require that their element type be valid*/
1973 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1974 MonoClass *element_class = klass->element_class;
1975 if (!element_class->inited)
1976 mono_class_init (element_class);
1978 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1979 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1980 mono_class_setup_vtable (element_class);
1982 if (mono_class_has_failure (element_class)) {
1983 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1984 if (!mono_class_has_failure (klass))
1985 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1986 mono_domain_unlock (domain);
1987 mono_loader_unlock ();
1988 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1994 * For some classes, mono_class_init () already computed klass->vtable_size, and
1995 * that is all that is needed because of the vtable trampolines.
1997 if (!klass->vtable_size)
1998 mono_class_setup_vtable (klass);
2000 if (klass->generic_class && !klass->vtable)
2001 mono_class_check_vtable_constraints (klass, NULL);
2003 /* Initialize klass->has_finalize */
2004 mono_class_has_finalizer (klass);
2006 if (mono_class_has_failure (klass)) {
2007 mono_domain_unlock (domain);
2008 mono_loader_unlock ();
2009 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2013 vtable_slots = klass->vtable_size;
2014 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2015 class_size = mono_class_data_size (klass);
2019 if (klass->interface_offsets_count) {
2020 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2021 mono_stats.imt_number_of_tables++;
2022 mono_stats.imt_tables_size += imt_table_bytes;
2024 imt_table_bytes = 0;
2027 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2029 mono_stats.used_class_count++;
2030 mono_stats.class_vtable_size += vtable_size;
2032 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2033 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2034 g_assert (!((gsize)vt & 7));
2037 vt->rank = klass->rank;
2038 vt->domain = domain;
2040 mono_class_compute_gc_descriptor (klass);
2042 * We can't use typed allocation in the non-root domains, since the
2043 * collector needs the GC descriptor stored in the vtable even after
2044 * the mempool containing the vtable is destroyed when the domain is
2045 * unloaded. An alternative might be to allocate vtables in the GC
2046 * heap, but this does not seem to work (it leads to crashes inside
2047 * libgc). If that approach is tried, two gc descriptors need to be
2048 * allocated for each class: one for the root domain, and one for all
2049 * other domains. The second descriptor should contain a bit for the
2050 * vtable field in MonoObject, since we can no longer assume the
2051 * vtable is reachable by other roots after the appdomain is unloaded.
2053 #ifdef HAVE_BOEHM_GC
2054 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2055 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2058 vt->gc_descr = klass->gc_descr;
2060 gc_bits = mono_gc_get_vtable_bits (klass);
2061 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2063 vt->gc_bits = gc_bits;
2066 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2067 if (klass->has_static_refs) {
2068 MonoGCDescriptor statics_gc_descr;
2070 gsize default_bitmap [4] = {0};
2073 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2074 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2075 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2076 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2077 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2078 if (bitmap != default_bitmap)
2081 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2083 vt->has_static_fields = TRUE;
2084 mono_stats.class_static_data_size += class_size;
2088 while ((field = mono_class_get_fields (klass, &iter))) {
2089 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2091 if (mono_field_is_deleted (field))
2093 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2094 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2095 if (special_static != SPECIAL_STATIC_NONE) {
2096 guint32 size, offset;
2098 gsize default_bitmap [4] = {0};
2103 if (mono_type_is_reference (field->type)) {
2104 default_bitmap [0] = 1;
2106 bitmap = default_bitmap;
2107 } else if (mono_type_is_struct (field->type)) {
2108 fclass = mono_class_from_mono_type (field->type);
2109 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2110 numbits = max_set + 1;
2112 default_bitmap [0] = 0;
2114 bitmap = default_bitmap;
2116 size = mono_type_size (field->type, &align);
2117 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2118 if (!domain->special_static_fields)
2119 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2120 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2121 if (bitmap != default_bitmap)
2124 * This marks the field as special static to speed up the
2125 * checks in mono_field_static_get/set_value ().
2131 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2132 MonoClass *fklass = mono_class_from_mono_type (field->type);
2133 const char *data = mono_field_get_data (field);
2135 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2136 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2137 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2140 if (fklass->valuetype) {
2141 memcpy (t, data, mono_class_value_size (fklass, NULL));
2143 /* it's a pointer type: add check */
2144 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2151 vt->max_interface_id = klass->max_interface_id;
2152 vt->interface_bitmap = klass->interface_bitmap;
2154 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2155 // class->name, klass->interface_offsets_count);
2157 /* Initialize vtable */
2158 if (callbacks.get_vtable_trampoline) {
2159 // This also covers the AOT case
2160 for (i = 0; i < klass->vtable_size; ++i) {
2161 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2164 mono_class_setup_vtable (klass);
2166 for (i = 0; i < klass->vtable_size; ++i) {
2169 if ((cm = klass->vtable [i]))
2170 vt->vtable [i] = arch_create_jit_trampoline (cm);
2174 if (imt_table_bytes) {
2175 /* Now that the vtable is full, we can actually fill up the IMT */
2176 for (i = 0; i < MONO_IMT_SIZE; ++i)
2177 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2181 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2182 * re-acquire them and check if another thread has created the vtable in the meantime.
2184 /* Special case System.MonoType to avoid infinite recursion */
2185 if (klass != mono_defaults.monotype_class) {
2186 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2187 if (!is_ok (error)) {
2188 mono_domain_unlock (domain);
2189 mono_loader_unlock ();
2193 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2194 /* This is unregistered in
2195 unregister_vtable_reflection_type() in
2197 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2200 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2202 /* class_vtable_array keeps an array of created vtables
2204 g_ptr_array_add (domain->class_vtable_array, vt);
2205 /* klass->runtime_info is protected by the loader lock, both when
2206 * it it enlarged and when it is stored info.
2210 * Store the vtable in klass->runtime_info.
2211 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2213 mono_memory_barrier ();
2215 old_info = klass->runtime_info;
2216 if (old_info && old_info->max_domain >= domain->domain_id) {
2217 /* someone already created a large enough runtime info */
2218 old_info->domain_vtables [domain->domain_id] = vt;
2220 int new_size = domain->domain_id;
2222 new_size = MAX (new_size, old_info->max_domain);
2224 /* make the new size a power of two */
2226 while (new_size > i)
2229 /* this is a bounded memory retention issue: may want to
2230 * handle it differently when we'll have a rcu-like system.
2232 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2233 runtime_info->max_domain = new_size - 1;
2234 /* copy the stuff from the older info */
2236 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2238 runtime_info->domain_vtables [domain->domain_id] = vt;
2240 mono_memory_barrier ();
2241 klass->runtime_info = runtime_info;
2244 if (klass == mono_defaults.monotype_class) {
2245 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2246 if (!is_ok (error)) {
2247 mono_domain_unlock (domain);
2248 mono_loader_unlock ();
2252 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2253 /* This is unregistered in
2254 unregister_vtable_reflection_type() in
2256 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2259 mono_domain_unlock (domain);
2260 mono_loader_unlock ();
2262 /* make sure the parent is initialized */
2263 /*FIXME shouldn't this fail the current type?*/
2265 mono_class_vtable_full (domain, klass->parent, error);
2270 #ifndef DISABLE_REMOTING
2272 * mono_class_proxy_vtable:
2273 * @domain: the application domain
2274 * @remove_class: the remote class
2276 * Creates a vtable for transparent proxies. It is basically
2277 * a copy of the real vtable of the class wrapped in @remote_class,
2278 * but all function pointers invoke the remoting functions, and
2279 * vtable->klass points to the transparent proxy class, and not to @class.
2282 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2284 MONO_REQ_GC_UNSAFE_MODE;
2287 MonoVTable *vt, *pvt;
2288 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2290 GSList *extra_interfaces = NULL;
2291 MonoClass *klass = remote_class->proxy_class;
2292 gpointer *interface_offsets;
2295 size_t imt_table_bytes;
2297 #ifdef COMPRESSED_INTERFACE_BITMAP
2301 vt = mono_class_vtable (domain, klass);
2302 g_assert (vt); /*FIXME property handle failure*/
2303 max_interface_id = vt->max_interface_id;
2305 /* Calculate vtable space for extra interfaces */
2306 for (j = 0; j < remote_class->interface_count; j++) {
2307 MonoClass* iclass = remote_class->interfaces[j];
2311 /*FIXME test for interfaces with variant generic arguments*/
2312 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2313 continue; /* interface implemented by the class */
2314 if (g_slist_find (extra_interfaces, iclass))
2317 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2319 method_count = mono_class_num_methods (iclass);
2321 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2322 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2324 for (i = 0; i < ifaces->len; ++i) {
2325 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2326 /*FIXME test for interfaces with variant generic arguments*/
2327 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2328 continue; /* interface implemented by the class */
2329 if (g_slist_find (extra_interfaces, ic))
2331 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2332 method_count += mono_class_num_methods (ic);
2334 g_ptr_array_free (ifaces, TRUE);
2337 extra_interface_vtsize += method_count * sizeof (gpointer);
2338 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2341 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2342 mono_stats.imt_number_of_tables++;
2343 mono_stats.imt_tables_size += imt_table_bytes;
2345 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2347 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2349 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2350 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2351 g_assert (!((gsize)pvt & 7));
2353 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2355 pvt->klass = mono_defaults.transparent_proxy_class;
2356 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2357 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2359 /* initialize vtable */
2360 mono_class_setup_vtable (klass);
2361 for (i = 0; i < klass->vtable_size; ++i) {
2364 if ((cm = klass->vtable [i]))
2365 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2367 pvt->vtable [i] = NULL;
2370 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2371 /* create trampolines for abstract methods */
2372 for (k = klass; k; k = k->parent) {
2374 gpointer iter = NULL;
2375 while ((m = mono_class_get_methods (k, &iter)))
2376 if (!pvt->vtable [m->slot])
2377 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2381 pvt->max_interface_id = max_interface_id;
2382 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2383 #ifdef COMPRESSED_INTERFACE_BITMAP
2384 bitmap = (uint8_t *)g_malloc0 (bsize);
2386 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2389 for (i = 0; i < klass->interface_offsets_count; ++i) {
2390 int interface_id = klass->interfaces_packed [i]->interface_id;
2391 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2394 if (extra_interfaces) {
2395 int slot = klass->vtable_size;
2401 /* Create trampolines for the methods of the interfaces */
2402 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2403 interf = (MonoClass *)list_item->data;
2405 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2409 while ((cm = mono_class_get_methods (interf, &iter)))
2410 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2412 slot += mono_class_num_methods (interf);
2416 /* Now that the vtable is full, we can actually fill up the IMT */
2417 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2418 if (extra_interfaces) {
2419 g_slist_free (extra_interfaces);
2422 #ifdef COMPRESSED_INTERFACE_BITMAP
2423 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2424 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2425 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2428 pvt->interface_bitmap = bitmap;
2433 #endif /* DISABLE_REMOTING */
2436 * mono_class_field_is_special_static:
2438 * Returns whether @field is a thread/context static field.
2441 mono_class_field_is_special_static (MonoClassField *field)
2443 MONO_REQ_GC_NEUTRAL_MODE
2445 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2447 if (mono_field_is_deleted (field))
2449 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2450 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2457 * mono_class_field_get_special_static_type:
2458 * @field: The MonoClassField describing the field.
2460 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2461 * SPECIAL_STATIC_NONE otherwise.
2464 mono_class_field_get_special_static_type (MonoClassField *field)
2466 MONO_REQ_GC_NEUTRAL_MODE
2468 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2469 return SPECIAL_STATIC_NONE;
2470 if (mono_field_is_deleted (field))
2471 return SPECIAL_STATIC_NONE;
2472 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2473 return field_is_special_static (field->parent, field);
2474 return SPECIAL_STATIC_NONE;
2478 * mono_class_has_special_static_fields:
2480 * Returns whenever @klass has any thread/context static fields.
2483 mono_class_has_special_static_fields (MonoClass *klass)
2485 MONO_REQ_GC_NEUTRAL_MODE
2487 MonoClassField *field;
2491 while ((field = mono_class_get_fields (klass, &iter))) {
2492 g_assert (field->parent == klass);
2493 if (mono_class_field_is_special_static (field))
2500 #ifndef DISABLE_REMOTING
2502 * create_remote_class_key:
2503 * Creates an array of pointers that can be used as a hash key for a remote class.
2504 * The first element of the array is the number of pointers.
2507 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2509 MONO_REQ_GC_NEUTRAL_MODE;
2514 if (remote_class == NULL) {
2515 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2516 key = (void **)g_malloc (sizeof(gpointer) * 3);
2517 key [0] = GINT_TO_POINTER (2);
2518 key [1] = mono_defaults.marshalbyrefobject_class;
2519 key [2] = extra_class;
2521 key = (void **)g_malloc (sizeof(gpointer) * 2);
2522 key [0] = GINT_TO_POINTER (1);
2523 key [1] = extra_class;
2526 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2527 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2528 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2529 key [1] = remote_class->proxy_class;
2531 // Keep the list of interfaces sorted
2532 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2533 if (extra_class && remote_class->interfaces [i] > extra_class) {
2534 key [j++] = extra_class;
2537 key [j] = remote_class->interfaces [i];
2540 key [j] = extra_class;
2542 // Replace the old class. The interface list is the same
2543 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2544 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2545 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2546 for (i = 0; i < remote_class->interface_count; i++)
2547 key [2 + i] = remote_class->interfaces [i];
2555 * copy_remote_class_key:
2557 * Make a copy of KEY in the domain and return the copy.
2560 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2562 MONO_REQ_GC_NEUTRAL_MODE
2564 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2565 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2567 memcpy (mp_key, key, key_size);
2573 * mono_remote_class:
2574 * @domain: the application domain
2575 * @class_name: name of the remote class
2577 * Creates and initializes a MonoRemoteClass object for a remote type.
2579 * Can raise an exception on failure.
2582 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2584 MONO_REQ_GC_UNSAFE_MODE;
2587 MonoRemoteClass *rc;
2588 gpointer* key, *mp_key;
2591 key = create_remote_class_key (NULL, proxy_class);
2593 mono_domain_lock (domain);
2594 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2598 mono_domain_unlock (domain);
2602 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2603 if (!mono_error_ok (&error)) {
2605 mono_domain_unlock (domain);
2606 mono_error_raise_exception (&error);
2609 mp_key = copy_remote_class_key (domain, key);
2613 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2614 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2615 rc->interface_count = 1;
2616 rc->interfaces [0] = proxy_class;
2617 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2619 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2620 rc->interface_count = 0;
2621 rc->proxy_class = proxy_class;
2624 rc->default_vtable = NULL;
2625 rc->xdomain_vtable = NULL;
2626 rc->proxy_class_name = name;
2627 #ifndef DISABLE_PERFCOUNTERS
2628 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2631 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2633 mono_domain_unlock (domain);
2638 * clone_remote_class:
2639 * Creates a copy of the remote_class, adding the provided class or interface
2641 static MonoRemoteClass*
2642 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2644 MONO_REQ_GC_NEUTRAL_MODE;
2646 MonoRemoteClass *rc;
2647 gpointer* key, *mp_key;
2649 key = create_remote_class_key (remote_class, extra_class);
2650 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2656 mp_key = copy_remote_class_key (domain, key);
2660 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2662 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2663 rc->proxy_class = remote_class->proxy_class;
2664 rc->interface_count = remote_class->interface_count + 1;
2666 // Keep the list of interfaces sorted, since the hash key of
2667 // the remote class depends on this
2668 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2669 if (remote_class->interfaces [i] > extra_class && i == j)
2670 rc->interfaces [j++] = extra_class;
2671 rc->interfaces [j] = remote_class->interfaces [i];
2674 rc->interfaces [j] = extra_class;
2676 // Replace the old class. The interface array is the same
2677 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2678 rc->proxy_class = extra_class;
2679 rc->interface_count = remote_class->interface_count;
2680 if (rc->interface_count > 0)
2681 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2684 rc->default_vtable = NULL;
2685 rc->xdomain_vtable = NULL;
2686 rc->proxy_class_name = remote_class->proxy_class_name;
2688 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2694 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2696 MONO_REQ_GC_UNSAFE_MODE;
2698 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2699 mono_domain_lock (domain);
2700 if (rp->target_domain_id != -1) {
2701 if (remote_class->xdomain_vtable == NULL)
2702 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2703 mono_domain_unlock (domain);
2704 mono_loader_unlock ();
2705 return remote_class->xdomain_vtable;
2707 if (remote_class->default_vtable == NULL) {
2710 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2711 klass = mono_class_from_mono_type (type);
2713 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)))
2714 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2717 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2720 mono_domain_unlock (domain);
2721 mono_loader_unlock ();
2722 return remote_class->default_vtable;
2726 * mono_upgrade_remote_class:
2727 * @domain: the application domain
2728 * @tproxy: the proxy whose remote class has to be upgraded.
2729 * @klass: class to which the remote class can be casted.
2731 * Updates the vtable of the remote class by adding the necessary method slots
2732 * and interface offsets so it can be safely casted to klass. klass can be a
2733 * class or an interface.
2736 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2738 MONO_REQ_GC_UNSAFE_MODE;
2740 MonoTransparentProxy *tproxy;
2741 MonoRemoteClass *remote_class;
2742 gboolean redo_vtable;
2744 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2745 mono_domain_lock (domain);
2747 tproxy = (MonoTransparentProxy*) proxy_object;
2748 remote_class = tproxy->remote_class;
2750 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2753 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2754 if (remote_class->interfaces [i] == klass)
2755 redo_vtable = FALSE;
2758 redo_vtable = (remote_class->proxy_class != klass);
2762 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2763 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2766 mono_domain_unlock (domain);
2767 mono_loader_unlock ();
2769 #endif /* DISABLE_REMOTING */
2773 * mono_object_get_virtual_method:
2774 * @obj: object to operate on.
2777 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2778 * the instance of a callvirt of method.
2781 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2783 MONO_REQ_GC_UNSAFE_MODE;
2786 MonoMethod **vtable;
2787 gboolean is_proxy = FALSE;
2788 MonoMethod *res = NULL;
2790 klass = mono_object_class (obj);
2791 #ifndef DISABLE_REMOTING
2792 if (klass == mono_defaults.transparent_proxy_class) {
2793 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2798 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2801 mono_class_setup_vtable (klass);
2802 vtable = klass->vtable;
2804 if (method->slot == -1) {
2805 /* method->slot might not be set for instances of generic methods */
2806 if (method->is_inflated) {
2807 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2808 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2811 g_assert_not_reached ();
2815 /* check method->slot is a valid index: perform isinstance? */
2816 if (method->slot != -1) {
2817 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2819 gboolean variance_used = FALSE;
2820 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2821 g_assert (iface_offset > 0);
2822 res = vtable [iface_offset + method->slot];
2825 res = vtable [method->slot];
2829 #ifndef DISABLE_REMOTING
2831 /* It may be an interface, abstract class method or generic method */
2832 if (!res || mono_method_signature (res)->generic_param_count)
2835 /* generic methods demand invoke_with_check */
2836 if (mono_method_signature (res)->generic_param_count)
2837 res = mono_marshal_get_remoting_invoke_with_check (res);
2840 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2841 res = mono_cominterop_get_invoke (res);
2844 res = mono_marshal_get_remoting_invoke (res);
2849 if (method->is_inflated) {
2851 /* Have to inflate the result */
2852 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2853 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2863 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2865 MONO_REQ_GC_UNSAFE_MODE;
2867 MonoObject *result = NULL;
2869 g_assert (callbacks.runtime_invoke);
2871 mono_error_init (error);
2873 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2874 mono_profiler_method_start_invoke (method);
2876 MONO_PREPARE_RESET_BLOCKING;
2878 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2880 MONO_FINISH_RESET_BLOCKING;
2882 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2883 mono_profiler_method_end_invoke (method);
2885 if (!mono_error_ok (error))
2892 * mono_runtime_invoke:
2893 * @method: method to invoke
2894 * @obJ: object instance
2895 * @params: arguments to the method
2896 * @exc: exception information.
2898 * Invokes the method represented by @method on the object @obj.
2900 * obj is the 'this' pointer, it should be NULL for static
2901 * methods, a MonoObject* for object instances and a pointer to
2902 * the value type for value types.
2904 * The params array contains the arguments to the method with the
2905 * same convention: MonoObject* pointers for object instances and
2906 * pointers to the value type otherwise.
2908 * From unmanaged code you'll usually use the
2909 * mono_runtime_invoke() variant.
2911 * Note that this function doesn't handle virtual methods for
2912 * you, it will exec the exact method you pass: we still need to
2913 * expose a function to lookup the derived class implementation
2914 * of a virtual method (there are examples of this in the code,
2917 * You can pass NULL as the exc argument if you don't want to
2918 * catch exceptions, otherwise, *exc will be set to the exception
2919 * thrown, if any. if an exception is thrown, you can't use the
2920 * MonoObject* result from the function.
2922 * If the method returns a value type, it is boxed in an object
2926 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2931 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2932 if (*exc == NULL && !mono_error_ok(&error)) {
2933 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2935 mono_error_cleanup (&error);
2937 res = mono_runtime_invoke_checked (method, obj, params, &error);
2938 mono_error_raise_exception (&error);
2944 * mono_runtime_try_invoke:
2945 * @method: method to invoke
2946 * @obJ: object instance
2947 * @params: arguments to the method
2948 * @exc: exception information.
2949 * @error: set on error
2951 * Invokes the method represented by @method on the object @obj.
2953 * obj is the 'this' pointer, it should be NULL for static
2954 * methods, a MonoObject* for object instances and a pointer to
2955 * the value type for value types.
2957 * The params array contains the arguments to the method with the
2958 * same convention: MonoObject* pointers for object instances and
2959 * pointers to the value type otherwise.
2961 * From unmanaged code you'll usually use the
2962 * mono_runtime_invoke() variant.
2964 * Note that this function doesn't handle virtual methods for
2965 * you, it will exec the exact method you pass: we still need to
2966 * expose a function to lookup the derived class implementation
2967 * of a virtual method (there are examples of this in the code,
2970 * For this function, you must not pass NULL as the exc argument if
2971 * you don't want to catch exceptions, use
2972 * mono_runtime_invoke_checked(). If an exception is thrown, you
2973 * can't use the MonoObject* result from the function.
2975 * If this method cannot be invoked, @error will be set and @exc and
2976 * the return value must not be used.
2978 * If the method returns a value type, it is boxed in an object
2982 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2984 MONO_REQ_GC_UNSAFE_MODE;
2986 g_assert (exc != NULL);
2988 if (mono_runtime_get_no_exec ())
2989 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2991 return do_runtime_invoke (method, obj, params, exc, error);
2995 * mono_runtime_invoke_checked:
2996 * @method: method to invoke
2997 * @obJ: object instance
2998 * @params: arguments to the method
2999 * @error: set on error
3001 * Invokes the method represented by @method on the object @obj.
3003 * obj is the 'this' pointer, it should be NULL for static
3004 * methods, a MonoObject* for object instances and a pointer to
3005 * the value type for value types.
3007 * The params array contains the arguments to the method with the
3008 * same convention: MonoObject* pointers for object instances and
3009 * pointers to the value type otherwise.
3011 * From unmanaged code you'll usually use the
3012 * mono_runtime_invoke() variant.
3014 * Note that this function doesn't handle virtual methods for
3015 * you, it will exec the exact method you pass: we still need to
3016 * expose a function to lookup the derived class implementation
3017 * of a virtual method (there are examples of this in the code,
3020 * If an exception is thrown, you can't use the MonoObject* result
3021 * from the function.
3023 * If this method cannot be invoked, @error will be set. If the
3024 * method throws an exception (and we're in coop mode) the exception
3025 * will be set in @error.
3027 * If the method returns a value type, it is boxed in an object
3031 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3033 MONO_REQ_GC_UNSAFE_MODE;
3035 if (mono_runtime_get_no_exec ())
3036 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3038 return do_runtime_invoke (method, obj, params, NULL, error);
3042 * mono_method_get_unmanaged_thunk:
3043 * @method: method to generate a thunk for.
3045 * Returns an unmanaged->managed thunk that can be used to call
3046 * a managed method directly from C.
3048 * The thunk's C signature closely matches the managed signature:
3050 * C#: public bool Equals (object obj);
3051 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3052 * MonoObject*, MonoException**);
3054 * The 1st ("this") parameter must not be used with static methods:
3056 * C#: public static bool ReferenceEquals (object a, object b);
3057 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3060 * The last argument must be a non-null pointer of a MonoException* pointer.
3061 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3062 * exception has been thrown in managed code. Otherwise it will point
3063 * to the MonoException* caught by the thunk. In this case, the result of
3064 * the thunk is undefined:
3066 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3067 * MonoException *ex = NULL;
3068 * Equals func = mono_method_get_unmanaged_thunk (method);
3069 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3071 * // handle exception
3074 * The calling convention of the thunk matches the platform's default
3075 * convention. This means that under Windows, C declarations must
3076 * contain the __stdcall attribute:
3078 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3079 * MonoObject*, MonoException**);
3083 * Value type arguments and return values are treated as they were objects:
3085 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3086 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3088 * Arguments must be properly boxed upon trunk's invocation, while return
3089 * values must be unboxed.
3092 mono_method_get_unmanaged_thunk (MonoMethod *method)
3094 MONO_REQ_GC_NEUTRAL_MODE;
3095 MONO_REQ_API_ENTRYPOINT;
3099 MONO_PREPARE_RESET_BLOCKING;
3100 method = mono_marshal_get_thunk_invoke_wrapper (method);
3101 res = mono_compile_method (method);
3102 MONO_FINISH_RESET_BLOCKING;
3108 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3110 MONO_REQ_GC_UNSAFE_MODE;
3114 /* object fields cannot be byref, so we don't need a
3116 gpointer *p = (gpointer*)dest;
3123 case MONO_TYPE_BOOLEAN:
3125 case MONO_TYPE_U1: {
3126 guint8 *p = (guint8*)dest;
3127 *p = value ? *(guint8*)value : 0;
3132 case MONO_TYPE_CHAR: {
3133 guint16 *p = (guint16*)dest;
3134 *p = value ? *(guint16*)value : 0;
3137 #if SIZEOF_VOID_P == 4
3142 case MONO_TYPE_U4: {
3143 gint32 *p = (gint32*)dest;
3144 *p = value ? *(gint32*)value : 0;
3147 #if SIZEOF_VOID_P == 8
3152 case MONO_TYPE_U8: {
3153 gint64 *p = (gint64*)dest;
3154 *p = value ? *(gint64*)value : 0;
3157 case MONO_TYPE_R4: {
3158 float *p = (float*)dest;
3159 *p = value ? *(float*)value : 0;
3162 case MONO_TYPE_R8: {
3163 double *p = (double*)dest;
3164 *p = value ? *(double*)value : 0;
3167 case MONO_TYPE_STRING:
3168 case MONO_TYPE_SZARRAY:
3169 case MONO_TYPE_CLASS:
3170 case MONO_TYPE_OBJECT:
3171 case MONO_TYPE_ARRAY:
3172 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3174 case MONO_TYPE_FNPTR:
3175 case MONO_TYPE_PTR: {
3176 gpointer *p = (gpointer*)dest;
3177 *p = deref_pointer? *(gpointer*)value: value;
3180 case MONO_TYPE_VALUETYPE:
3181 /* note that 't' and 'type->type' can be different */
3182 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3183 t = mono_class_enum_basetype (type->data.klass)->type;
3186 MonoClass *klass = mono_class_from_mono_type (type);
3187 int size = mono_class_value_size (klass, NULL);
3189 mono_gc_bzero_atomic (dest, size);
3191 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3194 case MONO_TYPE_GENERICINST:
3195 t = type->data.generic_class->container_class->byval_arg.type;
3198 g_error ("got type %x", type->type);
3203 * mono_field_set_value:
3204 * @obj: Instance object
3205 * @field: MonoClassField describing the field to set
3206 * @value: The value to be set
3208 * Sets the value of the field described by @field in the object instance @obj
3209 * to the value passed in @value. This method should only be used for instance
3210 * fields. For static fields, use mono_field_static_set_value.
3212 * The value must be on the native format of the field type.
3215 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3217 MONO_REQ_GC_UNSAFE_MODE;
3221 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3223 dest = (char*)obj + field->offset;
3224 mono_copy_value (field->type, dest, value, FALSE);
3228 * mono_field_static_set_value:
3229 * @field: MonoClassField describing the field to set
3230 * @value: The value to be set
3232 * Sets the value of the static field described by @field
3233 * to the value passed in @value.
3235 * The value must be on the native format of the field type.
3238 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3240 MONO_REQ_GC_UNSAFE_MODE;
3244 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3245 /* you cant set a constant! */
3246 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3248 if (field->offset == -1) {
3249 /* Special static */
3252 mono_domain_lock (vt->domain);
3253 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3254 mono_domain_unlock (vt->domain);
3255 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3257 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3259 mono_copy_value (field->type, dest, value, FALSE);
3263 * mono_vtable_get_static_field_data:
3265 * Internal use function: return a pointer to the memory holding the static fields
3266 * for a class or NULL if there are no static fields.
3267 * This is exported only for use by the debugger.
3270 mono_vtable_get_static_field_data (MonoVTable *vt)
3272 MONO_REQ_GC_NEUTRAL_MODE
3274 if (!vt->has_static_fields)
3276 return vt->vtable [vt->klass->vtable_size];
3280 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3282 MONO_REQ_GC_UNSAFE_MODE;
3286 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3287 if (field->offset == -1) {
3288 /* Special static */
3291 mono_domain_lock (vt->domain);
3292 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3293 mono_domain_unlock (vt->domain);
3294 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3296 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3299 src = (guint8*)obj + field->offset;
3306 * mono_field_get_value:
3307 * @obj: Object instance
3308 * @field: MonoClassField describing the field to fetch information from
3309 * @value: pointer to the location where the value will be stored
3311 * Use this routine to get the value of the field @field in the object
3314 * The pointer provided by value must be of the field type, for reference
3315 * types this is a MonoObject*, for value types its the actual pointer to
3320 * mono_field_get_value (obj, int_field, &i);
3323 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3325 MONO_REQ_GC_UNSAFE_MODE;
3331 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3333 src = (char*)obj + field->offset;
3334 mono_copy_value (field->type, value, src, TRUE);
3338 * mono_field_get_value_object:
3339 * @domain: domain where the object will be created (if boxing)
3340 * @field: MonoClassField describing the field to fetch information from
3341 * @obj: The object instance for the field.
3343 * Returns: a new MonoObject with the value from the given field. If the
3344 * field represents a value type, the value is boxed.
3348 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3350 MONO_REQ_GC_UNSAFE_MODE;
3355 MonoVTable *vtable = NULL;
3357 gboolean is_static = FALSE;
3358 gboolean is_ref = FALSE;
3359 gboolean is_literal = FALSE;
3360 gboolean is_ptr = FALSE;
3361 MonoType *type = mono_field_get_type_checked (field, &error);
3363 if (!mono_error_ok (&error))
3364 mono_error_raise_exception (&error); /* FIXME don't raise here */
3366 switch (type->type) {
3367 case MONO_TYPE_STRING:
3368 case MONO_TYPE_OBJECT:
3369 case MONO_TYPE_CLASS:
3370 case MONO_TYPE_ARRAY:
3371 case MONO_TYPE_SZARRAY:
3376 case MONO_TYPE_BOOLEAN:
3379 case MONO_TYPE_CHAR:
3388 case MONO_TYPE_VALUETYPE:
3389 is_ref = type->byref;
3391 case MONO_TYPE_GENERICINST:
3392 is_ref = !mono_type_generic_inst_is_valuetype (type);
3398 g_error ("type 0x%x not handled in "
3399 "mono_field_get_value_object", type->type);
3403 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3406 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3410 vtable = mono_class_vtable_full (domain, field->parent, &error);
3411 mono_error_raise_exception (&error); /* FIXME don't raise here */
3413 if (!vtable->initialized) {
3414 mono_runtime_class_init_full (vtable, &error);
3415 mono_error_raise_exception (&error); /* FIXME don't raise here */
3424 get_default_field_value (domain, field, &o);
3425 } else if (is_static) {
3426 mono_field_static_get_value (vtable, field, &o);
3428 mono_field_get_value (obj, field, &o);
3434 static MonoMethod *m;
3440 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3441 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3447 get_default_field_value (domain, field, v);
3448 } else if (is_static) {
3449 mono_field_static_get_value (vtable, field, v);
3451 mono_field_get_value (obj, field, v);
3454 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3455 args [0] = ptr ? *ptr : NULL;
3456 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3457 mono_error_raise_exception (&error); /* FIXME don't raise here */
3459 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3460 mono_error_raise_exception (&error); /* FIXME don't raise here */
3465 /* boxed value type */
3466 klass = mono_class_from_mono_type (type);
3468 if (mono_class_is_nullable (klass))
3469 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3471 o = mono_object_new_checked (domain, klass, &error);
3472 mono_error_raise_exception (&error); /* FIXME don't raise here */
3473 v = ((gchar *) o) + sizeof (MonoObject);
3476 get_default_field_value (domain, field, v);
3477 } else if (is_static) {
3478 mono_field_static_get_value (vtable, field, v);
3480 mono_field_get_value (obj, field, v);
3487 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3489 MONO_REQ_GC_UNSAFE_MODE;
3492 const char *p = blob;
3493 mono_metadata_decode_blob_size (p, &p);
3496 case MONO_TYPE_BOOLEAN:
3499 *(guint8 *) value = *p;
3501 case MONO_TYPE_CHAR:
3504 *(guint16*) value = read16 (p);
3508 *(guint32*) value = read32 (p);
3512 *(guint64*) value = read64 (p);
3515 readr4 (p, (float*) value);
3518 readr8 (p, (double*) value);
3520 case MONO_TYPE_STRING:
3521 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3523 case MONO_TYPE_CLASS:
3524 *(gpointer*) value = NULL;
3528 g_warning ("type 0x%02x should not be in constant table", type);
3534 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3536 MONO_REQ_GC_NEUTRAL_MODE;
3538 MonoTypeEnum def_type;
3541 data = mono_class_get_field_default_value (field, &def_type);
3542 mono_get_constant_value_from_blob (domain, def_type, data, value);
3546 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3548 MONO_REQ_GC_UNSAFE_MODE;
3552 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3554 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3555 get_default_field_value (vt->domain, field, value);
3559 if (field->offset == -1) {
3560 /* Special static */
3561 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3562 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3564 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3566 mono_copy_value (field->type, value, src, TRUE);
3570 * mono_field_static_get_value:
3571 * @vt: vtable to the object
3572 * @field: MonoClassField describing the field to fetch information from
3573 * @value: where the value is returned
3575 * Use this routine to get the value of the static field @field value.
3577 * The pointer provided by value must be of the field type, for reference
3578 * types this is a MonoObject*, for value types its the actual pointer to
3583 * mono_field_static_get_value (vt, int_field, &i);
3586 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3588 MONO_REQ_GC_NEUTRAL_MODE;
3590 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3594 * mono_property_set_value:
3595 * @prop: MonoProperty to set
3596 * @obj: instance object on which to act
3597 * @params: parameters to pass to the propery
3598 * @exc: optional exception
3600 * Invokes the property's set method with the given arguments on the
3601 * object instance obj (or NULL for static properties).
3603 * You can pass NULL as the exc argument if you don't want to
3604 * catch exceptions, otherwise, *exc will be set to the exception
3605 * thrown, if any. if an exception is thrown, you can't use the
3606 * MonoObject* result from the function.
3609 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3611 MONO_REQ_GC_UNSAFE_MODE;
3614 do_runtime_invoke (prop->set, obj, params, exc, &error);
3615 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3616 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3618 mono_error_raise_exception (&error); /* FIXME don't raise here */
3623 * mono_property_get_value:
3624 * @prop: MonoProperty to fetch
3625 * @obj: instance object on which to act
3626 * @params: parameters to pass to the propery
3627 * @exc: optional exception
3629 * Invokes the property's get method with the given arguments on the
3630 * object instance obj (or NULL for static properties).
3632 * You can pass NULL as the exc argument if you don't want to
3633 * catch exceptions, otherwise, *exc will be set to the exception
3634 * thrown, if any. if an exception is thrown, you can't use the
3635 * MonoObject* result from the function.
3637 * Returns: the value from invoking the get method on the property.
3640 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3642 MONO_REQ_GC_UNSAFE_MODE;
3645 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3646 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3647 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3649 mono_error_raise_exception (&error); /* FIXME don't raise here */
3656 * mono_nullable_init:
3657 * @buf: The nullable structure to initialize.
3658 * @value: the value to initialize from
3659 * @klass: the type for the object
3661 * Initialize the nullable structure pointed to by @buf from @value which
3662 * should be a boxed value type. The size of @buf should be able to hold
3663 * as much data as the @klass->instance_size (which is the number of bytes
3664 * that will be copies).
3666 * Since Nullables have variable structure, we can not define a C
3667 * structure for them.
3670 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3672 MONO_REQ_GC_UNSAFE_MODE;
3674 MonoClass *param_class = klass->cast_class;
3676 mono_class_setup_fields_locking (klass);
3677 g_assert (klass->fields_inited);
3679 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3680 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3682 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3684 if (param_class->has_references)
3685 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3687 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3689 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3694 * mono_nullable_box:
3695 * @buf: The buffer representing the data to be boxed
3696 * @klass: the type to box it as.
3698 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3702 mono_nullable_box (guint8 *buf, MonoClass *klass)
3704 MONO_REQ_GC_UNSAFE_MODE;
3708 MonoClass *param_class = klass->cast_class;
3710 mono_class_setup_fields_locking (klass);
3711 g_assert (klass->fields_inited);
3713 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3714 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3716 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3717 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3718 mono_error_raise_exception (&error); /* FIXME don't raise here */
3719 if (param_class->has_references)
3720 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3722 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3730 * mono_get_delegate_invoke:
3731 * @klass: The delegate class
3733 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3736 mono_get_delegate_invoke (MonoClass *klass)
3738 MONO_REQ_GC_NEUTRAL_MODE;
3742 /* This is called at runtime, so avoid the slower search in metadata */
3743 mono_class_setup_methods (klass);
3744 if (mono_class_has_failure (klass))
3746 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3751 * mono_get_delegate_begin_invoke:
3752 * @klass: The delegate class
3754 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3757 mono_get_delegate_begin_invoke (MonoClass *klass)
3759 MONO_REQ_GC_NEUTRAL_MODE;
3763 /* This is called at runtime, so avoid the slower search in metadata */
3764 mono_class_setup_methods (klass);
3765 if (mono_class_has_failure (klass))
3767 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3772 * mono_get_delegate_end_invoke:
3773 * @klass: The delegate class
3775 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3778 mono_get_delegate_end_invoke (MonoClass *klass)
3780 MONO_REQ_GC_NEUTRAL_MODE;
3784 /* This is called at runtime, so avoid the slower search in metadata */
3785 mono_class_setup_methods (klass);
3786 if (mono_class_has_failure (klass))
3788 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3793 * mono_runtime_delegate_invoke:
3794 * @delegate: pointer to a delegate object.
3795 * @params: parameters for the delegate.
3796 * @exc: Pointer to the exception result.
3798 * Invokes the delegate method @delegate with the parameters provided.
3800 * You can pass NULL as the exc argument if you don't want to
3801 * catch exceptions, otherwise, *exc will be set to the exception
3802 * thrown, if any. if an exception is thrown, you can't use the
3803 * MonoObject* result from the function.
3806 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3808 MONO_REQ_GC_UNSAFE_MODE;
3812 MonoClass *klass = delegate->vtable->klass;
3815 im = mono_get_delegate_invoke (klass);
3817 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3820 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3821 if (*exc == NULL && !mono_error_ok (&error))
3822 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3824 mono_error_cleanup (&error);
3826 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3827 mono_error_raise_exception (&error); /* FIXME don't raise here */
3833 static char **main_args = NULL;
3834 static int num_main_args = 0;
3837 * mono_runtime_get_main_args:
3839 * Returns: a MonoArray with the arguments passed to the main program
3842 mono_runtime_get_main_args (void)
3844 MONO_REQ_GC_UNSAFE_MODE;
3848 MonoDomain *domain = mono_domain_get ();
3850 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3852 for (i = 0; i < num_main_args; ++i)
3853 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3859 free_main_args (void)
3861 MONO_REQ_GC_NEUTRAL_MODE;
3865 for (i = 0; i < num_main_args; ++i)
3866 g_free (main_args [i]);
3873 * mono_runtime_set_main_args:
3874 * @argc: number of arguments from the command line
3875 * @argv: array of strings from the command line
3877 * Set the command line arguments from an embedding application that doesn't otherwise call
3878 * mono_runtime_run_main ().
3881 mono_runtime_set_main_args (int argc, char* argv[])
3883 MONO_REQ_GC_NEUTRAL_MODE;
3888 main_args = g_new0 (char*, argc);
3889 num_main_args = argc;
3891 for (i = 0; i < argc; ++i) {
3894 utf8_arg = mono_utf8_from_external (argv[i]);
3895 if (utf8_arg == NULL) {
3896 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3897 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3901 main_args [i] = utf8_arg;
3908 * mono_runtime_run_main:
3909 * @method: the method to start the application with (usually Main)
3910 * @argc: number of arguments from the command line
3911 * @argv: array of strings from the command line
3912 * @exc: excetption results
3914 * Execute a standard Main() method (argc/argv contains the
3915 * executable name). This method also sets the command line argument value
3916 * needed by System.Environment.
3921 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3924 MONO_REQ_GC_UNSAFE_MODE;
3927 MonoArray *args = NULL;
3928 MonoDomain *domain = mono_domain_get ();
3929 gchar *utf8_fullpath;
3930 MonoMethodSignature *sig;
3932 g_assert (method != NULL);
3934 mono_thread_set_main (mono_thread_current ());
3936 main_args = g_new0 (char*, argc);
3937 num_main_args = argc;
3939 if (!g_path_is_absolute (argv [0])) {
3940 gchar *basename = g_path_get_basename (argv [0]);
3941 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3945 utf8_fullpath = mono_utf8_from_external (fullpath);
3946 if(utf8_fullpath == NULL) {
3947 /* Printing the arg text will cause glib to
3948 * whinge about "Invalid UTF-8", but at least
3949 * its relevant, and shows the problem text
3952 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3953 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3960 utf8_fullpath = mono_utf8_from_external (argv[0]);
3961 if(utf8_fullpath == NULL) {
3962 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3963 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3968 main_args [0] = utf8_fullpath;
3970 for (i = 1; i < argc; ++i) {
3973 utf8_arg=mono_utf8_from_external (argv[i]);
3974 if(utf8_arg==NULL) {
3975 /* Ditto the comment about Invalid UTF-8 here */
3976 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3977 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3981 main_args [i] = utf8_arg;
3986 sig = mono_method_signature (method);
3988 g_print ("Unable to load Main method.\n");
3992 if (sig->param_count) {
3993 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3994 for (i = 0; i < argc; ++i) {
3995 /* The encodings should all work, given that
3996 * we've checked all these args for the
3999 gchar *str = mono_utf8_from_external (argv [i]);
4000 MonoString *arg = mono_string_new (domain, str);
4001 mono_array_setref (args, i, arg);
4005 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4008 mono_assembly_set_main (method->klass->image->assembly);
4010 return mono_runtime_exec_main (method, args, exc);
4014 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4016 static MonoMethod *serialize_method;
4022 if (!serialize_method) {
4023 MonoClass *klass = mono_class_get_remoting_services_class ();
4024 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4027 if (!serialize_method) {
4032 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4037 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4038 if (*exc == NULL && !mono_error_ok (&error))
4039 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4041 mono_error_cleanup (&error);
4050 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4052 MONO_REQ_GC_UNSAFE_MODE;
4054 static MonoMethod *deserialize_method;
4060 if (!deserialize_method) {
4061 MonoClass *klass = mono_class_get_remoting_services_class ();
4062 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4064 if (!deserialize_method) {
4072 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4073 if (*exc == NULL && !mono_error_ok (&error))
4074 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4076 mono_error_cleanup (&error);
4084 #ifndef DISABLE_REMOTING
4086 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4088 MONO_REQ_GC_UNSAFE_MODE;
4090 static MonoMethod *get_proxy_method;
4093 MonoDomain *domain = mono_domain_get ();
4094 MonoRealProxy *real_proxy;
4095 MonoReflectionType *reflection_type;
4096 MonoTransparentProxy *transparent_proxy;
4098 if (!get_proxy_method)
4099 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4101 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4103 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4104 mono_error_raise_exception (&error); /* FIXME don't raise here */
4105 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4106 mono_error_raise_exception (&error); /* FIXME don't raise here */
4108 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4109 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4113 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4114 if (*exc == NULL && !mono_error_ok (&error))
4115 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4117 mono_error_cleanup (&error);
4121 return (MonoObject*) transparent_proxy;
4123 #endif /* DISABLE_REMOTING */
4126 * mono_object_xdomain_representation
4128 * @target_domain: a domain
4129 * @exc: pointer to a MonoObject*
4131 * Creates a representation of obj in the domain target_domain. This
4132 * is either a copy of obj arrived through via serialization and
4133 * deserialization or a proxy, depending on whether the object is
4134 * serializable or marshal by ref. obj must not be in target_domain.
4136 * If the object cannot be represented in target_domain, NULL is
4137 * returned and *exc is set to an appropriate exception.
4140 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4142 MONO_REQ_GC_UNSAFE_MODE;
4144 MonoObject *deserialized = NULL;
4145 gboolean failure = FALSE;
4147 g_assert (exc != NULL);
4150 #ifndef DISABLE_REMOTING
4151 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4152 deserialized = make_transparent_proxy (obj, &failure, exc);
4157 MonoDomain *domain = mono_domain_get ();
4158 MonoObject *serialized;
4160 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4161 serialized = serialize_object (obj, &failure, exc);
4162 mono_domain_set_internal_with_options (target_domain, FALSE);
4164 deserialized = deserialize_object (serialized, &failure, exc);
4165 if (domain != target_domain)
4166 mono_domain_set_internal_with_options (domain, FALSE);
4169 return deserialized;
4172 /* Used in call_unhandled_exception_delegate */
4174 create_unhandled_exception_eventargs (MonoObject *exc)
4176 MONO_REQ_GC_UNSAFE_MODE;
4181 MonoMethod *method = NULL;
4182 MonoBoolean is_terminating = TRUE;
4185 klass = mono_class_get_unhandled_exception_event_args_class ();
4186 mono_class_init (klass);
4188 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4189 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4193 args [1] = &is_terminating;
4195 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4196 mono_error_raise_exception (&error); /* FIXME don't raise here */
4198 mono_runtime_invoke_checked (method, obj, args, &error);
4199 mono_error_raise_exception (&error); /* FIXME don't raise here */
4204 /* Used in mono_unhandled_exception */
4206 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4207 MONO_REQ_GC_UNSAFE_MODE;
4209 MonoObject *e = NULL;
4211 MonoDomain *current_domain = mono_domain_get ();
4213 if (domain != current_domain)
4214 mono_domain_set_internal_with_options (domain, FALSE);
4216 g_assert (domain == mono_object_domain (domain->domain));
4218 if (mono_object_domain (exc) != domain) {
4219 MonoObject *serialization_exc;
4221 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4223 if (serialization_exc) {
4225 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4228 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4229 "System.Runtime.Serialization", "SerializationException",
4230 "Could not serialize unhandled exception.");
4234 g_assert (mono_object_domain (exc) == domain);
4236 pa [0] = domain->domain;
4237 pa [1] = create_unhandled_exception_eventargs (exc);
4238 mono_runtime_delegate_invoke (delegate, pa, &e);
4240 if (domain != current_domain)
4241 mono_domain_set_internal_with_options (current_domain, FALSE);
4245 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4246 if (!mono_error_ok (&error)) {
4247 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4248 mono_error_cleanup (&error);
4250 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4256 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4259 * mono_runtime_unhandled_exception_policy_set:
4260 * @policy: the new policy
4262 * This is a VM internal routine.
4264 * Sets the runtime policy for handling unhandled exceptions.
4267 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4268 runtime_unhandled_exception_policy = policy;
4272 * mono_runtime_unhandled_exception_policy_get:
4274 * This is a VM internal routine.
4276 * Gets the runtime policy for handling unhandled exceptions.
4278 MonoRuntimeUnhandledExceptionPolicy
4279 mono_runtime_unhandled_exception_policy_get (void) {
4280 return runtime_unhandled_exception_policy;
4284 * mono_unhandled_exception:
4285 * @exc: exception thrown
4287 * This is a VM internal routine.
4289 * We call this function when we detect an unhandled exception
4290 * in the default domain.
4292 * It invokes the * UnhandledException event in AppDomain or prints
4293 * a warning to the console
4296 mono_unhandled_exception (MonoObject *exc)
4298 MONO_REQ_GC_UNSAFE_MODE;
4300 MonoClassField *field;
4301 MonoDomain *current_domain, *root_domain;
4302 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4304 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4307 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4310 current_domain = mono_domain_get ();
4311 root_domain = mono_get_root_domain ();
4313 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4314 if (current_domain != root_domain)
4315 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4317 /* set exitcode only if we will abort the process */
4318 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4319 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4320 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4322 mono_environment_exitcode_set (1);
4325 mono_print_unhandled_exception (exc);
4327 if (root_appdomain_delegate)
4328 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4329 if (current_appdomain_delegate)
4330 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4335 * mono_runtime_exec_managed_code:
4336 * @domain: Application domain
4337 * @main_func: function to invoke from the execution thread
4338 * @main_args: parameter to the main_func
4340 * Launch a new thread to execute a function
4342 * main_func is called back from the thread with main_args as the
4343 * parameter. The callback function is expected to start Main()
4344 * eventually. This function then waits for all managed threads to
4346 * It is not necesseray anymore to execute managed code in a subthread,
4347 * so this function should not be used anymore by default: just
4348 * execute the code and then call mono_thread_manage ().
4351 mono_runtime_exec_managed_code (MonoDomain *domain,
4352 MonoMainThreadFunc main_func,
4355 mono_thread_create (domain, main_func, main_args);
4357 mono_thread_manage ();
4361 * Execute a standard Main() method (args doesn't contain the
4365 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4367 MONO_REQ_GC_UNSAFE_MODE;
4373 MonoCustomAttrInfo* cinfo;
4374 gboolean has_stathread_attribute;
4375 MonoInternalThread* thread = mono_thread_internal_current ();
4381 domain = mono_object_domain (args);
4382 if (!domain->entry_assembly) {
4384 MonoAssembly *assembly;
4386 assembly = method->klass->image->assembly;
4387 domain->entry_assembly = assembly;
4388 /* Domains created from another domain already have application_base and configuration_file set */
4389 if (domain->setup->application_base == NULL) {
4390 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4393 if (domain->setup->configuration_file == NULL) {
4394 str = g_strconcat (assembly->image->name, ".config", NULL);
4395 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4397 mono_domain_set_options_from_config (domain);
4401 cinfo = mono_custom_attrs_from_method (method);
4403 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4405 mono_custom_attrs_free (cinfo);
4407 has_stathread_attribute = FALSE;
4409 if (has_stathread_attribute) {
4410 thread->apartment_state = ThreadApartmentState_STA;
4412 thread->apartment_state = ThreadApartmentState_MTA;
4414 mono_thread_init_apartment_state ();
4416 /* FIXME: check signature of method */
4417 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4420 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4421 if (*exc == NULL && !mono_error_ok (&error))
4422 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4424 mono_error_cleanup (&error);
4426 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4427 mono_error_raise_exception (&error); /* FIXME don't raise here */
4431 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4435 mono_environment_exitcode_set (rval);
4438 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4439 if (*exc == NULL && !mono_error_ok (&error))
4440 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4442 mono_error_cleanup (&error);
4444 mono_runtime_invoke_checked (method, NULL, pa, &error);
4445 mono_error_raise_exception (&error); /* FIXME don't raise here */
4451 /* If the return type of Main is void, only
4452 * set the exitcode if an exception was thrown
4453 * (we don't want to blow away an
4454 * explicitly-set exit code)
4457 mono_environment_exitcode_set (rval);
4465 * mono_runtime_invoke_array:
4466 * @method: method to invoke
4467 * @obJ: object instance
4468 * @params: arguments to the method
4469 * @exc: exception information.
4471 * Invokes the method represented by @method on the object @obj.
4473 * obj is the 'this' pointer, it should be NULL for static
4474 * methods, a MonoObject* for object instances and a pointer to
4475 * the value type for value types.
4477 * The params array contains the arguments to the method with the
4478 * same convention: MonoObject* pointers for object instances and
4479 * pointers to the value type otherwise. The _invoke_array
4480 * variant takes a C# object[] as the params argument (MonoArray
4481 * *params): in this case the value types are boxed inside the
4482 * respective reference representation.
4484 * From unmanaged code you'll usually use the
4485 * mono_runtime_invoke_checked() variant.
4487 * Note that this function doesn't handle virtual methods for
4488 * you, it will exec the exact method you pass: we still need to
4489 * expose a function to lookup the derived class implementation
4490 * of a virtual method (there are examples of this in the code,
4493 * You can pass NULL as the exc argument if you don't want to
4494 * catch exceptions, otherwise, *exc will be set to the exception
4495 * thrown, if any. if an exception is thrown, you can't use the
4496 * MonoObject* result from the function.
4498 * If the method returns a value type, it is boxed in an object
4502 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4505 MONO_REQ_GC_UNSAFE_MODE;
4508 MonoMethodSignature *sig = mono_method_signature (method);
4509 gpointer *pa = NULL;
4512 gboolean has_byref_nullables = FALSE;
4514 if (NULL != params) {
4515 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4516 for (i = 0; i < mono_array_length (params); i++) {
4517 MonoType *t = sig->params [i];
4523 case MONO_TYPE_BOOLEAN:
4526 case MONO_TYPE_CHAR:
4535 case MONO_TYPE_VALUETYPE:
4536 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4537 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4538 pa [i] = mono_array_get (params, MonoObject*, i);
4540 has_byref_nullables = TRUE;
4542 /* MS seems to create the objects if a null is passed in */
4543 if (!mono_array_get (params, MonoObject*, i)) {
4544 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4545 mono_error_raise_exception (&error); /* FIXME don't raise here */
4546 mono_array_setref (params, i, o);
4551 * We can't pass the unboxed vtype byref to the callee, since
4552 * that would mean the callee would be able to modify boxed
4553 * primitive types. So we (and MS) make a copy of the boxed
4554 * object, pass that to the callee, and replace the original
4555 * boxed object in the arg array with the copy.
4557 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4558 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4559 mono_array_setref (params, i, copy);
4562 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4565 case MONO_TYPE_STRING:
4566 case MONO_TYPE_OBJECT:
4567 case MONO_TYPE_CLASS:
4568 case MONO_TYPE_ARRAY:
4569 case MONO_TYPE_SZARRAY:
4571 pa [i] = mono_array_addr (params, MonoObject*, i);
4572 // FIXME: I need to check this code path
4574 pa [i] = mono_array_get (params, MonoObject*, i);
4576 case MONO_TYPE_GENERICINST:
4578 t = &t->data.generic_class->container_class->this_arg;
4580 t = &t->data.generic_class->container_class->byval_arg;
4582 case MONO_TYPE_PTR: {
4585 /* The argument should be an IntPtr */
4586 arg = mono_array_get (params, MonoObject*, i);
4590 g_assert (arg->vtable->klass == mono_defaults.int_class);
4591 pa [i] = ((MonoIntPtr*)arg)->m_value;
4596 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4601 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4604 if (mono_class_is_nullable (method->klass)) {
4605 /* Need to create a boxed vtype instead */
4611 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4615 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4616 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4617 #ifndef DISABLE_REMOTING
4618 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4619 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4622 if (method->klass->valuetype)
4623 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4626 } else if (method->klass->valuetype) {
4627 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4631 mono_runtime_try_invoke (method, o, pa, exc, &error);
4632 if (*exc == NULL && !mono_error_ok (&error))
4633 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4635 mono_error_cleanup (&error);
4637 mono_runtime_invoke_checked (method, o, pa, &error);
4638 mono_error_raise_exception (&error); /* FIXME don't raise here */
4641 return (MonoObject *)obj;
4643 if (mono_class_is_nullable (method->klass)) {
4644 MonoObject *nullable;
4646 /* Convert the unboxed vtype into a Nullable structure */
4647 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4648 mono_error_raise_exception (&error); /* FIXME don't raise here */
4650 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4651 obj = mono_object_unbox (nullable);
4654 /* obj must be already unboxed if needed */
4656 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4657 if (*exc == NULL && !mono_error_ok (&error))
4658 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4660 mono_error_cleanup (&error);
4662 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4663 mono_error_raise_exception (&error); /* FIXME don't raise here */
4666 if (sig->ret->type == MONO_TYPE_PTR) {
4667 MonoClass *pointer_class;
4668 static MonoMethod *box_method;
4670 MonoObject *box_exc;
4673 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4674 * convert it to a Pointer object.
4676 pointer_class = mono_class_get_pointer_class ();
4678 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4680 g_assert (res->vtable->klass == mono_defaults.int_class);
4681 box_args [0] = ((MonoIntPtr*)res)->m_value;
4682 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4683 mono_error_raise_exception (&error); /* FIXME don't raise here */
4685 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4686 g_assert (box_exc == NULL);
4687 mono_error_assert_ok (&error);
4690 if (has_byref_nullables) {
4692 * The runtime invoke wrapper already converted byref nullables back,
4693 * and stored them in pa, we just need to copy them back to the
4696 for (i = 0; i < mono_array_length (params); i++) {
4697 MonoType *t = sig->params [i];
4699 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4700 mono_array_setref (params, i, pa [i]);
4710 * @klass: the class of the object that we want to create
4712 * Returns: a newly created object whose definition is
4713 * looked up using @klass. This will not invoke any constructors,
4714 * so the consumer of this routine has to invoke any constructors on
4715 * its own to initialize the object.
4717 * It returns NULL on failure.
4720 mono_object_new (MonoDomain *domain, MonoClass *klass)
4722 MONO_REQ_GC_UNSAFE_MODE;
4726 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4728 mono_error_raise_exception (&error);
4733 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4735 MONO_REQ_GC_UNSAFE_MODE;
4739 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4741 mono_error_raise_exception (&error);
4746 * mono_object_new_checked:
4747 * @klass: the class of the object that we want to create
4748 * @error: set on error
4750 * Returns: a newly created object whose definition is
4751 * looked up using @klass. This will not invoke any constructors,
4752 * so the consumer of this routine has to invoke any constructors on
4753 * its own to initialize the object.
4755 * It returns NULL on failure and sets @error.
4758 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4760 MONO_REQ_GC_UNSAFE_MODE;
4764 vtable = mono_class_vtable (domain, klass);
4765 g_assert (vtable); /* FIXME don't swallow the error */
4767 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4772 * mono_object_new_pinned:
4774 * Same as mono_object_new, but the returned object will be pinned.
4775 * For SGEN, these objects will only be freed at appdomain unload.
4778 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4780 MONO_REQ_GC_UNSAFE_MODE;
4784 mono_error_init (error);
4786 vtable = mono_class_vtable (domain, klass);
4787 g_assert (vtable); /* FIXME don't swallow the error */
4789 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4791 if (G_UNLIKELY (!o))
4792 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4793 else if (G_UNLIKELY (vtable->klass->has_finalize))
4794 mono_object_register_finalizer (o);
4800 * mono_object_new_specific:
4801 * @vtable: the vtable of the object that we want to create
4803 * Returns: A newly created object with class and domain specified
4807 mono_object_new_specific (MonoVTable *vtable)
4810 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4811 mono_error_raise_exception (&error);
4817 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4819 MONO_REQ_GC_UNSAFE_MODE;
4823 mono_error_init (error);
4825 /* check for is_com_object for COM Interop */
4826 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4829 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4832 MonoClass *klass = mono_class_get_activation_services_class ();
4835 mono_class_init (klass);
4837 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4839 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4842 vtable->domain->create_proxy_for_type_method = im;
4845 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4846 if (!mono_error_ok (error))
4849 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4850 if (!mono_error_ok (error))
4857 return mono_object_new_alloc_specific_checked (vtable, error);
4861 ves_icall_object_new_specific (MonoVTable *vtable)
4864 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4865 mono_error_raise_exception (&error);
4871 * mono_object_new_alloc_specific:
4872 * @vtable: virtual table for the object.
4874 * This function allocates a new `MonoObject` with the type derived
4875 * from the @vtable information. If the class of this object has a
4876 * finalizer, then the object will be tracked for finalization.
4878 * This method might raise an exception on errors. Use the
4879 * `mono_object_new_fast_checked` method if you want to manually raise
4882 * Returns: the allocated object.
4885 mono_object_new_alloc_specific (MonoVTable *vtable)
4888 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4889 mono_error_raise_exception (&error);
4895 * mono_object_new_alloc_specific_checked:
4896 * @vtable: virtual table for the object.
4897 * @error: holds the error return value.
4899 * This function allocates a new `MonoObject` with the type derived
4900 * from the @vtable information. If the class of this object has a
4901 * finalizer, then the object will be tracked for finalization.
4903 * If there is not enough memory, the @error parameter will be set
4904 * and will contain a user-visible message with the amount of bytes
4905 * that were requested.
4907 * Returns: the allocated object, or NULL if there is not enough memory
4911 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4913 MONO_REQ_GC_UNSAFE_MODE;
4917 mono_error_init (error);
4919 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4921 if (G_UNLIKELY (!o))
4922 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4923 else if (G_UNLIKELY (vtable->klass->has_finalize))
4924 mono_object_register_finalizer (o);
4930 * mono_object_new_fast:
4931 * @vtable: virtual table for the object.
4933 * This function allocates a new `MonoObject` with the type derived
4934 * from the @vtable information. The returned object is not tracked
4935 * for finalization. If your object implements a finalizer, you should
4936 * use `mono_object_new_alloc_specific` instead.
4938 * This method might raise an exception on errors. Use the
4939 * `mono_object_new_fast_checked` method if you want to manually raise
4942 * Returns: the allocated object.
4945 mono_object_new_fast (MonoVTable *vtable)
4948 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4949 mono_error_raise_exception (&error);
4955 * mono_object_new_fast_checked:
4956 * @vtable: virtual table for the object.
4957 * @error: holds the error return value.
4959 * This function allocates a new `MonoObject` with the type derived
4960 * from the @vtable information. The returned object is not tracked
4961 * for finalization. If your object implements a finalizer, you should
4962 * use `mono_object_new_alloc_specific_checked` instead.
4964 * If there is not enough memory, the @error parameter will be set
4965 * and will contain a user-visible message with the amount of bytes
4966 * that were requested.
4968 * Returns: the allocated object, or NULL if there is not enough memory
4972 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4974 MONO_REQ_GC_UNSAFE_MODE;
4978 mono_error_init (error);
4980 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4982 if (G_UNLIKELY (!o))
4983 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4989 ves_icall_object_new_fast (MonoVTable *vtable)
4992 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4993 mono_error_raise_exception (&error);
4999 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5001 MONO_REQ_GC_UNSAFE_MODE;
5005 mono_error_init (error);
5007 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5009 if (G_UNLIKELY (!o))
5010 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5011 else if (G_UNLIKELY (vtable->klass->has_finalize))
5012 mono_object_register_finalizer (o);
5018 * mono_class_get_allocation_ftn:
5020 * @for_box: the object will be used for boxing
5021 * @pass_size_in_words:
5023 * Return the allocation function appropriate for the given class.
5027 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5029 MONO_REQ_GC_NEUTRAL_MODE;
5031 *pass_size_in_words = FALSE;
5033 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5034 return ves_icall_object_new_specific;
5036 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5038 return ves_icall_object_new_fast;
5041 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5042 * of the overhead of parameter passing.
5045 *pass_size_in_words = TRUE;
5046 #ifdef GC_REDIRECT_TO_LOCAL
5047 return GC_local_gcj_fast_malloc;
5049 return GC_gcj_fast_malloc;
5054 return ves_icall_object_new_specific;
5058 * mono_object_new_from_token:
5059 * @image: Context where the type_token is hosted
5060 * @token: a token of the type that we want to create
5062 * Returns: A newly created object whose definition is
5063 * looked up using @token in the @image image
5066 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5068 MONO_REQ_GC_UNSAFE_MODE;
5074 klass = mono_class_get_checked (image, token, &error);
5075 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5077 result = mono_object_new_checked (domain, klass, &error);
5079 mono_error_raise_exception (&error); /* FIXME don't raise here */
5086 * mono_object_clone:
5087 * @obj: the object to clone
5089 * Returns: A newly created object who is a shallow copy of @obj
5092 mono_object_clone (MonoObject *obj)
5095 MonoObject *o = mono_object_clone_checked (obj, &error);
5096 mono_error_raise_exception (&error);
5102 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5104 MONO_REQ_GC_UNSAFE_MODE;
5109 mono_error_init (error);
5111 size = obj->vtable->klass->instance_size;
5113 if (obj->vtable->klass->rank)
5114 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5116 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5118 if (G_UNLIKELY (!o)) {
5119 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5123 /* If the object doesn't contain references this will do a simple memmove. */
5124 mono_gc_wbarrier_object_copy (o, obj);
5126 if (obj->vtable->klass->has_finalize)
5127 mono_object_register_finalizer (o);
5132 * mono_array_full_copy:
5133 * @src: source array to copy
5134 * @dest: destination array
5136 * Copies the content of one array to another with exactly the same type and size.
5139 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5141 MONO_REQ_GC_UNSAFE_MODE;
5144 MonoClass *klass = src->obj.vtable->klass;
5146 g_assert (klass == dest->obj.vtable->klass);
5148 size = mono_array_length (src);
5149 g_assert (size == mono_array_length (dest));
5150 size *= mono_array_element_size (klass);
5152 if (klass->element_class->valuetype) {
5153 if (klass->element_class->has_references)
5154 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5156 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5158 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5161 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5166 * mono_array_clone_in_domain:
5167 * @domain: the domain in which the array will be cloned into
5168 * @array: the array to clone
5170 * This routine returns a copy of the array that is hosted on the
5171 * specified MonoDomain.
5174 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5176 MONO_REQ_GC_UNSAFE_MODE;
5182 MonoClass *klass = array->obj.vtable->klass;
5184 if (array->bounds == NULL) {
5185 size = mono_array_length (array);
5186 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5187 mono_error_raise_exception (&error); /* FIXME don't raise here */
5189 size *= mono_array_element_size (klass);
5191 if (klass->element_class->valuetype) {
5192 if (klass->element_class->has_references)
5193 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5195 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5197 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5200 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5205 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5206 size = mono_array_element_size (klass);
5207 for (i = 0; i < klass->rank; ++i) {
5208 sizes [i] = array->bounds [i].length;
5209 size *= array->bounds [i].length;
5210 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5212 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5213 mono_error_raise_exception (&error); /* FIXME don't raise here */
5215 if (klass->element_class->valuetype) {
5216 if (klass->element_class->has_references)
5217 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5219 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5221 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5224 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5232 * @array: the array to clone
5234 * Returns: A newly created array who is a shallow copy of @array
5237 mono_array_clone (MonoArray *array)
5239 MONO_REQ_GC_UNSAFE_MODE;
5241 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5244 /* helper macros to check for overflow when calculating the size of arrays */
5245 #ifdef MONO_BIG_ARRAYS
5246 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5247 #define MYGUINT_MAX MYGUINT64_MAX
5248 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5249 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5250 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5251 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5252 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5254 #define MYGUINT32_MAX 4294967295U
5255 #define MYGUINT_MAX MYGUINT32_MAX
5256 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5257 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5258 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5259 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5260 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5264 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5266 MONO_REQ_GC_NEUTRAL_MODE;
5270 byte_len = mono_array_element_size (klass);
5271 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5274 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5276 byte_len += MONO_SIZEOF_MONO_ARRAY;
5284 * mono_array_new_full:
5285 * @domain: domain where the object is created
5286 * @array_class: array class
5287 * @lengths: lengths for each dimension in the array
5288 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5290 * This routine creates a new array objects with the given dimensions,
5291 * lower bounds and type.
5294 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5297 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5298 mono_error_raise_exception (&error);
5304 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5306 MONO_REQ_GC_UNSAFE_MODE;
5308 uintptr_t byte_len = 0, len, bounds_size;
5311 MonoArrayBounds *bounds;
5315 mono_error_init (error);
5317 if (!array_class->inited)
5318 mono_class_init (array_class);
5322 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5323 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5325 if (len > MONO_ARRAY_MAX_INDEX) {
5326 mono_error_set_generic_error (error, "System", "OverflowException", "");
5331 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5333 for (i = 0; i < array_class->rank; ++i) {
5334 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5335 mono_error_set_generic_error (error, "System", "OverflowException", "");
5338 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5339 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5346 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5347 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5353 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5354 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5357 byte_len = (byte_len + 3) & ~3;
5358 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5359 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5362 byte_len += bounds_size;
5365 * Following three lines almost taken from mono_object_new ():
5366 * they need to be kept in sync.
5368 vtable = mono_class_vtable_full (domain, array_class, error);
5369 return_val_if_nok (error, NULL);
5372 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5374 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5376 if (G_UNLIKELY (!o)) {
5377 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5381 array = (MonoArray*)o;
5383 bounds = array->bounds;
5386 for (i = 0; i < array_class->rank; ++i) {
5387 bounds [i].length = lengths [i];
5389 bounds [i].lower_bound = lower_bounds [i];
5398 * @domain: domain where the object is created
5399 * @eclass: element class
5400 * @n: number of array elements
5402 * This routine creates a new szarray with @n elements of type @eclass.
5405 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5407 MONO_REQ_GC_UNSAFE_MODE;
5413 ac = mono_array_class_get (eclass, 1);
5416 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5417 mono_error_raise_exception (&error); /* FIXME don't raise here */
5419 arr = mono_array_new_specific_checked (vtable, n, &error);
5420 mono_error_raise_exception (&error); /* FIXME don't raise here */
5426 * mono_array_new_specific:
5427 * @vtable: a vtable in the appropriate domain for an initialized class
5428 * @n: number of array elements
5430 * This routine is a fast alternative to mono_array_new() for code which
5431 * can be sure about the domain it operates in.
5434 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5437 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5438 mono_error_raise_exception (&error); /* FIXME don't raise here */
5444 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5446 MONO_REQ_GC_UNSAFE_MODE;
5451 mono_error_init (error);
5453 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5454 mono_error_set_generic_error (error, "System", "OverflowException", "");
5458 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5459 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5462 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5464 if (G_UNLIKELY (!o)) {
5465 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5469 return (MonoArray*)o;
5473 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5476 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5477 mono_error_raise_exception (&error);
5483 * mono_string_new_utf16:
5484 * @text: a pointer to an utf16 string
5485 * @len: the length of the string
5487 * Returns: A newly created string object which contains @text.
5490 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5492 MONO_REQ_GC_UNSAFE_MODE;
5495 MonoString *res = NULL;
5496 res = mono_string_new_utf16_checked (domain, text, len, &error);
5497 mono_error_raise_exception (&error);
5503 * mono_string_new_utf16_checked:
5504 * @text: a pointer to an utf16 string
5505 * @len: the length of the string
5506 * @error: written on error.
5508 * Returns: A newly created string object which contains @text.
5509 * On error, returns NULL and sets @error.
5512 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5514 MONO_REQ_GC_UNSAFE_MODE;
5518 mono_error_init (error);
5520 s = mono_string_new_size_checked (domain, len, error);
5522 memcpy (mono_string_chars (s), text, len * 2);
5528 * mono_string_new_utf32:
5529 * @text: a pointer to an utf32 string
5530 * @len: the length of the string
5532 * Returns: A newly created string object which contains @text.
5535 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5537 MONO_REQ_GC_UNSAFE_MODE;
5541 mono_unichar2 *utf16_output = NULL;
5542 gint32 utf16_len = 0;
5543 GError *gerror = NULL;
5544 glong items_written;
5546 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5549 g_error_free (gerror);
5551 while (utf16_output [utf16_len]) utf16_len++;
5553 s = mono_string_new_size_checked (domain, utf16_len, &error);
5554 mono_error_raise_exception (&error); /* FIXME don't raise here */
5556 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5558 g_free (utf16_output);
5564 * mono_string_new_size:
5565 * @text: a pointer to an utf16 string
5566 * @len: the length of the string
5568 * Returns: A newly created string object of @len
5571 mono_string_new_size (MonoDomain *domain, gint32 len)
5574 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5575 mono_error_raise_exception (&error);
5581 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5583 MONO_REQ_GC_UNSAFE_MODE;
5589 mono_error_init (error);
5591 /* check for overflow */
5592 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5593 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5597 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5598 g_assert (size > 0);
5600 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5603 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5605 if (G_UNLIKELY (!s)) {
5606 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5614 * mono_string_new_len:
5615 * @text: a pointer to an utf8 string
5616 * @length: number of bytes in @text to consider
5618 * Returns: A newly created string object which contains @text.
5621 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5623 MONO_REQ_GC_UNSAFE_MODE;
5626 GError *eg_error = NULL;
5627 MonoString *o = NULL;
5629 glong items_written;
5631 mono_error_init (&error);
5633 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5636 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5638 g_error_free (eg_error);
5642 mono_error_raise_exception (&error); /* FIXME don't raise here */
5648 * @text: a pointer to an utf8 string
5650 * Returns: A newly created string object which contains @text.
5652 * This function asserts if it cannot allocate a new string.
5654 * @deprecated Use mono_string_new_checked in new code.
5657 mono_string_new (MonoDomain *domain, const char *text)
5660 MonoString *res = NULL;
5661 res = mono_string_new_checked (domain, text, &error);
5662 mono_error_assert_ok (&error);
5667 * mono_string_new_checked:
5668 * @text: a pointer to an utf8 string
5669 * @merror: set on error
5671 * Returns: A newly created string object which contains @text.
5672 * On error returns NULL and sets @merror.
5675 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5677 MONO_REQ_GC_UNSAFE_MODE;
5679 GError *eg_error = NULL;
5680 MonoString *o = NULL;
5682 glong items_written;
5685 mono_error_init (error);
5689 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5692 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5694 g_error_free (eg_error);
5697 mono_error_raise_exception (error);
5699 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5704 MonoString *o = NULL;
5706 if (!g_utf8_validate (text, -1, &end)) {
5707 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5711 len = g_utf8_strlen (text, -1);
5712 o = mono_string_new_size_checked (domain, len, error);
5715 str = mono_string_chars (o);
5717 while (text < end) {
5718 *str++ = g_utf8_get_char (text);
5719 text = g_utf8_next_char (text);
5728 * mono_string_new_wrapper:
5729 * @text: pointer to utf8 characters.
5731 * Helper function to create a string object from @text in the current domain.
5734 mono_string_new_wrapper (const char *text)
5736 MONO_REQ_GC_UNSAFE_MODE;
5738 MonoDomain *domain = mono_domain_get ();
5741 return mono_string_new (domain, text);
5748 * @class: the class of the value
5749 * @value: a pointer to the unboxed data
5751 * Returns: A newly created object which contains @value.
5754 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5756 MONO_REQ_GC_UNSAFE_MODE;
5763 g_assert (klass->valuetype);
5764 if (mono_class_is_nullable (klass))
5765 return mono_nullable_box ((guint8 *)value, klass);
5767 vtable = mono_class_vtable (domain, klass);
5770 size = mono_class_instance_size (klass);
5771 res = mono_object_new_alloc_specific_checked (vtable, &error);
5772 mono_error_raise_exception (&error); /* FIXME don't raise here */
5774 size = size - sizeof (MonoObject);
5777 g_assert (size == mono_class_value_size (klass, NULL));
5778 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5780 #if NO_UNALIGNED_ACCESS
5781 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5785 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5788 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5791 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5794 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5797 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5801 if (klass->has_finalize)
5802 mono_object_register_finalizer (res);
5808 * @dest: destination pointer
5809 * @src: source pointer
5810 * @klass: a valuetype class
5812 * Copy a valuetype from @src to @dest. This function must be used
5813 * when @klass contains references fields.
5816 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5818 MONO_REQ_GC_UNSAFE_MODE;
5820 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5824 * mono_value_copy_array:
5825 * @dest: destination array
5826 * @dest_idx: index in the @dest array
5827 * @src: source pointer
5828 * @count: number of items
5830 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5831 * This function must be used when @klass contains references fields.
5832 * Overlap is handled.
5835 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5837 MONO_REQ_GC_UNSAFE_MODE;
5839 int size = mono_array_element_size (dest->obj.vtable->klass);
5840 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5841 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5842 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5846 * mono_object_get_domain:
5847 * @obj: object to query
5849 * Returns: the MonoDomain where the object is hosted
5852 mono_object_get_domain (MonoObject *obj)
5854 MONO_REQ_GC_UNSAFE_MODE;
5856 return mono_object_domain (obj);
5860 * mono_object_get_class:
5861 * @obj: object to query
5863 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5865 * Returns: the MonoClass of the object.
5868 mono_object_get_class (MonoObject *obj)
5870 MONO_REQ_GC_UNSAFE_MODE;
5872 return mono_object_class (obj);
5875 * mono_object_get_size:
5876 * @o: object to query
5878 * Returns: the size, in bytes, of @o
5881 mono_object_get_size (MonoObject* o)
5883 MONO_REQ_GC_UNSAFE_MODE;
5885 MonoClass* klass = mono_object_class (o);
5886 if (klass == mono_defaults.string_class) {
5887 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5888 } else if (o->vtable->rank) {
5889 MonoArray *array = (MonoArray*)o;
5890 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5891 if (array->bounds) {
5894 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5898 return mono_class_instance_size (klass);
5903 * mono_object_unbox:
5904 * @obj: object to unbox
5906 * Returns: a pointer to the start of the valuetype boxed in this
5909 * This method will assert if the object passed is not a valuetype.
5912 mono_object_unbox (MonoObject *obj)
5914 MONO_REQ_GC_UNSAFE_MODE;
5916 /* add assert for valuetypes? */
5917 g_assert (obj->vtable->klass->valuetype);
5918 return ((char*)obj) + sizeof (MonoObject);
5922 * mono_object_isinst:
5924 * @klass: a pointer to a class
5926 * Returns: @obj if @obj is derived from @klass
5929 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5931 MONO_REQ_GC_UNSAFE_MODE;
5934 mono_class_init (klass);
5936 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5937 return mono_object_isinst_mbyref (obj, klass);
5942 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5946 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5948 MONO_REQ_GC_UNSAFE_MODE;
5958 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5959 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5963 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5964 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5967 MonoClass *oklass = vt->klass;
5968 if (mono_class_is_transparent_proxy (oklass))
5969 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5971 mono_class_setup_supertypes (klass);
5972 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5975 #ifndef DISABLE_REMOTING
5976 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5978 MonoDomain *domain = mono_domain_get ();
5980 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5981 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5982 MonoMethod *im = NULL;
5985 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5987 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5988 im = mono_object_get_virtual_method (rp, im);
5991 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5992 mono_error_raise_exception (&error); /* FIXME don't raise here */
5995 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5996 mono_error_raise_exception (&error); /* FIXME don't raise here */
5998 if (*(MonoBoolean *) mono_object_unbox(res)) {
5999 /* Update the vtable of the remote type, so it can safely cast to this new type */
6000 mono_upgrade_remote_class (domain, obj, klass);
6004 #endif /* DISABLE_REMOTING */
6009 * mono_object_castclass_mbyref:
6011 * @klass: a pointer to a class
6013 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6016 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6018 MONO_REQ_GC_UNSAFE_MODE;
6020 if (!obj) return NULL;
6021 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6023 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6025 "InvalidCastException"));
6030 MonoDomain *orig_domain;
6036 str_lookup (MonoDomain *domain, gpointer user_data)
6038 MONO_REQ_GC_UNSAFE_MODE;
6040 LDStrInfo *info = (LDStrInfo *)user_data;
6041 if (info->res || domain == info->orig_domain)
6043 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6047 mono_string_get_pinned (MonoString *str, MonoError *error)
6049 MONO_REQ_GC_UNSAFE_MODE;
6051 mono_error_init (error);
6053 /* We only need to make a pinned version of a string if this is a moving GC */
6054 if (!mono_gc_is_moving ())
6058 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6059 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6061 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6062 news->length = mono_string_length (str);
6064 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6070 mono_string_is_interned_lookup (MonoString *str, int insert)
6072 MONO_REQ_GC_UNSAFE_MODE;
6075 MonoGHashTable *ldstr_table;
6076 MonoString *s, *res;
6079 domain = ((MonoObject *)str)->vtable->domain;
6080 ldstr_table = domain->ldstr_table;
6082 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6088 /* Allocate outside the lock */
6090 s = mono_string_get_pinned (str, &error);
6091 mono_error_raise_exception (&error); /* FIXME don't raise here */
6094 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6099 mono_g_hash_table_insert (ldstr_table, s, s);
6104 LDStrInfo ldstr_info;
6105 ldstr_info.orig_domain = domain;
6106 ldstr_info.ins = str;
6107 ldstr_info.res = NULL;
6109 mono_domain_foreach (str_lookup, &ldstr_info);
6110 if (ldstr_info.res) {
6112 * the string was already interned in some other domain:
6113 * intern it in the current one as well.
6115 mono_g_hash_table_insert (ldstr_table, str, str);
6125 * mono_string_is_interned:
6126 * @o: String to probe
6128 * Returns whether the string has been interned.
6131 mono_string_is_interned (MonoString *o)
6133 MONO_REQ_GC_UNSAFE_MODE;
6135 return mono_string_is_interned_lookup (o, FALSE);
6139 * mono_string_intern:
6140 * @o: String to intern
6142 * Interns the string passed.
6143 * Returns: The interned string.
6146 mono_string_intern (MonoString *str)
6148 MONO_REQ_GC_UNSAFE_MODE;
6150 return mono_string_is_interned_lookup (str, TRUE);
6155 * @domain: the domain where the string will be used.
6156 * @image: a metadata context
6157 * @idx: index into the user string table.
6159 * Implementation for the ldstr opcode.
6160 * Returns: a loaded string from the @image/@idx combination.
6163 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6165 MONO_REQ_GC_UNSAFE_MODE;
6167 if (image->dynamic) {
6168 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6171 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6172 return NULL; /*FIXME we should probably be raising an exception here*/
6173 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6178 * mono_ldstr_metadata_sig
6179 * @domain: the domain for the string
6180 * @sig: the signature of a metadata string
6182 * Returns: a MonoString for a string stored in the metadata
6185 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6187 MONO_REQ_GC_UNSAFE_MODE;
6190 const char *str = sig;
6191 MonoString *o, *interned;
6194 len2 = mono_metadata_decode_blob_size (str, &str);
6197 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6198 mono_error_raise_exception (&error); /* FIXME don't raise here */
6199 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6202 guint16 *p2 = (guint16*)mono_string_chars (o);
6203 for (i = 0; i < len2; ++i) {
6204 *p2 = GUINT16_FROM_LE (*p2);
6210 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6213 return interned; /* o will get garbage collected */
6215 o = mono_string_get_pinned (o, &error);
6216 mono_error_raise_exception (&error); /* FIXME don't raise here */
6219 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6221 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6231 * mono_string_to_utf8:
6232 * @s: a System.String
6234 * Returns the UTF8 representation for @s.
6235 * The resulting buffer needs to be freed with mono_free().
6237 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6240 mono_string_to_utf8 (MonoString *s)
6242 MONO_REQ_GC_UNSAFE_MODE;
6245 char *result = mono_string_to_utf8_checked (s, &error);
6247 if (!mono_error_ok (&error))
6248 mono_error_raise_exception (&error);
6253 * mono_string_to_utf8_checked:
6254 * @s: a System.String
6255 * @error: a MonoError.
6257 * Converts a MonoString to its UTF8 representation. May fail; check
6258 * @error to determine whether the conversion was successful.
6259 * The resulting buffer should be freed with mono_free().
6262 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6264 MONO_REQ_GC_UNSAFE_MODE;
6268 GError *gerror = NULL;
6270 mono_error_init (error);
6276 return g_strdup ("");
6278 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6280 mono_error_set_argument (error, "string", "%s", gerror->message);
6281 g_error_free (gerror);
6284 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6285 if (s->length > written) {
6286 /* allocate the total length and copy the part of the string that has been converted */
6287 char *as2 = (char *)g_malloc0 (s->length);
6288 memcpy (as2, as, written);
6297 * mono_string_to_utf8_ignore:
6300 * Converts a MonoString to its UTF8 representation. Will ignore
6301 * invalid surrogate pairs.
6302 * The resulting buffer should be freed with mono_free().
6306 mono_string_to_utf8_ignore (MonoString *s)
6308 MONO_REQ_GC_UNSAFE_MODE;
6317 return g_strdup ("");
6319 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6321 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6322 if (s->length > written) {
6323 /* allocate the total length and copy the part of the string that has been converted */
6324 char *as2 = (char *)g_malloc0 (s->length);
6325 memcpy (as2, as, written);
6334 * mono_string_to_utf8_image_ignore:
6335 * @s: a System.String
6337 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6340 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6342 MONO_REQ_GC_UNSAFE_MODE;
6344 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6348 * mono_string_to_utf8_mp_ignore:
6349 * @s: a System.String
6351 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6354 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6356 MONO_REQ_GC_UNSAFE_MODE;
6358 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6363 * mono_string_to_utf16:
6366 * Return an null-terminated array of the utf-16 chars
6367 * contained in @s. The result must be freed with g_free().
6368 * This is a temporary helper until our string implementation
6369 * is reworked to always include the null terminating char.
6372 mono_string_to_utf16 (MonoString *s)
6374 MONO_REQ_GC_UNSAFE_MODE;
6381 as = (char *)g_malloc ((s->length * 2) + 2);
6382 as [(s->length * 2)] = '\0';
6383 as [(s->length * 2) + 1] = '\0';
6386 return (gunichar2 *)(as);
6389 memcpy (as, mono_string_chars(s), s->length * 2);
6390 return (gunichar2 *)(as);
6394 * mono_string_to_utf32:
6397 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6398 * contained in @s. The result must be freed with g_free().
6401 mono_string_to_utf32 (MonoString *s)
6403 MONO_REQ_GC_UNSAFE_MODE;
6405 mono_unichar4 *utf32_output = NULL;
6406 GError *error = NULL;
6407 glong items_written;
6412 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6415 g_error_free (error);
6417 return utf32_output;
6421 * mono_string_from_utf16:
6422 * @data: the UTF16 string (LPWSTR) to convert
6424 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6426 * Returns: a MonoString.
6429 mono_string_from_utf16 (gunichar2 *data)
6431 MONO_REQ_GC_UNSAFE_MODE;
6434 MonoString *res = NULL;
6435 MonoDomain *domain = mono_domain_get ();
6441 while (data [len]) len++;
6443 res = mono_string_new_utf16_checked (domain, data, len, &error);
6444 mono_error_raise_exception (&error); /* FIXME don't raise here */
6449 * mono_string_from_utf32:
6450 * @data: the UTF32 string (LPWSTR) to convert
6452 * Converts a UTF32 (UCS-4)to a MonoString.
6454 * Returns: a MonoString.
6457 mono_string_from_utf32 (mono_unichar4 *data)
6459 MONO_REQ_GC_UNSAFE_MODE;
6461 MonoString* result = NULL;
6462 mono_unichar2 *utf16_output = NULL;
6463 GError *error = NULL;
6464 glong items_written;
6470 while (data [len]) len++;
6472 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6475 g_error_free (error);
6477 result = mono_string_from_utf16 (utf16_output);
6478 g_free (utf16_output);
6483 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6485 MONO_REQ_GC_UNSAFE_MODE;
6492 r = mono_string_to_utf8_ignore (s);
6494 r = mono_string_to_utf8_checked (s, error);
6495 if (!mono_error_ok (error))
6502 len = strlen (r) + 1;
6504 mp_s = (char *)mono_mempool_alloc (mp, len);
6506 mp_s = (char *)mono_image_alloc (image, len);
6508 memcpy (mp_s, r, len);
6516 * mono_string_to_utf8_image:
6517 * @s: a System.String
6519 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6522 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6524 MONO_REQ_GC_UNSAFE_MODE;
6526 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6530 * mono_string_to_utf8_mp:
6531 * @s: a System.String
6533 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6536 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6538 MONO_REQ_GC_UNSAFE_MODE;
6540 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6544 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6547 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6549 eh_callbacks = *cbs;
6552 MonoRuntimeExceptionHandlingCallbacks *
6553 mono_get_eh_callbacks (void)
6555 return &eh_callbacks;
6559 * mono_raise_exception:
6560 * @ex: exception object
6562 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6565 mono_raise_exception (MonoException *ex)
6567 MONO_REQ_GC_UNSAFE_MODE;
6570 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6571 * that will cause gcc to omit the function epilog, causing problems when
6572 * the JIT tries to walk the stack, since the return address on the stack
6573 * will point into the next function in the executable, not this one.
6575 eh_callbacks.mono_raise_exception (ex);
6579 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6581 MONO_REQ_GC_UNSAFE_MODE;
6583 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6587 * mono_wait_handle_new:
6588 * @domain: Domain where the object will be created
6589 * @handle: Handle for the wait handle
6591 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6594 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6596 MONO_REQ_GC_UNSAFE_MODE;
6599 MonoWaitHandle *res;
6600 gpointer params [1];
6601 static MonoMethod *handle_set;
6603 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6604 mono_error_raise_exception (&error); /* FIXME don't raise here */
6606 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6608 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6610 params [0] = &handle;
6612 mono_runtime_invoke_checked (handle_set, res, params, &error);
6613 mono_error_raise_exception (&error); /* FIXME don't raise here */
6619 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6621 MONO_REQ_GC_UNSAFE_MODE;
6623 static MonoClassField *f_safe_handle = NULL;
6626 if (!f_safe_handle) {
6627 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6628 g_assert (f_safe_handle);
6631 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6637 mono_runtime_capture_context (MonoDomain *domain)
6639 MONO_REQ_GC_UNSAFE_MODE;
6641 RuntimeInvokeFunction runtime_invoke;
6643 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6644 MonoMethod *method = mono_get_context_capture_method ();
6645 MonoMethod *wrapper;
6648 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6649 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6650 domain->capture_context_method = mono_compile_method (method);
6653 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6655 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6658 * mono_async_result_new:
6659 * @domain:domain where the object will be created.
6660 * @handle: wait handle.
6661 * @state: state to pass to AsyncResult
6662 * @data: C closure data.
6664 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6665 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6669 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6671 MONO_REQ_GC_UNSAFE_MODE;
6674 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6675 mono_error_raise_exception (&error); /* FIXME don't raise here */
6676 MonoObject *context = mono_runtime_capture_context (domain);
6677 /* we must capture the execution context from the original thread */
6679 MONO_OBJECT_SETREF (res, execution_context, context);
6680 /* note: result may be null if the flow is suppressed */
6683 res->data = (void **)data;
6684 MONO_OBJECT_SETREF (res, object_data, object_data);
6685 MONO_OBJECT_SETREF (res, async_state, state);
6687 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6689 res->sync_completed = FALSE;
6690 res->completed = FALSE;
6696 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6698 MONO_REQ_GC_UNSAFE_MODE;
6705 g_assert (ares->async_delegate);
6707 ac = (MonoAsyncCall*) ares->object_data;
6709 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6711 gpointer wait_event = NULL;
6713 ac->msg->exc = NULL;
6714 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6715 MONO_OBJECT_SETREF (ac, res, res);
6717 mono_monitor_enter ((MonoObject*) ares);
6718 ares->completed = 1;
6720 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6721 mono_monitor_exit ((MonoObject*) ares);
6723 if (wait_event != NULL)
6724 SetEvent (wait_event);
6726 if (ac->cb_method) {
6727 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6728 mono_error_raise_exception (&error);
6736 mono_message_init (MonoDomain *domain,
6737 MonoMethodMessage *this_obj,
6738 MonoReflectionMethod *method,
6739 MonoArray *out_args)
6741 MONO_REQ_GC_UNSAFE_MODE;
6743 static MonoClass *object_array_klass;
6744 static MonoClass *byte_array_klass;
6745 static MonoClass *string_array_klass;
6747 MonoMethodSignature *sig = mono_method_signature (method->method);
6754 if (!object_array_klass) {
6757 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6759 byte_array_klass = klass;
6761 klass = mono_array_class_get (mono_defaults.string_class, 1);
6763 string_array_klass = klass;
6765 klass = mono_array_class_get (mono_defaults.object_class, 1);
6768 mono_atomic_store_release (&object_array_klass, klass);
6771 MONO_OBJECT_SETREF (this_obj, method, method);
6773 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6774 mono_error_raise_exception (&error); /* FIXME don't raise here */
6776 MONO_OBJECT_SETREF (this_obj, args, arr);
6778 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6779 mono_error_raise_exception (&error); /* FIXME don't raise here */
6781 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6783 this_obj->async_result = NULL;
6784 this_obj->call_type = CallType_Sync;
6786 names = g_new (char *, sig->param_count);
6787 mono_method_get_param_names (method->method, (const char **) names);
6789 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6790 mono_error_raise_exception (&error); /* FIXME don't raise here */
6792 MONO_OBJECT_SETREF (this_obj, names, arr);
6794 for (i = 0; i < sig->param_count; i++) {
6795 name = mono_string_new (domain, names [i]);
6796 mono_array_setref (this_obj->names, i, name);
6800 for (i = 0, j = 0; i < sig->param_count; i++) {
6801 if (sig->params [i]->byref) {
6803 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6804 mono_array_setref (this_obj->args, i, arg);
6808 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6812 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6815 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6819 #ifndef DISABLE_REMOTING
6821 * mono_remoting_invoke:
6822 * @real_proxy: pointer to a RealProxy object
6823 * @msg: The MonoMethodMessage to execute
6824 * @exc: used to store exceptions
6825 * @out_args: used to store output arguments
6827 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6828 * IMessage interface and it is not trivial to extract results from there. So
6829 * we call an helper method PrivateInvoke instead of calling
6830 * RealProxy::Invoke() directly.
6832 * Returns: the result object.
6835 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6836 MonoObject **exc, MonoArray **out_args)
6838 MONO_REQ_GC_UNSAFE_MODE;
6842 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6845 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6848 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6850 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6851 real_proxy->vtable->domain->private_invoke_method = im;
6854 pa [0] = real_proxy;
6860 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6862 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6864 mono_error_raise_exception (&error); /* FIXME don't raise here */
6871 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6872 MonoObject **exc, MonoArray **out_args)
6874 MONO_REQ_GC_UNSAFE_MODE;
6876 static MonoClass *object_array_klass;
6880 MonoMethodSignature *sig;
6883 int i, j, outarg_count = 0;
6885 #ifndef DISABLE_REMOTING
6886 if (target && mono_object_is_transparent_proxy (target)) {
6887 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6888 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6889 target = tp->rp->unwrapped_server;
6891 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6896 domain = mono_domain_get ();
6897 method = msg->method->method;
6898 sig = mono_method_signature (method);
6900 for (i = 0; i < sig->param_count; i++) {
6901 if (sig->params [i]->byref)
6905 if (!object_array_klass) {
6908 klass = mono_array_class_get (mono_defaults.object_class, 1);
6911 mono_memory_barrier ();
6912 object_array_klass = klass;
6915 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6916 mono_error_raise_exception (&error); /* FIXME don't raise here */
6918 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6921 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6923 for (i = 0, j = 0; i < sig->param_count; i++) {
6924 if (sig->params [i]->byref) {
6926 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6927 mono_array_setref (*out_args, j, arg);
6936 * mono_object_to_string:
6938 * @exc: Any exception thrown by ToString (). May be NULL.
6940 * Returns: the result of calling ToString () on an object.
6943 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6945 MONO_REQ_GC_UNSAFE_MODE;
6947 static MonoMethod *to_string = NULL;
6956 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6958 method = mono_object_get_virtual_method (obj, to_string);
6960 // Unbox value type if needed
6961 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6962 target = mono_object_unbox (obj);
6966 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6967 if (*exc == NULL && !mono_error_ok (&error))
6968 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6970 mono_error_cleanup (&error);
6972 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6973 mono_error_raise_exception (&error); /* FIXME don't raise here */
6980 * mono_print_unhandled_exception:
6981 * @exc: The exception
6983 * Prints the unhandled exception.
6986 mono_print_unhandled_exception (MonoObject *exc)
6988 MONO_REQ_GC_UNSAFE_MODE;
6991 char *message = (char*)"";
6992 gboolean free_message = FALSE;
6995 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6996 message = g_strdup ("OutOfMemoryException");
6997 free_message = TRUE;
6998 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6999 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7000 free_message = TRUE;
7003 if (((MonoException*)exc)->native_trace_ips) {
7004 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7005 free_message = TRUE;
7007 MonoObject *other_exc = NULL;
7008 str = mono_object_to_string (exc, &other_exc);
7010 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7011 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7013 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7014 original_backtrace, nested_backtrace);
7016 g_free (original_backtrace);
7017 g_free (nested_backtrace);
7018 free_message = TRUE;
7020 message = mono_string_to_utf8_checked (str, &error);
7021 if (!mono_error_ok (&error)) {
7022 mono_error_cleanup (&error);
7023 message = (char *) "";
7025 free_message = TRUE;
7032 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7033 * exc->vtable->klass->name, message);
7035 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7042 * mono_delegate_ctor:
7043 * @this: pointer to an uninitialized delegate object
7044 * @target: target object
7045 * @addr: pointer to native code
7048 * Initialize a delegate and sets a specific method, not the one
7049 * associated with addr. This is useful when sharing generic code.
7050 * In that case addr will most probably not be associated with the
7051 * correct instantiation of the method.
7054 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7056 MONO_REQ_GC_UNSAFE_MODE;
7058 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7060 g_assert (this_obj);
7063 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7066 delegate->method = method;
7068 mono_stats.delegate_creations++;
7070 #ifndef DISABLE_REMOTING
7071 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7073 method = mono_marshal_get_remoting_invoke (method);
7074 delegate->method_ptr = mono_compile_method (method);
7075 MONO_OBJECT_SETREF (delegate, target, target);
7079 delegate->method_ptr = addr;
7080 MONO_OBJECT_SETREF (delegate, target, target);
7083 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7084 if (callbacks.init_delegate)
7085 callbacks.init_delegate (delegate);
7089 * mono_delegate_ctor:
7090 * @this: pointer to an uninitialized delegate object
7091 * @target: target object
7092 * @addr: pointer to native code
7094 * This is used to initialize a delegate.
7097 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7099 MONO_REQ_GC_UNSAFE_MODE;
7101 MonoDomain *domain = mono_domain_get ();
7103 MonoMethod *method = NULL;
7107 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7109 if (!ji && domain != mono_get_root_domain ())
7110 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7112 method = mono_jit_info_get_method (ji);
7113 g_assert (!method->klass->generic_container);
7116 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7120 * mono_method_call_message_new:
7121 * @method: method to encapsulate
7122 * @params: parameters to the method
7123 * @invoke: optional, delegate invoke.
7124 * @cb: async callback delegate.
7125 * @state: state passed to the async callback.
7127 * Translates arguments pointers into a MonoMethodMessage.
7130 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7131 MonoDelegate **cb, MonoObject **state)
7133 MONO_REQ_GC_UNSAFE_MODE;
7137 MonoDomain *domain = mono_domain_get ();
7138 MonoMethodSignature *sig = mono_method_signature (method);
7139 MonoMethodMessage *msg;
7142 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7143 mono_error_raise_exception (&error); /* FIXME don't raise here */
7146 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7147 mono_error_raise_exception (&error); /* FIXME don't raise here */
7148 mono_message_init (domain, msg, rm, NULL);
7149 count = sig->param_count - 2;
7151 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7152 mono_error_raise_exception (&error); /* FIXME don't raise here */
7153 mono_message_init (domain, msg, rm, NULL);
7154 count = sig->param_count;
7157 for (i = 0; i < count; i++) {
7162 if (sig->params [i]->byref)
7163 vpos = *((gpointer *)params [i]);
7167 klass = mono_class_from_mono_type (sig->params [i]);
7169 if (klass->valuetype)
7170 arg = mono_value_box (domain, klass, vpos);
7172 arg = *((MonoObject **)vpos);
7174 mono_array_setref (msg->args, i, arg);
7177 if (cb != NULL && state != NULL) {
7178 *cb = *((MonoDelegate **)params [i]);
7180 *state = *((MonoObject **)params [i]);
7187 * mono_method_return_message_restore:
7189 * Restore results from message based processing back to arguments pointers
7192 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7194 MONO_REQ_GC_UNSAFE_MODE;
7196 MonoMethodSignature *sig = mono_method_signature (method);
7197 int i, j, type, size, out_len;
7199 if (out_args == NULL)
7201 out_len = mono_array_length (out_args);
7205 for (i = 0, j = 0; i < sig->param_count; i++) {
7206 MonoType *pt = sig->params [i];
7211 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7213 arg = (char *)mono_array_get (out_args, gpointer, j);
7216 g_assert (type != MONO_TYPE_VOID);
7218 if (MONO_TYPE_IS_REFERENCE (pt)) {
7219 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7222 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7223 size = mono_class_value_size (klass, NULL);
7224 if (klass->has_references)
7225 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7227 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7229 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7230 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7239 #ifndef DISABLE_REMOTING
7242 * mono_load_remote_field:
7243 * @this: pointer to an object
7244 * @klass: klass of the object containing @field
7245 * @field: the field to load
7246 * @res: a storage to store the result
7248 * This method is called by the runtime on attempts to load fields of
7249 * transparent proxy objects. @this points to such TP, @klass is the class of
7250 * the object containing @field. @res is a storage location which can be
7251 * used to store the result.
7253 * Returns: an address pointing to the value of field.
7256 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7258 MONO_REQ_GC_UNSAFE_MODE;
7262 static MonoMethod *getter = NULL;
7263 MonoDomain *domain = mono_domain_get ();
7264 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7265 MonoClass *field_class;
7266 MonoMethodMessage *msg;
7267 MonoArray *out_args;
7271 g_assert (mono_object_is_transparent_proxy (this_obj));
7272 g_assert (res != NULL);
7274 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7275 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7280 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7282 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7285 field_class = mono_class_from_mono_type (field->type);
7287 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7288 mono_error_raise_exception (&error); /* FIXME don't raise here */
7289 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7290 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7291 mono_error_raise_exception (&error); /* FIXME don't raise here */
7292 mono_message_init (domain, msg, rm, out_args);
7294 full_name = mono_type_get_full_name (klass);
7295 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7296 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7299 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7301 if (exc) mono_raise_exception ((MonoException *)exc);
7303 if (mono_array_length (out_args) == 0)
7306 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7308 if (field_class->valuetype) {
7309 return ((char *)*res) + sizeof (MonoObject);
7315 * mono_load_remote_field_new:
7320 * Missing documentation.
7323 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7325 MONO_REQ_GC_UNSAFE_MODE;
7329 static MonoMethod *getter = NULL;
7330 MonoDomain *domain = mono_domain_get ();
7331 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7332 MonoClass *field_class;
7333 MonoMethodMessage *msg;
7334 MonoArray *out_args;
7335 MonoObject *exc, *res;
7338 g_assert (mono_object_is_transparent_proxy (this_obj));
7340 field_class = mono_class_from_mono_type (field->type);
7342 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7344 if (field_class->valuetype) {
7345 res = mono_object_new_checked (domain, field_class, &error);
7346 mono_error_raise_exception (&error); /* FIXME don't raise here */
7347 val = ((gchar *) res) + sizeof (MonoObject);
7351 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7356 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7358 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7361 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7362 mono_error_raise_exception (&error); /* FIXME don't raise here */
7363 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7365 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7366 mono_error_raise_exception (&error); /* FIXME don't raise here */
7367 mono_message_init (domain, msg, rm, out_args);
7369 full_name = mono_type_get_full_name (klass);
7370 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7371 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7374 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7376 if (exc) mono_raise_exception ((MonoException *)exc);
7378 if (mono_array_length (out_args) == 0)
7381 res = mono_array_get (out_args, MonoObject *, 0);
7387 * mono_store_remote_field:
7388 * @this_obj: pointer to an object
7389 * @klass: klass of the object containing @field
7390 * @field: the field to load
7391 * @val: the value/object to store
7393 * This method is called by the runtime on attempts to store fields of
7394 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7395 * the object containing @field. @val is the new value to store in @field.
7398 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7400 MONO_REQ_GC_UNSAFE_MODE;
7404 static MonoMethod *setter = NULL;
7405 MonoDomain *domain = mono_domain_get ();
7406 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7407 MonoClass *field_class;
7408 MonoMethodMessage *msg;
7409 MonoArray *out_args;
7414 g_assert (mono_object_is_transparent_proxy (this_obj));
7416 field_class = mono_class_from_mono_type (field->type);
7418 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7419 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7420 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7425 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7427 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7430 if (field_class->valuetype)
7431 arg = mono_value_box (domain, field_class, val);
7433 arg = *((MonoObject **)val);
7436 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7437 mono_error_raise_exception (&error); /* FIXME don't raise here */
7438 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7439 mono_error_raise_exception (&error); /* FIXME don't raise here */
7440 mono_message_init (domain, msg, rm, NULL);
7442 full_name = mono_type_get_full_name (klass);
7443 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7444 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7445 mono_array_setref (msg->args, 2, arg);
7448 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7450 if (exc) mono_raise_exception ((MonoException *)exc);
7454 * mono_store_remote_field_new:
7460 * Missing documentation
7463 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7465 MONO_REQ_GC_UNSAFE_MODE;
7469 static MonoMethod *setter = NULL;
7470 MonoDomain *domain = mono_domain_get ();
7471 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7472 MonoClass *field_class;
7473 MonoMethodMessage *msg;
7474 MonoArray *out_args;
7478 g_assert (mono_object_is_transparent_proxy (this_obj));
7480 field_class = mono_class_from_mono_type (field->type);
7482 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7483 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7484 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7489 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7491 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7494 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7495 mono_error_raise_exception (&error); /* FIXME don't raise here */
7496 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7497 mono_error_raise_exception (&error); /* FIXME don't raise here */
7498 mono_message_init (domain, msg, rm, NULL);
7500 full_name = mono_type_get_full_name (klass);
7501 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7502 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7503 mono_array_setref (msg->args, 2, arg);
7506 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7508 if (exc) mono_raise_exception ((MonoException *)exc);
7513 * mono_create_ftnptr:
7515 * Given a function address, create a function descriptor for it.
7516 * This is only needed on some platforms.
7519 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7521 return callbacks.create_ftnptr (domain, addr);
7525 * mono_get_addr_from_ftnptr:
7527 * Given a pointer to a function descriptor, return the function address.
7528 * This is only needed on some platforms.
7531 mono_get_addr_from_ftnptr (gpointer descr)
7533 return callbacks.get_addr_from_ftnptr (descr);
7537 * mono_string_chars:
7540 * Returns a pointer to the UCS16 characters stored in the MonoString
7543 mono_string_chars (MonoString *s)
7545 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7551 * mono_string_length:
7554 * Returns the lenght in characters of the string
7557 mono_string_length (MonoString *s)
7559 MONO_REQ_GC_UNSAFE_MODE;
7565 * mono_array_length:
7566 * @array: a MonoArray*
7568 * Returns the total number of elements in the array. This works for
7569 * both vectors and multidimensional arrays.
7572 mono_array_length (MonoArray *array)
7574 MONO_REQ_GC_UNSAFE_MODE;
7576 return array->max_length;
7580 * mono_array_addr_with_size:
7581 * @array: a MonoArray*
7582 * @size: size of the array elements
7583 * @idx: index into the array
7585 * Use this function to obtain the address for the @idx item on the
7586 * @array containing elements of size @size.
7588 * This method performs no bounds checking or type checking.
7590 * Returns the address of the @idx element in the array.
7593 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7595 MONO_REQ_GC_UNSAFE_MODE;
7597 return ((char*)(array)->vector) + size * idx;
7602 mono_glist_to_array (GList *list, MonoClass *eclass)
7604 MonoDomain *domain = mono_domain_get ();
7611 len = g_list_length (list);
7612 res = mono_array_new (domain, eclass, len);
7614 for (i = 0; list; list = list->next, i++)
7615 mono_array_set (res, gpointer, i, list->data);
7622 * The following section is purely to declare prototypes and
7623 * document the API, as these C files are processed by our
7629 * @array: array to alter
7630 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7631 * @index: index into the array
7632 * @value: value to set
7634 * Value Type version: This sets the @index's element of the @array
7635 * with elements of size sizeof(type) to the provided @value.
7637 * This macro does not attempt to perform type checking or bounds checking.
7639 * Use this to set value types in a `MonoArray`.
7641 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7646 * mono_array_setref:
7647 * @array: array to alter
7648 * @index: index into the array
7649 * @value: value to set
7651 * Reference Type version: This sets the @index's element of the
7652 * @array with elements of size sizeof(type) to the provided @value.
7654 * This macro does not attempt to perform type checking or bounds checking.
7656 * Use this to reference types in a `MonoArray`.
7658 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7664 * @array: array on which to operate on
7665 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7666 * @index: index into the array
7668 * Use this macro to retrieve the @index element of an @array and
7669 * extract the value assuming that the elements of the array match
7670 * the provided type value.
7672 * This method can be used with both arrays holding value types and
7673 * reference types. For reference types, the @type parameter should
7674 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7676 * This macro does not attempt to perform type checking or bounds checking.
7678 * Returns: The element at the @index position in the @array.
7680 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)