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 MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
543 static MonoImtThunkBuilder imt_thunk_builder;
544 static gboolean always_build_imt_thunks;
546 #if (MONO_IMT_SIZE > 32)
547 #error "MONO_IMT_SIZE cannot be larger than 32"
551 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
553 memcpy (&callbacks, cbs, sizeof (*cbs));
556 MonoRuntimeCallbacks*
557 mono_get_runtime_callbacks (void)
562 #ifndef DISABLE_REMOTING
564 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
566 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
571 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
573 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
577 mono_install_imt_thunk_builder (MonoImtThunkBuilder func) {
578 imt_thunk_builder = func;
582 mono_set_always_build_imt_thunks (gboolean value)
584 always_build_imt_thunks = value;
588 * mono_compile_method:
589 * @method: The method to compile.
591 * This JIT-compiles the method, and returns the pointer to the native code
595 mono_compile_method (MonoMethod *method)
600 MONO_REQ_GC_NEUTRAL_MODE
602 if (!callbacks.compile_method) {
603 g_error ("compile method called on uninitialized runtime");
606 res = callbacks.compile_method (method, &error);
607 if (!mono_error_ok (&error))
608 mono_error_raise_exception (&error);
613 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper)
618 MONO_REQ_GC_NEUTRAL_MODE;
620 res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, &error);
621 if (!mono_error_ok (&error))
622 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
627 mono_runtime_create_delegate_trampoline (MonoClass *klass)
629 MONO_REQ_GC_NEUTRAL_MODE
631 return arch_create_delegate_trampoline (mono_domain_get (), klass);
634 static MonoFreeMethodFunc default_mono_free_method = NULL;
637 * mono_install_free_method:
638 * @func: pointer to the MonoFreeMethodFunc used to release a method
640 * This is an internal VM routine, it is used for the engines to
641 * register a handler to release the resources associated with a method.
643 * Methods are freed when no more references to the delegate that holds
647 mono_install_free_method (MonoFreeMethodFunc func)
649 default_mono_free_method = func;
653 * mono_runtime_free_method:
654 * @domain; domain where the method is hosted
655 * @method: method to release
657 * This routine is invoked to free the resources associated with
658 * a method that has been JIT compiled. This is used to discard
659 * methods that were used only temporarily (for example, used in marshalling)
663 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
665 MONO_REQ_GC_NEUTRAL_MODE
667 if (default_mono_free_method != NULL)
668 default_mono_free_method (domain, method);
670 mono_method_clear_object (domain, method);
672 mono_free_method (method);
676 * The vtables in the root appdomain are assumed to be reachable by other
677 * roots, and we don't use typed allocation in the other domains.
680 /* The sync block is no longer a GC pointer */
681 #define GC_HEADER_BITMAP (0)
683 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
686 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
688 MONO_REQ_GC_NEUTRAL_MODE;
690 MonoClassField *field;
696 max_size = mono_class_data_size (klass) / sizeof (gpointer);
698 max_size = klass->instance_size / sizeof (gpointer);
699 if (max_size > size) {
700 g_assert (offset <= 0);
701 bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
706 /*An Ephemeron cannot be marked by sgen*/
707 if (!static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
709 memset (bitmap, 0, size / 8);
714 for (p = klass; p != NULL; p = p->parent) {
715 gpointer iter = NULL;
716 while ((field = mono_class_get_fields (p, &iter))) {
720 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
722 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
725 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
728 /* FIXME: should not happen, flag as type load error */
729 if (field->type->byref)
732 if (static_fields && field->offset == -1)
736 pos = field->offset / sizeof (gpointer);
739 type = mono_type_get_underlying_type (field->type);
740 switch (type->type) {
743 case MONO_TYPE_FNPTR:
745 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
750 if (klass->image != mono_defaults.corlib)
753 case MONO_TYPE_STRING:
754 case MONO_TYPE_SZARRAY:
755 case MONO_TYPE_CLASS:
756 case MONO_TYPE_OBJECT:
757 case MONO_TYPE_ARRAY:
758 g_assert ((field->offset % sizeof(gpointer)) == 0);
760 g_assert (pos < size || pos <= max_size);
761 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
762 *max_set = MAX (*max_set, pos);
764 case MONO_TYPE_GENERICINST:
765 if (!mono_type_generic_inst_is_valuetype (type)) {
766 g_assert ((field->offset % sizeof(gpointer)) == 0);
768 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
769 *max_set = MAX (*max_set, pos);
774 case MONO_TYPE_VALUETYPE: {
775 MonoClass *fclass = mono_class_from_mono_type (field->type);
776 if (fclass->has_references) {
777 /* remove the object header */
778 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
792 case MONO_TYPE_BOOLEAN:
796 g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
807 * mono_class_compute_bitmap:
809 * Mono internal function to compute a bitmap of reference fields in a class.
812 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
814 MONO_REQ_GC_NEUTRAL_MODE;
816 return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
821 * similar to the above, but sets the bits in the bitmap for any non-ref field
822 * and ignores static fields
825 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
827 MonoClassField *field;
832 max_size = class->instance_size / sizeof (gpointer);
833 if (max_size >= size) {
834 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
837 for (p = class; p != NULL; p = p->parent) {
838 gpointer iter = NULL;
839 while ((field = mono_class_get_fields (p, &iter))) {
842 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
844 /* FIXME: should not happen, flag as type load error */
845 if (field->type->byref)
848 pos = field->offset / sizeof (gpointer);
851 type = mono_type_get_underlying_type (field->type);
852 switch (type->type) {
853 #if SIZEOF_VOID_P == 8
857 case MONO_TYPE_FNPTR:
862 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
863 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
864 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
867 #if SIZEOF_VOID_P == 4
871 case MONO_TYPE_FNPTR:
876 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
877 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
878 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
884 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
885 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
886 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
889 case MONO_TYPE_BOOLEAN:
892 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
894 case MONO_TYPE_STRING:
895 case MONO_TYPE_SZARRAY:
896 case MONO_TYPE_CLASS:
897 case MONO_TYPE_OBJECT:
898 case MONO_TYPE_ARRAY:
900 case MONO_TYPE_GENERICINST:
901 if (!mono_type_generic_inst_is_valuetype (type)) {
906 case MONO_TYPE_VALUETYPE: {
907 MonoClass *fclass = mono_class_from_mono_type (field->type);
908 /* remove the object header */
909 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
913 g_assert_not_reached ();
922 * mono_class_insecure_overlapping:
923 * check if a class with explicit layout has references and non-references
924 * fields overlapping.
926 * Returns: TRUE if it is insecure to load the type.
929 mono_class_insecure_overlapping (MonoClass *klass)
933 gsize default_bitmap [4] = {0};
935 gsize default_nrbitmap [4] = {0};
936 int i, insecure = FALSE;
939 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
940 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
942 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
943 int idx = i % (sizeof (bitmap [0]) * 8);
944 if (bitmap [idx] & nrbitmap [idx]) {
949 if (bitmap != default_bitmap)
951 if (nrbitmap != default_nrbitmap)
954 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
962 ves_icall_string_alloc (int length)
965 MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
966 mono_error_raise_exception (&error);
972 mono_class_compute_gc_descriptor (MonoClass *klass)
974 MONO_REQ_GC_NEUTRAL_MODE;
978 gsize default_bitmap [4] = {0};
979 static gboolean gcj_inited = FALSE;
984 mono_register_jit_icall (ves_icall_object_new_fast, "ves_icall_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
985 mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
988 mono_loader_unlock ();
992 mono_class_init (klass);
994 if (klass->gc_descr_inited)
997 klass->gc_descr_inited = TRUE;
998 klass->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1000 bitmap = default_bitmap;
1001 if (klass == mono_defaults.string_class) {
1002 klass->gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1003 } else if (klass->rank) {
1004 mono_class_compute_gc_descriptor (klass->element_class);
1005 if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1007 klass->gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1008 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1009 class->name_space, class->name);*/
1011 /* remove the object header */
1012 bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1013 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));
1014 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1015 class->name_space, class->name);*/
1016 if (bitmap != default_bitmap)
1020 /*static int count = 0;
1023 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1024 klass->gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1026 if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1027 g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1029 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1030 if (bitmap != default_bitmap)
1036 * field_is_special_static:
1037 * @fklass: The MonoClass to look up.
1038 * @field: The MonoClassField describing the field.
1040 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1041 * SPECIAL_STATIC_NONE otherwise.
1044 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1046 MONO_REQ_GC_NEUTRAL_MODE;
1048 MonoCustomAttrInfo *ainfo;
1050 ainfo = mono_custom_attrs_from_field (fklass, field);
1053 for (i = 0; i < ainfo->num_attrs; ++i) {
1054 MonoClass *klass = ainfo->attrs [i].ctor->klass;
1055 if (klass->image == mono_defaults.corlib) {
1056 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1057 mono_custom_attrs_free (ainfo);
1058 return SPECIAL_STATIC_THREAD;
1060 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1061 mono_custom_attrs_free (ainfo);
1062 return SPECIAL_STATIC_CONTEXT;
1066 mono_custom_attrs_free (ainfo);
1067 return SPECIAL_STATIC_NONE;
1070 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1071 #define mix(a,b,c) { \
1072 a -= c; a ^= rot(c, 4); c += b; \
1073 b -= a; b ^= rot(a, 6); a += c; \
1074 c -= b; c ^= rot(b, 8); b += a; \
1075 a -= c; a ^= rot(c,16); c += b; \
1076 b -= a; b ^= rot(a,19); a += c; \
1077 c -= b; c ^= rot(b, 4); b += a; \
1079 #define final(a,b,c) { \
1080 c ^= b; c -= rot(b,14); \
1081 a ^= c; a -= rot(c,11); \
1082 b ^= a; b -= rot(a,25); \
1083 c ^= b; c -= rot(b,16); \
1084 a ^= c; a -= rot(c,4); \
1085 b ^= a; b -= rot(a,14); \
1086 c ^= b; c -= rot(b,24); \
1090 * mono_method_get_imt_slot:
1092 * The IMT slot is embedded into AOTed code, so this must return the same value
1093 * for the same method across all executions. This means:
1094 * - pointers shouldn't be used as hash values.
1095 * - mono_metadata_str_hash () should be used for hashing strings.
1098 mono_method_get_imt_slot (MonoMethod *method)
1100 MONO_REQ_GC_NEUTRAL_MODE;
1102 MonoMethodSignature *sig;
1104 guint32 *hashes_start, *hashes;
1108 /* This can be used to stress tests the collision code */
1112 * We do this to simplify generic sharing. It will hurt
1113 * performance in cases where a class implements two different
1114 * instantiations of the same generic interface.
1115 * The code in build_imt_slots () depends on this.
1117 if (method->is_inflated)
1118 method = ((MonoMethodInflated*)method)->declaring;
1120 sig = mono_method_signature (method);
1121 hashes_count = sig->param_count + 4;
1122 hashes_start = (guint32 *)malloc (hashes_count * sizeof (guint32));
1123 hashes = hashes_start;
1125 if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1126 g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1127 method->klass->name_space, method->klass->name, method->name);
1130 /* Initialize hashes */
1131 hashes [0] = mono_metadata_str_hash (method->klass->name);
1132 hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1133 hashes [2] = mono_metadata_str_hash (method->name);
1134 hashes [3] = mono_metadata_type_hash (sig->ret);
1135 for (i = 0; i < sig->param_count; i++) {
1136 hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1139 /* Setup internal state */
1140 a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1142 /* Handle most of the hashes */
1143 while (hashes_count > 3) {
1152 /* Handle the last 3 hashes (all the case statements fall through) */
1153 switch (hashes_count) {
1154 case 3 : c += hashes [2];
1155 case 2 : b += hashes [1];
1156 case 1 : a += hashes [0];
1158 case 0: /* nothing left to add */
1162 free (hashes_start);
1163 /* Report the result */
1164 return c % MONO_IMT_SIZE;
1173 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1174 MONO_REQ_GC_NEUTRAL_MODE;
1176 guint32 imt_slot = mono_method_get_imt_slot (method);
1177 MonoImtBuilderEntry *entry;
1179 if (slot_num >= 0 && imt_slot != slot_num) {
1180 /* we build just a single imt slot and this is not it */
1184 entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1185 entry->key = method;
1186 entry->value.vtable_slot = vtable_slot;
1187 entry->next = imt_builder [imt_slot];
1188 if (imt_builder [imt_slot] != NULL) {
1189 entry->children = imt_builder [imt_slot]->children + 1;
1190 if (entry->children == 1) {
1191 mono_stats.imt_slots_with_collisions++;
1192 *imt_collisions_bitmap |= (1 << imt_slot);
1195 entry->children = 0;
1196 mono_stats.imt_used_slots++;
1198 imt_builder [imt_slot] = entry;
1201 char *method_name = mono_method_full_name (method, TRUE);
1202 printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1203 method, method_name, imt_slot, vtable_slot, entry->children);
1204 g_free (method_name);
1211 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1213 MonoMethod *method = e->key;
1214 printf (" * %s [%d]: (%p) '%s.%s.%s'\n",
1218 method->klass->name_space,
1219 method->klass->name,
1222 printf (" * %s: NULL\n", message);
1228 compare_imt_builder_entries (const void *p1, const void *p2) {
1229 MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1230 MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1232 return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1236 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1238 MONO_REQ_GC_NEUTRAL_MODE;
1240 int count = end - start;
1241 int chunk_start = out_array->len;
1244 for (i = start; i < end; ++i) {
1245 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1246 item->key = sorted_array [i]->key;
1247 item->value = sorted_array [i]->value;
1248 item->has_target_code = sorted_array [i]->has_target_code;
1249 item->is_equals = TRUE;
1251 item->check_target_idx = out_array->len + 1;
1253 item->check_target_idx = 0;
1254 g_ptr_array_add (out_array, item);
1257 int middle = start + count / 2;
1258 MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1260 item->key = sorted_array [middle]->key;
1261 item->is_equals = FALSE;
1262 g_ptr_array_add (out_array, item);
1263 imt_emit_ir (sorted_array, start, middle, out_array);
1264 item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1270 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1271 MONO_REQ_GC_NEUTRAL_MODE;
1273 int number_of_entries = entries->children + 1;
1274 MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1275 GPtrArray *result = g_ptr_array_new ();
1276 MonoImtBuilderEntry *current_entry;
1279 for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1280 sorted_array [i] = current_entry;
1282 qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1284 /*for (i = 0; i < number_of_entries; i++) {
1285 print_imt_entry (" sorted array:", sorted_array [i], i);
1288 imt_emit_ir (sorted_array, 0, number_of_entries, result);
1290 free (sorted_array);
1295 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1297 MONO_REQ_GC_NEUTRAL_MODE;
1299 if (imt_builder_entry != NULL) {
1300 if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_thunks) {
1301 /* No collision, return the vtable slot contents */
1302 return vtable->vtable [imt_builder_entry->value.vtable_slot];
1304 /* Collision, build the thunk */
1305 GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1308 result = imt_thunk_builder (vtable, domain,
1309 (MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1310 for (i = 0; i < imt_ir->len; ++i)
1311 g_free (g_ptr_array_index (imt_ir, i));
1312 g_ptr_array_free (imt_ir, TRUE);
1324 static MonoImtBuilderEntry*
1325 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1328 * LOCKING: requires the loader and domain locks.
1332 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1334 MONO_REQ_GC_NEUTRAL_MODE;
1338 guint32 imt_collisions_bitmap = 0;
1339 MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1340 int method_count = 0;
1341 gboolean record_method_count_for_max_collisions = FALSE;
1342 gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1345 printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1347 for (i = 0; i < klass->interface_offsets_count; ++i) {
1348 MonoClass *iface = klass->interfaces_packed [i];
1349 int interface_offset = klass->interface_offsets_packed [i];
1350 int method_slot_in_interface, vt_slot;
1352 if (mono_class_has_variant_generic_params (iface))
1353 has_variant_iface = TRUE;
1355 mono_class_setup_methods (iface);
1356 vt_slot = interface_offset;
1357 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1360 if (slot_num >= 0 && iface->is_inflated) {
1362 * The imt slot of the method is the same as for its declaring method,
1363 * see the comment in mono_method_get_imt_slot (), so we can
1364 * avoid inflating methods which will be discarded by
1365 * add_imt_builder_entry anyway.
1367 method = mono_class_get_method_by_index (iface->generic_class->container_class, method_slot_in_interface);
1368 if (mono_method_get_imt_slot (method) != slot_num) {
1373 method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1374 if (method->is_generic) {
1375 has_generic_virtual = TRUE;
1380 if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1381 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1386 if (extra_interfaces) {
1387 int interface_offset = klass->vtable_size;
1389 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1390 MonoClass* iface = (MonoClass *)list_item->data;
1391 int method_slot_in_interface;
1392 for (method_slot_in_interface = 0; method_slot_in_interface < iface->method.count; method_slot_in_interface++) {
1393 MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1395 if (method->is_generic)
1396 has_generic_virtual = TRUE;
1397 add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1399 interface_offset += iface->method.count;
1402 for (i = 0; i < MONO_IMT_SIZE; ++i) {
1403 /* overwrite the imt slot only if we're building all the entries or if
1404 * we're building this specific one
1406 if (slot_num < 0 || i == slot_num) {
1407 MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1410 if (imt_builder [i]) {
1411 MonoImtBuilderEntry *entry;
1413 /* Link entries with imt_builder [i] */
1414 for (entry = entries; entry->next; entry = entry->next) {
1416 MonoMethod *method = (MonoMethod*)entry->key;
1417 char *method_name = mono_method_full_name (method, TRUE);
1418 printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1419 g_free (method_name);
1422 entry->next = imt_builder [i];
1423 entries->children += imt_builder [i]->children + 1;
1425 imt_builder [i] = entries;
1428 if (has_generic_virtual || has_variant_iface) {
1430 * There might be collisions later when the the thunk is expanded.
1432 imt_collisions_bitmap |= (1 << i);
1435 * The IMT thunk might be called with an instance of one of the
1436 * generic virtual methods, so has to fallback to the IMT trampoline.
1438 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1440 imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1443 printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1447 if (imt_builder [i] != NULL) {
1448 int methods_in_slot = imt_builder [i]->children + 1;
1449 if (methods_in_slot > mono_stats.imt_max_collisions_in_slot) {
1450 mono_stats.imt_max_collisions_in_slot = methods_in_slot;
1451 record_method_count_for_max_collisions = TRUE;
1453 method_count += methods_in_slot;
1457 mono_stats.imt_number_of_methods += method_count;
1458 if (record_method_count_for_max_collisions) {
1459 mono_stats.imt_method_count_when_max_collisions = method_count;
1462 for (i = 0; i < MONO_IMT_SIZE; i++) {
1463 MonoImtBuilderEntry* entry = imt_builder [i];
1464 while (entry != NULL) {
1465 MonoImtBuilderEntry* next = entry->next;
1471 /* we OR the bitmap since we may build just a single imt slot at a time */
1472 vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1476 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1477 MONO_REQ_GC_NEUTRAL_MODE;
1479 build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1483 * mono_vtable_build_imt_slot:
1484 * @vtable: virtual object table struct
1485 * @imt_slot: slot in the IMT table
1487 * Fill the given @imt_slot in the IMT table of @vtable with
1488 * a trampoline or a thunk for the case of collisions.
1489 * This is part of the internal mono API.
1491 * LOCKING: Take the domain lock.
1494 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1496 MONO_REQ_GC_NEUTRAL_MODE;
1498 gpointer *imt = (gpointer*)vtable;
1499 imt -= MONO_IMT_SIZE;
1500 g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1502 /* no support for extra interfaces: the proxy objects will need
1503 * to build the complete IMT
1504 * Update and heck needs to ahppen inside the proper domain lock, as all
1505 * the changes made to a MonoVTable.
1507 mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1508 mono_domain_lock (vtable->domain);
1509 /* we change the slot only if it wasn't changed from the generic imt trampoline already */
1510 if (!callbacks.imt_entry_inited (vtable, imt_slot))
1511 build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1512 mono_domain_unlock (vtable->domain);
1513 mono_loader_unlock ();
1518 * The first two free list entries both belong to the wait list: The
1519 * first entry is the pointer to the head of the list and the second
1520 * entry points to the last element. That way appending and removing
1521 * the first element are both O(1) operations.
1523 #ifdef MONO_SMALL_CONFIG
1524 #define NUM_FREE_LISTS 6
1526 #define NUM_FREE_LISTS 12
1528 #define FIRST_FREE_LIST_SIZE 64
1529 #define MAX_WAIT_LENGTH 50
1530 #define THUNK_THRESHOLD 10
1533 * LOCKING: The domain lock must be held.
1536 init_thunk_free_lists (MonoDomain *domain)
1538 MONO_REQ_GC_NEUTRAL_MODE;
1540 if (domain->thunk_free_lists)
1542 domain->thunk_free_lists = (MonoThunkFreeList **)mono_domain_alloc0 (domain, sizeof (gpointer) * NUM_FREE_LISTS);
1546 list_index_for_size (int item_size)
1549 int size = FIRST_FREE_LIST_SIZE;
1551 while (item_size > size && i < NUM_FREE_LISTS - 1) {
1560 * mono_method_alloc_generic_virtual_thunk:
1562 * @size: size in bytes
1564 * Allocs size bytes to be used for the code of a generic virtual
1565 * thunk. It's either allocated from the domain's code manager or
1566 * reused from a previously invalidated piece.
1568 * LOCKING: The domain lock must be held.
1571 mono_method_alloc_generic_virtual_thunk (MonoDomain *domain, int size)
1573 MONO_REQ_GC_NEUTRAL_MODE;
1575 static gboolean inited = FALSE;
1576 static int generic_virtual_thunks_size = 0;
1580 MonoThunkFreeList **l;
1582 init_thunk_free_lists (domain);
1584 size += sizeof (guint32);
1585 if (size < sizeof (MonoThunkFreeList))
1586 size = sizeof (MonoThunkFreeList);
1588 i = list_index_for_size (size);
1589 for (l = &domain->thunk_free_lists [i]; *l; l = &(*l)->next) {
1590 if ((*l)->size >= size) {
1591 MonoThunkFreeList *item = *l;
1593 return ((guint32*)item) + 1;
1597 /* no suitable item found - search lists of larger sizes */
1598 while (++i < NUM_FREE_LISTS) {
1599 MonoThunkFreeList *item = domain->thunk_free_lists [i];
1602 g_assert (item->size > size);
1603 domain->thunk_free_lists [i] = item->next;
1604 return ((guint32*)item) + 1;
1607 /* still nothing found - allocate it */
1609 mono_counters_register ("Generic virtual thunk bytes",
1610 MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_thunks_size);
1613 generic_virtual_thunks_size += size;
1615 p = (guint32 *)mono_domain_code_reserve (domain, size);
1618 mono_domain_lock (domain);
1619 if (!domain->generic_virtual_thunks)
1620 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1621 g_hash_table_insert (domain->generic_virtual_thunks, p, p);
1622 mono_domain_unlock (domain);
1628 * LOCKING: The domain lock must be held.
1631 invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
1633 MONO_REQ_GC_NEUTRAL_MODE;
1635 guint32 *p = (guint32 *)code;
1636 MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
1637 gboolean found = FALSE;
1639 mono_domain_lock (domain);
1640 if (!domain->generic_virtual_thunks)
1641 domain->generic_virtual_thunks = g_hash_table_new (NULL, NULL);
1642 if (g_hash_table_lookup (domain->generic_virtual_thunks, l))
1644 mono_domain_unlock (domain);
1647 /* Not allocated by mono_method_alloc_generic_virtual_thunk (), i.e. AOT */
1649 init_thunk_free_lists (domain);
1651 while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
1652 MonoThunkFreeList *item = domain->thunk_free_lists [0];
1653 int length = item->length;
1656 /* unlink the first item from the wait list */
1657 domain->thunk_free_lists [0] = item->next;
1658 domain->thunk_free_lists [0]->length = length - 1;
1660 i = list_index_for_size (item->size);
1662 /* put it in the free list */
1663 item->next = domain->thunk_free_lists [i];
1664 domain->thunk_free_lists [i] = item;
1668 if (domain->thunk_free_lists [1]) {
1669 domain->thunk_free_lists [1] = domain->thunk_free_lists [1]->next = l;
1670 domain->thunk_free_lists [0]->length++;
1672 g_assert (!domain->thunk_free_lists [0]);
1674 domain->thunk_free_lists [0] = domain->thunk_free_lists [1] = l;
1675 domain->thunk_free_lists [0]->length = 1;
1679 typedef struct _GenericVirtualCase {
1683 struct _GenericVirtualCase *next;
1684 } GenericVirtualCase;
1687 * get_generic_virtual_entries:
1689 * Return IMT entries for the generic virtual method instances and
1690 * variant interface methods for vtable slot
1693 static MonoImtBuilderEntry*
1694 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1696 MONO_REQ_GC_NEUTRAL_MODE;
1698 GenericVirtualCase *list;
1699 MonoImtBuilderEntry *entries;
1701 mono_domain_lock (domain);
1702 if (!domain->generic_virtual_cases)
1703 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1705 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1708 for (; list; list = list->next) {
1709 MonoImtBuilderEntry *entry;
1711 if (list->count < THUNK_THRESHOLD)
1714 entry = g_new0 (MonoImtBuilderEntry, 1);
1715 entry->key = list->method;
1716 entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1717 entry->has_target_code = 1;
1719 entry->children = entries->children + 1;
1720 entry->next = entries;
1724 mono_domain_unlock (domain);
1726 /* FIXME: Leaking memory ? */
1731 * mono_method_add_generic_virtual_invocation:
1733 * @vtable_slot: pointer to the vtable slot
1734 * @method: the inflated generic virtual method
1735 * @code: the method's code
1737 * Registers a call via unmanaged code to a generic virtual method
1738 * instantiation or variant interface method. If the number of calls reaches a threshold
1739 * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1740 * virtual method thunk.
1743 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1744 gpointer *vtable_slot,
1745 MonoMethod *method, gpointer code)
1747 MONO_REQ_GC_NEUTRAL_MODE;
1749 static gboolean inited = FALSE;
1750 static int num_added = 0;
1752 GenericVirtualCase *gvc, *list;
1753 MonoImtBuilderEntry *entries;
1757 mono_domain_lock (domain);
1758 if (!domain->generic_virtual_cases)
1759 domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1761 /* Check whether the case was already added */
1762 list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1765 if (gvc->method == method)
1770 /* If not found, make a new one */
1772 gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1773 gvc->method = method;
1776 gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1778 g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1781 mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1787 if (++gvc->count == THUNK_THRESHOLD) {
1788 gpointer *old_thunk = (void **)*vtable_slot;
1789 gpointer vtable_trampoline = NULL;
1790 gpointer imt_trampoline = NULL;
1792 if ((gpointer)vtable_slot < (gpointer)vtable) {
1793 int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1794 int imt_slot = MONO_IMT_SIZE + displacement;
1796 /* Force the rebuild of the thunk at the next call */
1797 imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1798 *vtable_slot = imt_trampoline;
1800 vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1802 entries = get_generic_virtual_entries (domain, vtable_slot);
1804 sorted = imt_sort_slot_entries (entries);
1806 *vtable_slot = imt_thunk_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1810 MonoImtBuilderEntry *next = entries->next;
1815 for (i = 0; i < sorted->len; ++i)
1816 g_free (g_ptr_array_index (sorted, i));
1817 g_ptr_array_free (sorted, TRUE);
1820 #ifndef __native_client__
1821 /* We don't re-use any thunks as there is a lot of overhead */
1822 /* to deleting and re-using code in Native Client. */
1823 if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1824 invalidate_generic_virtual_thunk (domain, old_thunk);
1828 mono_domain_unlock (domain);
1831 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1834 * mono_class_vtable:
1835 * @domain: the application domain
1836 * @class: the class to initialize
1838 * VTables are domain specific because we create domain specific code, and
1839 * they contain the domain specific static class data.
1840 * On failure, NULL is returned, and class->exception_type is set.
1843 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1846 MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1847 mono_error_cleanup (&error);
1852 * mono_class_vtable_full:
1853 * @domain: the application domain
1854 * @class: the class to initialize
1855 * @error set on failure.
1857 * VTables are domain specific because we create domain specific code, and
1858 * they contain the domain specific static class data.
1861 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1863 MONO_REQ_GC_UNSAFE_MODE;
1865 MonoClassRuntimeInfo *runtime_info;
1867 mono_error_init (error);
1871 if (mono_class_has_failure (klass)) {
1872 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1876 /* this check can be inlined in jitted code, too */
1877 runtime_info = klass->runtime_info;
1878 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1879 return runtime_info->domain_vtables [domain->domain_id];
1880 return mono_class_create_runtime_vtable (domain, klass, error);
1884 * mono_class_try_get_vtable:
1885 * @domain: the application domain
1886 * @class: the class to initialize
1888 * This function tries to get the associated vtable from @class if
1889 * it was already created.
1892 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1894 MONO_REQ_GC_NEUTRAL_MODE;
1896 MonoClassRuntimeInfo *runtime_info;
1900 runtime_info = klass->runtime_info;
1901 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1902 return runtime_info->domain_vtables [domain->domain_id];
1907 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1909 MONO_REQ_GC_NEUTRAL_MODE;
1911 size_t alloc_offset;
1914 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1915 * address bits. The IMT has an odd number of entries, however, so on 32 bits the
1916 * alignment will be off. In that case we allocate 4 more bytes and skip over them.
1918 if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1919 g_assert ((imt_table_bytes & 7) == 4);
1926 return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1930 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1932 MONO_REQ_GC_UNSAFE_MODE;
1935 MonoClassRuntimeInfo *runtime_info, *old_info;
1936 MonoClassField *field;
1938 int i, vtable_slots;
1939 size_t imt_table_bytes;
1941 guint32 vtable_size, class_size;
1943 gpointer *interface_offsets;
1945 mono_error_init (error);
1947 mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1948 mono_domain_lock (domain);
1949 runtime_info = klass->runtime_info;
1950 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1951 mono_domain_unlock (domain);
1952 mono_loader_unlock ();
1953 return runtime_info->domain_vtables [domain->domain_id];
1955 if (!klass->inited || mono_class_has_failure (klass)) {
1956 if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1957 mono_domain_unlock (domain);
1958 mono_loader_unlock ();
1959 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1964 /* Array types require that their element type be valid*/
1965 if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1966 MonoClass *element_class = klass->element_class;
1967 if (!element_class->inited)
1968 mono_class_init (element_class);
1970 /*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1971 if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1972 mono_class_setup_vtable (element_class);
1974 if (mono_class_has_failure (element_class)) {
1975 /*Can happen if element_class only got bad after mono_class_setup_vtable*/
1976 if (!mono_class_has_failure (klass))
1977 mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
1978 mono_domain_unlock (domain);
1979 mono_loader_unlock ();
1980 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
1986 * For some classes, mono_class_init () already computed klass->vtable_size, and
1987 * that is all that is needed because of the vtable trampolines.
1989 if (!klass->vtable_size)
1990 mono_class_setup_vtable (klass);
1992 if (klass->generic_class && !klass->vtable)
1993 mono_class_check_vtable_constraints (klass, NULL);
1995 /* Initialize klass->has_finalize */
1996 mono_class_has_finalizer (klass);
1998 if (mono_class_has_failure (klass)) {
1999 mono_domain_unlock (domain);
2000 mono_loader_unlock ();
2001 mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (klass));
2005 vtable_slots = klass->vtable_size;
2006 /* we add an additional vtable slot to store the pointer to static field data only when needed */
2007 class_size = mono_class_data_size (klass);
2011 if (klass->interface_offsets_count) {
2012 imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
2013 mono_stats.imt_number_of_tables++;
2014 mono_stats.imt_tables_size += imt_table_bytes;
2016 imt_table_bytes = 0;
2019 vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
2021 mono_stats.used_class_count++;
2022 mono_stats.class_vtable_size += vtable_size;
2024 interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
2025 vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2026 g_assert (!((gsize)vt & 7));
2029 vt->rank = klass->rank;
2030 vt->domain = domain;
2032 mono_class_compute_gc_descriptor (klass);
2034 * We can't use typed allocation in the non-root domains, since the
2035 * collector needs the GC descriptor stored in the vtable even after
2036 * the mempool containing the vtable is destroyed when the domain is
2037 * unloaded. An alternative might be to allocate vtables in the GC
2038 * heap, but this does not seem to work (it leads to crashes inside
2039 * libgc). If that approach is tried, two gc descriptors need to be
2040 * allocated for each class: one for the root domain, and one for all
2041 * other domains. The second descriptor should contain a bit for the
2042 * vtable field in MonoObject, since we can no longer assume the
2043 * vtable is reachable by other roots after the appdomain is unloaded.
2045 #ifdef HAVE_BOEHM_GC
2046 if (domain != mono_get_root_domain () && !mono_dont_free_domains)
2047 vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
2050 vt->gc_descr = klass->gc_descr;
2052 gc_bits = mono_gc_get_vtable_bits (klass);
2053 g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
2055 vt->gc_bits = gc_bits;
2058 /* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
2059 if (klass->has_static_refs) {
2060 MonoGCDescriptor statics_gc_descr;
2062 gsize default_bitmap [4] = {0};
2065 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2066 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2067 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2068 vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2069 mono_domain_add_class_static_data (domain, klass, vt->vtable [klass->vtable_size], NULL);
2070 if (bitmap != default_bitmap)
2073 vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2075 vt->has_static_fields = TRUE;
2076 mono_stats.class_static_data_size += class_size;
2080 while ((field = mono_class_get_fields (klass, &iter))) {
2081 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2083 if (mono_field_is_deleted (field))
2085 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2086 gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2087 if (special_static != SPECIAL_STATIC_NONE) {
2088 guint32 size, offset;
2090 gsize default_bitmap [4] = {0};
2095 if (mono_type_is_reference (field->type)) {
2096 default_bitmap [0] = 1;
2098 bitmap = default_bitmap;
2099 } else if (mono_type_is_struct (field->type)) {
2100 fclass = mono_class_from_mono_type (field->type);
2101 bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2102 numbits = max_set + 1;
2104 default_bitmap [0] = 0;
2106 bitmap = default_bitmap;
2108 size = mono_type_size (field->type, &align);
2109 offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2110 if (!domain->special_static_fields)
2111 domain->special_static_fields = g_hash_table_new (NULL, NULL);
2112 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2113 if (bitmap != default_bitmap)
2116 * This marks the field as special static to speed up the
2117 * checks in mono_field_static_get/set_value ().
2123 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2124 MonoClass *fklass = mono_class_from_mono_type (field->type);
2125 const char *data = mono_field_get_data (field);
2127 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2128 t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2129 /* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2132 if (fklass->valuetype) {
2133 memcpy (t, data, mono_class_value_size (fklass, NULL));
2135 /* it's a pointer type: add check */
2136 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2143 vt->max_interface_id = klass->max_interface_id;
2144 vt->interface_bitmap = klass->interface_bitmap;
2146 //printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2147 // class->name, klass->interface_offsets_count);
2149 /* Initialize vtable */
2150 if (callbacks.get_vtable_trampoline) {
2151 // This also covers the AOT case
2152 for (i = 0; i < klass->vtable_size; ++i) {
2153 vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2156 mono_class_setup_vtable (klass);
2158 for (i = 0; i < klass->vtable_size; ++i) {
2161 cm = klass->vtable [i];
2163 vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2164 mono_error_raise_exception (error); /* FIXME: Don't raise here */
2169 if (imt_table_bytes) {
2170 /* Now that the vtable is full, we can actually fill up the IMT */
2171 for (i = 0; i < MONO_IMT_SIZE; ++i)
2172 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2176 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2177 * re-acquire them and check if another thread has created the vtable in the meantime.
2179 /* Special case System.MonoType to avoid infinite recursion */
2180 if (klass != mono_defaults.monotype_class) {
2181 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2182 if (!is_ok (error)) {
2183 mono_domain_unlock (domain);
2184 mono_loader_unlock ();
2188 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2189 /* This is unregistered in
2190 unregister_vtable_reflection_type() in
2192 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2195 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2197 /* class_vtable_array keeps an array of created vtables
2199 g_ptr_array_add (domain->class_vtable_array, vt);
2200 /* klass->runtime_info is protected by the loader lock, both when
2201 * it it enlarged and when it is stored info.
2205 * Store the vtable in klass->runtime_info.
2206 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2208 mono_memory_barrier ();
2210 old_info = klass->runtime_info;
2211 if (old_info && old_info->max_domain >= domain->domain_id) {
2212 /* someone already created a large enough runtime info */
2213 old_info->domain_vtables [domain->domain_id] = vt;
2215 int new_size = domain->domain_id;
2217 new_size = MAX (new_size, old_info->max_domain);
2219 /* make the new size a power of two */
2221 while (new_size > i)
2224 /* this is a bounded memory retention issue: may want to
2225 * handle it differently when we'll have a rcu-like system.
2227 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2228 runtime_info->max_domain = new_size - 1;
2229 /* copy the stuff from the older info */
2231 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2233 runtime_info->domain_vtables [domain->domain_id] = vt;
2235 mono_memory_barrier ();
2236 klass->runtime_info = runtime_info;
2239 if (klass == mono_defaults.monotype_class) {
2240 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2241 if (!is_ok (error)) {
2242 mono_domain_unlock (domain);
2243 mono_loader_unlock ();
2247 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2248 /* This is unregistered in
2249 unregister_vtable_reflection_type() in
2251 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2254 mono_domain_unlock (domain);
2255 mono_loader_unlock ();
2257 /* make sure the parent is initialized */
2258 /*FIXME shouldn't this fail the current type?*/
2260 mono_class_vtable_full (domain, klass->parent, error);
2265 #ifndef DISABLE_REMOTING
2267 * mono_class_proxy_vtable:
2268 * @domain: the application domain
2269 * @remove_class: the remote class
2271 * Creates a vtable for transparent proxies. It is basically
2272 * a copy of the real vtable of the class wrapped in @remote_class,
2273 * but all function pointers invoke the remoting functions, and
2274 * vtable->klass points to the transparent proxy class, and not to @class.
2277 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2279 MONO_REQ_GC_UNSAFE_MODE;
2282 MonoVTable *vt, *pvt;
2283 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2285 GSList *extra_interfaces = NULL;
2286 MonoClass *klass = remote_class->proxy_class;
2287 gpointer *interface_offsets;
2290 size_t imt_table_bytes;
2292 #ifdef COMPRESSED_INTERFACE_BITMAP
2296 vt = mono_class_vtable (domain, klass);
2297 g_assert (vt); /*FIXME property handle failure*/
2298 max_interface_id = vt->max_interface_id;
2300 /* Calculate vtable space for extra interfaces */
2301 for (j = 0; j < remote_class->interface_count; j++) {
2302 MonoClass* iclass = remote_class->interfaces[j];
2306 /*FIXME test for interfaces with variant generic arguments*/
2307 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2308 continue; /* interface implemented by the class */
2309 if (g_slist_find (extra_interfaces, iclass))
2312 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2314 method_count = mono_class_num_methods (iclass);
2316 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2317 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2319 for (i = 0; i < ifaces->len; ++i) {
2320 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2321 /*FIXME test for interfaces with variant generic arguments*/
2322 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2323 continue; /* interface implemented by the class */
2324 if (g_slist_find (extra_interfaces, ic))
2326 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2327 method_count += mono_class_num_methods (ic);
2329 g_ptr_array_free (ifaces, TRUE);
2332 extra_interface_vtsize += method_count * sizeof (gpointer);
2333 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2336 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2337 mono_stats.imt_number_of_tables++;
2338 mono_stats.imt_tables_size += imt_table_bytes;
2340 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2342 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2344 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2345 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2346 g_assert (!((gsize)pvt & 7));
2348 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2350 pvt->klass = mono_defaults.transparent_proxy_class;
2351 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2352 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2354 /* initialize vtable */
2355 mono_class_setup_vtable (klass);
2356 for (i = 0; i < klass->vtable_size; ++i) {
2359 if ((cm = klass->vtable [i]))
2360 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2362 pvt->vtable [i] = NULL;
2365 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2366 /* create trampolines for abstract methods */
2367 for (k = klass; k; k = k->parent) {
2369 gpointer iter = NULL;
2370 while ((m = mono_class_get_methods (k, &iter)))
2371 if (!pvt->vtable [m->slot])
2372 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2376 pvt->max_interface_id = max_interface_id;
2377 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2378 #ifdef COMPRESSED_INTERFACE_BITMAP
2379 bitmap = (uint8_t *)g_malloc0 (bsize);
2381 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2384 for (i = 0; i < klass->interface_offsets_count; ++i) {
2385 int interface_id = klass->interfaces_packed [i]->interface_id;
2386 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2389 if (extra_interfaces) {
2390 int slot = klass->vtable_size;
2396 /* Create trampolines for the methods of the interfaces */
2397 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2398 interf = (MonoClass *)list_item->data;
2400 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2404 while ((cm = mono_class_get_methods (interf, &iter)))
2405 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2407 slot += mono_class_num_methods (interf);
2411 /* Now that the vtable is full, we can actually fill up the IMT */
2412 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2413 if (extra_interfaces) {
2414 g_slist_free (extra_interfaces);
2417 #ifdef COMPRESSED_INTERFACE_BITMAP
2418 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2419 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2420 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2423 pvt->interface_bitmap = bitmap;
2428 #endif /* DISABLE_REMOTING */
2431 * mono_class_field_is_special_static:
2433 * Returns whether @field is a thread/context static field.
2436 mono_class_field_is_special_static (MonoClassField *field)
2438 MONO_REQ_GC_NEUTRAL_MODE
2440 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2442 if (mono_field_is_deleted (field))
2444 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2445 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2452 * mono_class_field_get_special_static_type:
2453 * @field: The MonoClassField describing the field.
2455 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2456 * SPECIAL_STATIC_NONE otherwise.
2459 mono_class_field_get_special_static_type (MonoClassField *field)
2461 MONO_REQ_GC_NEUTRAL_MODE
2463 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2464 return SPECIAL_STATIC_NONE;
2465 if (mono_field_is_deleted (field))
2466 return SPECIAL_STATIC_NONE;
2467 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2468 return field_is_special_static (field->parent, field);
2469 return SPECIAL_STATIC_NONE;
2473 * mono_class_has_special_static_fields:
2475 * Returns whenever @klass has any thread/context static fields.
2478 mono_class_has_special_static_fields (MonoClass *klass)
2480 MONO_REQ_GC_NEUTRAL_MODE
2482 MonoClassField *field;
2486 while ((field = mono_class_get_fields (klass, &iter))) {
2487 g_assert (field->parent == klass);
2488 if (mono_class_field_is_special_static (field))
2495 #ifndef DISABLE_REMOTING
2497 * create_remote_class_key:
2498 * Creates an array of pointers that can be used as a hash key for a remote class.
2499 * The first element of the array is the number of pointers.
2502 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2504 MONO_REQ_GC_NEUTRAL_MODE;
2509 if (remote_class == NULL) {
2510 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2511 key = (void **)g_malloc (sizeof(gpointer) * 3);
2512 key [0] = GINT_TO_POINTER (2);
2513 key [1] = mono_defaults.marshalbyrefobject_class;
2514 key [2] = extra_class;
2516 key = (void **)g_malloc (sizeof(gpointer) * 2);
2517 key [0] = GINT_TO_POINTER (1);
2518 key [1] = extra_class;
2521 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2522 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2523 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2524 key [1] = remote_class->proxy_class;
2526 // Keep the list of interfaces sorted
2527 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2528 if (extra_class && remote_class->interfaces [i] > extra_class) {
2529 key [j++] = extra_class;
2532 key [j] = remote_class->interfaces [i];
2535 key [j] = extra_class;
2537 // Replace the old class. The interface list is the same
2538 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2539 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2540 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2541 for (i = 0; i < remote_class->interface_count; i++)
2542 key [2 + i] = remote_class->interfaces [i];
2550 * copy_remote_class_key:
2552 * Make a copy of KEY in the domain and return the copy.
2555 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2557 MONO_REQ_GC_NEUTRAL_MODE
2559 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2560 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2562 memcpy (mp_key, key, key_size);
2568 * mono_remote_class:
2569 * @domain: the application domain
2570 * @class_name: name of the remote class
2572 * Creates and initializes a MonoRemoteClass object for a remote type.
2574 * Can raise an exception on failure.
2577 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2579 MONO_REQ_GC_UNSAFE_MODE;
2582 MonoRemoteClass *rc;
2583 gpointer* key, *mp_key;
2586 key = create_remote_class_key (NULL, proxy_class);
2588 mono_domain_lock (domain);
2589 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2593 mono_domain_unlock (domain);
2597 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2598 if (!mono_error_ok (&error)) {
2600 mono_domain_unlock (domain);
2601 mono_error_raise_exception (&error);
2604 mp_key = copy_remote_class_key (domain, key);
2608 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2609 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2610 rc->interface_count = 1;
2611 rc->interfaces [0] = proxy_class;
2612 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2614 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2615 rc->interface_count = 0;
2616 rc->proxy_class = proxy_class;
2619 rc->default_vtable = NULL;
2620 rc->xdomain_vtable = NULL;
2621 rc->proxy_class_name = name;
2622 #ifndef DISABLE_PERFCOUNTERS
2623 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2626 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2628 mono_domain_unlock (domain);
2633 * clone_remote_class:
2634 * Creates a copy of the remote_class, adding the provided class or interface
2636 static MonoRemoteClass*
2637 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2639 MONO_REQ_GC_NEUTRAL_MODE;
2641 MonoRemoteClass *rc;
2642 gpointer* key, *mp_key;
2644 key = create_remote_class_key (remote_class, extra_class);
2645 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2651 mp_key = copy_remote_class_key (domain, key);
2655 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2657 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2658 rc->proxy_class = remote_class->proxy_class;
2659 rc->interface_count = remote_class->interface_count + 1;
2661 // Keep the list of interfaces sorted, since the hash key of
2662 // the remote class depends on this
2663 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2664 if (remote_class->interfaces [i] > extra_class && i == j)
2665 rc->interfaces [j++] = extra_class;
2666 rc->interfaces [j] = remote_class->interfaces [i];
2669 rc->interfaces [j] = extra_class;
2671 // Replace the old class. The interface array is the same
2672 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2673 rc->proxy_class = extra_class;
2674 rc->interface_count = remote_class->interface_count;
2675 if (rc->interface_count > 0)
2676 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2679 rc->default_vtable = NULL;
2680 rc->xdomain_vtable = NULL;
2681 rc->proxy_class_name = remote_class->proxy_class_name;
2683 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2689 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2691 MONO_REQ_GC_UNSAFE_MODE;
2693 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2694 mono_domain_lock (domain);
2695 if (rp->target_domain_id != -1) {
2696 if (remote_class->xdomain_vtable == NULL)
2697 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2698 mono_domain_unlock (domain);
2699 mono_loader_unlock ();
2700 return remote_class->xdomain_vtable;
2702 if (remote_class->default_vtable == NULL) {
2705 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2706 klass = mono_class_from_mono_type (type);
2708 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)))
2709 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2712 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2715 mono_domain_unlock (domain);
2716 mono_loader_unlock ();
2717 return remote_class->default_vtable;
2721 * mono_upgrade_remote_class:
2722 * @domain: the application domain
2723 * @tproxy: the proxy whose remote class has to be upgraded.
2724 * @klass: class to which the remote class can be casted.
2726 * Updates the vtable of the remote class by adding the necessary method slots
2727 * and interface offsets so it can be safely casted to klass. klass can be a
2728 * class or an interface.
2731 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2733 MONO_REQ_GC_UNSAFE_MODE;
2735 MonoTransparentProxy *tproxy;
2736 MonoRemoteClass *remote_class;
2737 gboolean redo_vtable;
2739 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2740 mono_domain_lock (domain);
2742 tproxy = (MonoTransparentProxy*) proxy_object;
2743 remote_class = tproxy->remote_class;
2745 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2748 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2749 if (remote_class->interfaces [i] == klass)
2750 redo_vtable = FALSE;
2753 redo_vtable = (remote_class->proxy_class != klass);
2757 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2758 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2761 mono_domain_unlock (domain);
2762 mono_loader_unlock ();
2764 #endif /* DISABLE_REMOTING */
2768 * mono_object_get_virtual_method:
2769 * @obj: object to operate on.
2772 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2773 * the instance of a callvirt of method.
2776 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2778 MONO_REQ_GC_UNSAFE_MODE;
2781 MonoMethod **vtable;
2782 gboolean is_proxy = FALSE;
2783 MonoMethod *res = NULL;
2785 klass = mono_object_class (obj);
2786 #ifndef DISABLE_REMOTING
2787 if (klass == mono_defaults.transparent_proxy_class) {
2788 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2793 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2796 mono_class_setup_vtable (klass);
2797 vtable = klass->vtable;
2799 if (method->slot == -1) {
2800 /* method->slot might not be set for instances of generic methods */
2801 if (method->is_inflated) {
2802 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2803 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2806 g_assert_not_reached ();
2810 /* check method->slot is a valid index: perform isinstance? */
2811 if (method->slot != -1) {
2812 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2814 gboolean variance_used = FALSE;
2815 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2816 g_assert (iface_offset > 0);
2817 res = vtable [iface_offset + method->slot];
2820 res = vtable [method->slot];
2824 #ifndef DISABLE_REMOTING
2826 /* It may be an interface, abstract class method or generic method */
2827 if (!res || mono_method_signature (res)->generic_param_count)
2830 /* generic methods demand invoke_with_check */
2831 if (mono_method_signature (res)->generic_param_count)
2832 res = mono_marshal_get_remoting_invoke_with_check (res);
2835 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2836 res = mono_cominterop_get_invoke (res);
2839 res = mono_marshal_get_remoting_invoke (res);
2844 if (method->is_inflated) {
2846 /* Have to inflate the result */
2847 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2848 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2858 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2860 MONO_REQ_GC_UNSAFE_MODE;
2862 MonoObject *result = NULL;
2864 g_assert (callbacks.runtime_invoke);
2866 mono_error_init (error);
2868 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2869 mono_profiler_method_start_invoke (method);
2871 MONO_PREPARE_RESET_BLOCKING;
2873 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2875 MONO_FINISH_RESET_BLOCKING;
2877 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2878 mono_profiler_method_end_invoke (method);
2880 if (!mono_error_ok (error))
2887 * mono_runtime_invoke:
2888 * @method: method to invoke
2889 * @obJ: object instance
2890 * @params: arguments to the method
2891 * @exc: exception information.
2893 * Invokes the method represented by @method on the object @obj.
2895 * obj is the 'this' pointer, it should be NULL for static
2896 * methods, a MonoObject* for object instances and a pointer to
2897 * the value type for value types.
2899 * The params array contains the arguments to the method with the
2900 * same convention: MonoObject* pointers for object instances and
2901 * pointers to the value type otherwise.
2903 * From unmanaged code you'll usually use the
2904 * mono_runtime_invoke() variant.
2906 * Note that this function doesn't handle virtual methods for
2907 * you, it will exec the exact method you pass: we still need to
2908 * expose a function to lookup the derived class implementation
2909 * of a virtual method (there are examples of this in the code,
2912 * You can pass NULL as the exc argument if you don't want to
2913 * catch exceptions, otherwise, *exc will be set to the exception
2914 * thrown, if any. if an exception is thrown, you can't use the
2915 * MonoObject* result from the function.
2917 * If the method returns a value type, it is boxed in an object
2921 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2926 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2927 if (*exc == NULL && !mono_error_ok(&error)) {
2928 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2930 mono_error_cleanup (&error);
2932 res = mono_runtime_invoke_checked (method, obj, params, &error);
2933 mono_error_raise_exception (&error);
2939 * mono_runtime_try_invoke:
2940 * @method: method to invoke
2941 * @obJ: object instance
2942 * @params: arguments to the method
2943 * @exc: exception information.
2944 * @error: set on error
2946 * Invokes the method represented by @method on the object @obj.
2948 * obj is the 'this' pointer, it should be NULL for static
2949 * methods, a MonoObject* for object instances and a pointer to
2950 * the value type for value types.
2952 * The params array contains the arguments to the method with the
2953 * same convention: MonoObject* pointers for object instances and
2954 * pointers to the value type otherwise.
2956 * From unmanaged code you'll usually use the
2957 * mono_runtime_invoke() variant.
2959 * Note that this function doesn't handle virtual methods for
2960 * you, it will exec the exact method you pass: we still need to
2961 * expose a function to lookup the derived class implementation
2962 * of a virtual method (there are examples of this in the code,
2965 * For this function, you must not pass NULL as the exc argument if
2966 * you don't want to catch exceptions, use
2967 * mono_runtime_invoke_checked(). If an exception is thrown, you
2968 * can't use the MonoObject* result from the function.
2970 * If this method cannot be invoked, @error will be set and @exc and
2971 * the return value must not be used.
2973 * If the method returns a value type, it is boxed in an object
2977 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2979 MONO_REQ_GC_UNSAFE_MODE;
2981 g_assert (exc != NULL);
2983 if (mono_runtime_get_no_exec ())
2984 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2986 return do_runtime_invoke (method, obj, params, exc, error);
2990 * mono_runtime_invoke_checked:
2991 * @method: method to invoke
2992 * @obJ: object instance
2993 * @params: arguments to the method
2994 * @error: set on error
2996 * Invokes the method represented by @method on the object @obj.
2998 * obj is the 'this' pointer, it should be NULL for static
2999 * methods, a MonoObject* for object instances and a pointer to
3000 * the value type for value types.
3002 * The params array contains the arguments to the method with the
3003 * same convention: MonoObject* pointers for object instances and
3004 * pointers to the value type otherwise.
3006 * From unmanaged code you'll usually use the
3007 * mono_runtime_invoke() variant.
3009 * Note that this function doesn't handle virtual methods for
3010 * you, it will exec the exact method you pass: we still need to
3011 * expose a function to lookup the derived class implementation
3012 * of a virtual method (there are examples of this in the code,
3015 * If an exception is thrown, you can't use the MonoObject* result
3016 * from the function.
3018 * If this method cannot be invoked, @error will be set. If the
3019 * method throws an exception (and we're in coop mode) the exception
3020 * will be set in @error.
3022 * If the method returns a value type, it is boxed in an object
3026 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3028 MONO_REQ_GC_UNSAFE_MODE;
3030 if (mono_runtime_get_no_exec ())
3031 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3033 return do_runtime_invoke (method, obj, params, NULL, error);
3037 * mono_method_get_unmanaged_thunk:
3038 * @method: method to generate a thunk for.
3040 * Returns an unmanaged->managed thunk that can be used to call
3041 * a managed method directly from C.
3043 * The thunk's C signature closely matches the managed signature:
3045 * C#: public bool Equals (object obj);
3046 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3047 * MonoObject*, MonoException**);
3049 * The 1st ("this") parameter must not be used with static methods:
3051 * C#: public static bool ReferenceEquals (object a, object b);
3052 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3055 * The last argument must be a non-null pointer of a MonoException* pointer.
3056 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3057 * exception has been thrown in managed code. Otherwise it will point
3058 * to the MonoException* caught by the thunk. In this case, the result of
3059 * the thunk is undefined:
3061 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3062 * MonoException *ex = NULL;
3063 * Equals func = mono_method_get_unmanaged_thunk (method);
3064 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3066 * // handle exception
3069 * The calling convention of the thunk matches the platform's default
3070 * convention. This means that under Windows, C declarations must
3071 * contain the __stdcall attribute:
3073 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3074 * MonoObject*, MonoException**);
3078 * Value type arguments and return values are treated as they were objects:
3080 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3081 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3083 * Arguments must be properly boxed upon trunk's invocation, while return
3084 * values must be unboxed.
3087 mono_method_get_unmanaged_thunk (MonoMethod *method)
3089 MONO_REQ_GC_NEUTRAL_MODE;
3090 MONO_REQ_API_ENTRYPOINT;
3094 MONO_PREPARE_RESET_BLOCKING;
3095 method = mono_marshal_get_thunk_invoke_wrapper (method);
3096 res = mono_compile_method (method);
3097 MONO_FINISH_RESET_BLOCKING;
3103 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3105 MONO_REQ_GC_UNSAFE_MODE;
3109 /* object fields cannot be byref, so we don't need a
3111 gpointer *p = (gpointer*)dest;
3118 case MONO_TYPE_BOOLEAN:
3120 case MONO_TYPE_U1: {
3121 guint8 *p = (guint8*)dest;
3122 *p = value ? *(guint8*)value : 0;
3127 case MONO_TYPE_CHAR: {
3128 guint16 *p = (guint16*)dest;
3129 *p = value ? *(guint16*)value : 0;
3132 #if SIZEOF_VOID_P == 4
3137 case MONO_TYPE_U4: {
3138 gint32 *p = (gint32*)dest;
3139 *p = value ? *(gint32*)value : 0;
3142 #if SIZEOF_VOID_P == 8
3147 case MONO_TYPE_U8: {
3148 gint64 *p = (gint64*)dest;
3149 *p = value ? *(gint64*)value : 0;
3152 case MONO_TYPE_R4: {
3153 float *p = (float*)dest;
3154 *p = value ? *(float*)value : 0;
3157 case MONO_TYPE_R8: {
3158 double *p = (double*)dest;
3159 *p = value ? *(double*)value : 0;
3162 case MONO_TYPE_STRING:
3163 case MONO_TYPE_SZARRAY:
3164 case MONO_TYPE_CLASS:
3165 case MONO_TYPE_OBJECT:
3166 case MONO_TYPE_ARRAY:
3167 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3169 case MONO_TYPE_FNPTR:
3170 case MONO_TYPE_PTR: {
3171 gpointer *p = (gpointer*)dest;
3172 *p = deref_pointer? *(gpointer*)value: value;
3175 case MONO_TYPE_VALUETYPE:
3176 /* note that 't' and 'type->type' can be different */
3177 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3178 t = mono_class_enum_basetype (type->data.klass)->type;
3181 MonoClass *klass = mono_class_from_mono_type (type);
3182 int size = mono_class_value_size (klass, NULL);
3184 mono_gc_bzero_atomic (dest, size);
3186 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3189 case MONO_TYPE_GENERICINST:
3190 t = type->data.generic_class->container_class->byval_arg.type;
3193 g_error ("got type %x", type->type);
3198 * mono_field_set_value:
3199 * @obj: Instance object
3200 * @field: MonoClassField describing the field to set
3201 * @value: The value to be set
3203 * Sets the value of the field described by @field in the object instance @obj
3204 * to the value passed in @value. This method should only be used for instance
3205 * fields. For static fields, use mono_field_static_set_value.
3207 * The value must be on the native format of the field type.
3210 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3212 MONO_REQ_GC_UNSAFE_MODE;
3216 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3218 dest = (char*)obj + field->offset;
3219 mono_copy_value (field->type, dest, value, FALSE);
3223 * mono_field_static_set_value:
3224 * @field: MonoClassField describing the field to set
3225 * @value: The value to be set
3227 * Sets the value of the static field described by @field
3228 * to the value passed in @value.
3230 * The value must be on the native format of the field type.
3233 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3235 MONO_REQ_GC_UNSAFE_MODE;
3239 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3240 /* you cant set a constant! */
3241 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3243 if (field->offset == -1) {
3244 /* Special static */
3247 mono_domain_lock (vt->domain);
3248 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3249 mono_domain_unlock (vt->domain);
3250 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3252 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3254 mono_copy_value (field->type, dest, value, FALSE);
3258 * mono_vtable_get_static_field_data:
3260 * Internal use function: return a pointer to the memory holding the static fields
3261 * for a class or NULL if there are no static fields.
3262 * This is exported only for use by the debugger.
3265 mono_vtable_get_static_field_data (MonoVTable *vt)
3267 MONO_REQ_GC_NEUTRAL_MODE
3269 if (!vt->has_static_fields)
3271 return vt->vtable [vt->klass->vtable_size];
3275 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3277 MONO_REQ_GC_UNSAFE_MODE;
3281 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3282 if (field->offset == -1) {
3283 /* Special static */
3286 mono_domain_lock (vt->domain);
3287 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3288 mono_domain_unlock (vt->domain);
3289 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3291 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3294 src = (guint8*)obj + field->offset;
3301 * mono_field_get_value:
3302 * @obj: Object instance
3303 * @field: MonoClassField describing the field to fetch information from
3304 * @value: pointer to the location where the value will be stored
3306 * Use this routine to get the value of the field @field in the object
3309 * The pointer provided by value must be of the field type, for reference
3310 * types this is a MonoObject*, for value types its the actual pointer to
3315 * mono_field_get_value (obj, int_field, &i);
3318 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3320 MONO_REQ_GC_UNSAFE_MODE;
3326 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3328 src = (char*)obj + field->offset;
3329 mono_copy_value (field->type, value, src, TRUE);
3333 * mono_field_get_value_object:
3334 * @domain: domain where the object will be created (if boxing)
3335 * @field: MonoClassField describing the field to fetch information from
3336 * @obj: The object instance for the field.
3338 * Returns: a new MonoObject with the value from the given field. If the
3339 * field represents a value type, the value is boxed.
3343 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3345 MONO_REQ_GC_UNSAFE_MODE;
3350 MonoVTable *vtable = NULL;
3352 gboolean is_static = FALSE;
3353 gboolean is_ref = FALSE;
3354 gboolean is_literal = FALSE;
3355 gboolean is_ptr = FALSE;
3356 MonoType *type = mono_field_get_type_checked (field, &error);
3358 if (!mono_error_ok (&error))
3359 mono_error_raise_exception (&error); /* FIXME don't raise here */
3361 switch (type->type) {
3362 case MONO_TYPE_STRING:
3363 case MONO_TYPE_OBJECT:
3364 case MONO_TYPE_CLASS:
3365 case MONO_TYPE_ARRAY:
3366 case MONO_TYPE_SZARRAY:
3371 case MONO_TYPE_BOOLEAN:
3374 case MONO_TYPE_CHAR:
3383 case MONO_TYPE_VALUETYPE:
3384 is_ref = type->byref;
3386 case MONO_TYPE_GENERICINST:
3387 is_ref = !mono_type_generic_inst_is_valuetype (type);
3393 g_error ("type 0x%x not handled in "
3394 "mono_field_get_value_object", type->type);
3398 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3401 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3405 vtable = mono_class_vtable_full (domain, field->parent, &error);
3406 mono_error_raise_exception (&error); /* FIXME don't raise here */
3408 if (!vtable->initialized) {
3409 mono_runtime_class_init_full (vtable, &error);
3410 mono_error_raise_exception (&error); /* FIXME don't raise here */
3419 get_default_field_value (domain, field, &o);
3420 } else if (is_static) {
3421 mono_field_static_get_value (vtable, field, &o);
3423 mono_field_get_value (obj, field, &o);
3429 static MonoMethod *m;
3435 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3436 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3442 get_default_field_value (domain, field, v);
3443 } else if (is_static) {
3444 mono_field_static_get_value (vtable, field, v);
3446 mono_field_get_value (obj, field, v);
3449 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3450 args [0] = ptr ? *ptr : NULL;
3451 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3452 mono_error_raise_exception (&error); /* FIXME don't raise here */
3454 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3455 mono_error_raise_exception (&error); /* FIXME don't raise here */
3460 /* boxed value type */
3461 klass = mono_class_from_mono_type (type);
3463 if (mono_class_is_nullable (klass))
3464 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3466 o = mono_object_new_checked (domain, klass, &error);
3467 mono_error_raise_exception (&error); /* FIXME don't raise here */
3468 v = ((gchar *) o) + sizeof (MonoObject);
3471 get_default_field_value (domain, field, v);
3472 } else if (is_static) {
3473 mono_field_static_get_value (vtable, field, v);
3475 mono_field_get_value (obj, field, v);
3482 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3484 MONO_REQ_GC_UNSAFE_MODE;
3487 const char *p = blob;
3488 mono_metadata_decode_blob_size (p, &p);
3491 case MONO_TYPE_BOOLEAN:
3494 *(guint8 *) value = *p;
3496 case MONO_TYPE_CHAR:
3499 *(guint16*) value = read16 (p);
3503 *(guint32*) value = read32 (p);
3507 *(guint64*) value = read64 (p);
3510 readr4 (p, (float*) value);
3513 readr8 (p, (double*) value);
3515 case MONO_TYPE_STRING:
3516 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3518 case MONO_TYPE_CLASS:
3519 *(gpointer*) value = NULL;
3523 g_warning ("type 0x%02x should not be in constant table", type);
3529 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3531 MONO_REQ_GC_NEUTRAL_MODE;
3533 MonoTypeEnum def_type;
3536 data = mono_class_get_field_default_value (field, &def_type);
3537 mono_get_constant_value_from_blob (domain, def_type, data, value);
3541 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3543 MONO_REQ_GC_UNSAFE_MODE;
3547 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3549 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3550 get_default_field_value (vt->domain, field, value);
3554 if (field->offset == -1) {
3555 /* Special static */
3556 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3557 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3559 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3561 mono_copy_value (field->type, value, src, TRUE);
3565 * mono_field_static_get_value:
3566 * @vt: vtable to the object
3567 * @field: MonoClassField describing the field to fetch information from
3568 * @value: where the value is returned
3570 * Use this routine to get the value of the static field @field value.
3572 * The pointer provided by value must be of the field type, for reference
3573 * types this is a MonoObject*, for value types its the actual pointer to
3578 * mono_field_static_get_value (vt, int_field, &i);
3581 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3583 MONO_REQ_GC_NEUTRAL_MODE;
3585 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3589 * mono_property_set_value:
3590 * @prop: MonoProperty to set
3591 * @obj: instance object on which to act
3592 * @params: parameters to pass to the propery
3593 * @exc: optional exception
3595 * Invokes the property's set method with the given arguments on the
3596 * object instance obj (or NULL for static properties).
3598 * You can pass NULL as the exc argument if you don't want to
3599 * catch exceptions, otherwise, *exc will be set to the exception
3600 * thrown, if any. if an exception is thrown, you can't use the
3601 * MonoObject* result from the function.
3604 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3606 MONO_REQ_GC_UNSAFE_MODE;
3609 do_runtime_invoke (prop->set, obj, params, exc, &error);
3610 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3611 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3613 mono_error_raise_exception (&error); /* FIXME don't raise here */
3618 * mono_property_get_value:
3619 * @prop: MonoProperty to fetch
3620 * @obj: instance object on which to act
3621 * @params: parameters to pass to the propery
3622 * @exc: optional exception
3624 * Invokes the property's get method with the given arguments on the
3625 * object instance obj (or NULL for static properties).
3627 * You can pass NULL as the exc argument if you don't want to
3628 * catch exceptions, otherwise, *exc will be set to the exception
3629 * thrown, if any. if an exception is thrown, you can't use the
3630 * MonoObject* result from the function.
3632 * Returns: the value from invoking the get method on the property.
3635 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3637 MONO_REQ_GC_UNSAFE_MODE;
3640 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3641 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3642 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3644 mono_error_raise_exception (&error); /* FIXME don't raise here */
3651 * mono_nullable_init:
3652 * @buf: The nullable structure to initialize.
3653 * @value: the value to initialize from
3654 * @klass: the type for the object
3656 * Initialize the nullable structure pointed to by @buf from @value which
3657 * should be a boxed value type. The size of @buf should be able to hold
3658 * as much data as the @klass->instance_size (which is the number of bytes
3659 * that will be copies).
3661 * Since Nullables have variable structure, we can not define a C
3662 * structure for them.
3665 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3667 MONO_REQ_GC_UNSAFE_MODE;
3669 MonoClass *param_class = klass->cast_class;
3671 mono_class_setup_fields_locking (klass);
3672 g_assert (klass->fields_inited);
3674 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3675 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3677 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3679 if (param_class->has_references)
3680 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3682 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3684 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3689 * mono_nullable_box:
3690 * @buf: The buffer representing the data to be boxed
3691 * @klass: the type to box it as.
3693 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3697 mono_nullable_box (guint8 *buf, MonoClass *klass)
3699 MONO_REQ_GC_UNSAFE_MODE;
3703 MonoClass *param_class = klass->cast_class;
3705 mono_class_setup_fields_locking (klass);
3706 g_assert (klass->fields_inited);
3708 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3709 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3711 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3712 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3713 mono_error_raise_exception (&error); /* FIXME don't raise here */
3714 if (param_class->has_references)
3715 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3717 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3725 * mono_get_delegate_invoke:
3726 * @klass: The delegate class
3728 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3731 mono_get_delegate_invoke (MonoClass *klass)
3733 MONO_REQ_GC_NEUTRAL_MODE;
3737 /* This is called at runtime, so avoid the slower search in metadata */
3738 mono_class_setup_methods (klass);
3739 if (mono_class_has_failure (klass))
3741 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3746 * mono_get_delegate_begin_invoke:
3747 * @klass: The delegate class
3749 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3752 mono_get_delegate_begin_invoke (MonoClass *klass)
3754 MONO_REQ_GC_NEUTRAL_MODE;
3758 /* This is called at runtime, so avoid the slower search in metadata */
3759 mono_class_setup_methods (klass);
3760 if (mono_class_has_failure (klass))
3762 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3767 * mono_get_delegate_end_invoke:
3768 * @klass: The delegate class
3770 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3773 mono_get_delegate_end_invoke (MonoClass *klass)
3775 MONO_REQ_GC_NEUTRAL_MODE;
3779 /* This is called at runtime, so avoid the slower search in metadata */
3780 mono_class_setup_methods (klass);
3781 if (mono_class_has_failure (klass))
3783 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3788 * mono_runtime_delegate_invoke:
3789 * @delegate: pointer to a delegate object.
3790 * @params: parameters for the delegate.
3791 * @exc: Pointer to the exception result.
3793 * Invokes the delegate method @delegate with the parameters provided.
3795 * You can pass NULL as the exc argument if you don't want to
3796 * catch exceptions, otherwise, *exc will be set to the exception
3797 * thrown, if any. if an exception is thrown, you can't use the
3798 * MonoObject* result from the function.
3801 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3803 MONO_REQ_GC_UNSAFE_MODE;
3807 MonoClass *klass = delegate->vtable->klass;
3810 im = mono_get_delegate_invoke (klass);
3812 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3815 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3816 if (*exc == NULL && !mono_error_ok (&error))
3817 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3819 mono_error_cleanup (&error);
3821 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3822 mono_error_raise_exception (&error); /* FIXME don't raise here */
3828 static char **main_args = NULL;
3829 static int num_main_args = 0;
3832 * mono_runtime_get_main_args:
3834 * Returns: a MonoArray with the arguments passed to the main program
3837 mono_runtime_get_main_args (void)
3839 MONO_REQ_GC_UNSAFE_MODE;
3843 MonoDomain *domain = mono_domain_get ();
3845 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3847 for (i = 0; i < num_main_args; ++i)
3848 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3854 free_main_args (void)
3856 MONO_REQ_GC_NEUTRAL_MODE;
3860 for (i = 0; i < num_main_args; ++i)
3861 g_free (main_args [i]);
3868 * mono_runtime_set_main_args:
3869 * @argc: number of arguments from the command line
3870 * @argv: array of strings from the command line
3872 * Set the command line arguments from an embedding application that doesn't otherwise call
3873 * mono_runtime_run_main ().
3876 mono_runtime_set_main_args (int argc, char* argv[])
3878 MONO_REQ_GC_NEUTRAL_MODE;
3883 main_args = g_new0 (char*, argc);
3884 num_main_args = argc;
3886 for (i = 0; i < argc; ++i) {
3889 utf8_arg = mono_utf8_from_external (argv[i]);
3890 if (utf8_arg == NULL) {
3891 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3892 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3896 main_args [i] = utf8_arg;
3903 * mono_runtime_run_main:
3904 * @method: the method to start the application with (usually Main)
3905 * @argc: number of arguments from the command line
3906 * @argv: array of strings from the command line
3907 * @exc: excetption results
3909 * Execute a standard Main() method (argc/argv contains the
3910 * executable name). This method also sets the command line argument value
3911 * needed by System.Environment.
3916 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3919 MONO_REQ_GC_UNSAFE_MODE;
3922 MonoArray *args = NULL;
3923 MonoDomain *domain = mono_domain_get ();
3924 gchar *utf8_fullpath;
3925 MonoMethodSignature *sig;
3927 g_assert (method != NULL);
3929 mono_thread_set_main (mono_thread_current ());
3931 main_args = g_new0 (char*, argc);
3932 num_main_args = argc;
3934 if (!g_path_is_absolute (argv [0])) {
3935 gchar *basename = g_path_get_basename (argv [0]);
3936 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3940 utf8_fullpath = mono_utf8_from_external (fullpath);
3941 if(utf8_fullpath == NULL) {
3942 /* Printing the arg text will cause glib to
3943 * whinge about "Invalid UTF-8", but at least
3944 * its relevant, and shows the problem text
3947 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3948 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3955 utf8_fullpath = mono_utf8_from_external (argv[0]);
3956 if(utf8_fullpath == NULL) {
3957 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3958 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3963 main_args [0] = utf8_fullpath;
3965 for (i = 1; i < argc; ++i) {
3968 utf8_arg=mono_utf8_from_external (argv[i]);
3969 if(utf8_arg==NULL) {
3970 /* Ditto the comment about Invalid UTF-8 here */
3971 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3972 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3976 main_args [i] = utf8_arg;
3981 sig = mono_method_signature (method);
3983 g_print ("Unable to load Main method.\n");
3987 if (sig->param_count) {
3988 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3989 for (i = 0; i < argc; ++i) {
3990 /* The encodings should all work, given that
3991 * we've checked all these args for the
3994 gchar *str = mono_utf8_from_external (argv [i]);
3995 MonoString *arg = mono_string_new (domain, str);
3996 mono_array_setref (args, i, arg);
4000 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4003 mono_assembly_set_main (method->klass->image->assembly);
4005 return mono_runtime_exec_main (method, args, exc);
4009 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4011 static MonoMethod *serialize_method;
4017 if (!serialize_method) {
4018 MonoClass *klass = mono_class_get_remoting_services_class ();
4019 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4022 if (!serialize_method) {
4027 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4032 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4033 if (*exc == NULL && !mono_error_ok (&error))
4034 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4036 mono_error_cleanup (&error);
4045 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4047 MONO_REQ_GC_UNSAFE_MODE;
4049 static MonoMethod *deserialize_method;
4055 if (!deserialize_method) {
4056 MonoClass *klass = mono_class_get_remoting_services_class ();
4057 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4059 if (!deserialize_method) {
4067 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4068 if (*exc == NULL && !mono_error_ok (&error))
4069 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4071 mono_error_cleanup (&error);
4079 #ifndef DISABLE_REMOTING
4081 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4083 MONO_REQ_GC_UNSAFE_MODE;
4085 static MonoMethod *get_proxy_method;
4088 MonoDomain *domain = mono_domain_get ();
4089 MonoRealProxy *real_proxy;
4090 MonoReflectionType *reflection_type;
4091 MonoTransparentProxy *transparent_proxy;
4093 if (!get_proxy_method)
4094 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4096 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4098 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4099 mono_error_raise_exception (&error); /* FIXME don't raise here */
4100 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4101 mono_error_raise_exception (&error); /* FIXME don't raise here */
4103 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4104 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4108 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4109 if (*exc == NULL && !mono_error_ok (&error))
4110 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4112 mono_error_cleanup (&error);
4116 return (MonoObject*) transparent_proxy;
4118 #endif /* DISABLE_REMOTING */
4121 * mono_object_xdomain_representation
4123 * @target_domain: a domain
4124 * @exc: pointer to a MonoObject*
4126 * Creates a representation of obj in the domain target_domain. This
4127 * is either a copy of obj arrived through via serialization and
4128 * deserialization or a proxy, depending on whether the object is
4129 * serializable or marshal by ref. obj must not be in target_domain.
4131 * If the object cannot be represented in target_domain, NULL is
4132 * returned and *exc is set to an appropriate exception.
4135 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4137 MONO_REQ_GC_UNSAFE_MODE;
4139 MonoObject *deserialized = NULL;
4140 gboolean failure = FALSE;
4142 g_assert (exc != NULL);
4145 #ifndef DISABLE_REMOTING
4146 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4147 deserialized = make_transparent_proxy (obj, &failure, exc);
4152 MonoDomain *domain = mono_domain_get ();
4153 MonoObject *serialized;
4155 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4156 serialized = serialize_object (obj, &failure, exc);
4157 mono_domain_set_internal_with_options (target_domain, FALSE);
4159 deserialized = deserialize_object (serialized, &failure, exc);
4160 if (domain != target_domain)
4161 mono_domain_set_internal_with_options (domain, FALSE);
4164 return deserialized;
4167 /* Used in call_unhandled_exception_delegate */
4169 create_unhandled_exception_eventargs (MonoObject *exc)
4171 MONO_REQ_GC_UNSAFE_MODE;
4176 MonoMethod *method = NULL;
4177 MonoBoolean is_terminating = TRUE;
4180 klass = mono_class_get_unhandled_exception_event_args_class ();
4181 mono_class_init (klass);
4183 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4184 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4188 args [1] = &is_terminating;
4190 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4191 mono_error_raise_exception (&error); /* FIXME don't raise here */
4193 mono_runtime_invoke_checked (method, obj, args, &error);
4194 mono_error_raise_exception (&error); /* FIXME don't raise here */
4199 /* Used in mono_unhandled_exception */
4201 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4202 MONO_REQ_GC_UNSAFE_MODE;
4204 MonoObject *e = NULL;
4206 MonoDomain *current_domain = mono_domain_get ();
4208 if (domain != current_domain)
4209 mono_domain_set_internal_with_options (domain, FALSE);
4211 g_assert (domain == mono_object_domain (domain->domain));
4213 if (mono_object_domain (exc) != domain) {
4214 MonoObject *serialization_exc;
4216 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4218 if (serialization_exc) {
4220 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4223 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4224 "System.Runtime.Serialization", "SerializationException",
4225 "Could not serialize unhandled exception.");
4229 g_assert (mono_object_domain (exc) == domain);
4231 pa [0] = domain->domain;
4232 pa [1] = create_unhandled_exception_eventargs (exc);
4233 mono_runtime_delegate_invoke (delegate, pa, &e);
4235 if (domain != current_domain)
4236 mono_domain_set_internal_with_options (current_domain, FALSE);
4240 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4241 if (!mono_error_ok (&error)) {
4242 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4243 mono_error_cleanup (&error);
4245 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4251 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4254 * mono_runtime_unhandled_exception_policy_set:
4255 * @policy: the new policy
4257 * This is a VM internal routine.
4259 * Sets the runtime policy for handling unhandled exceptions.
4262 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4263 runtime_unhandled_exception_policy = policy;
4267 * mono_runtime_unhandled_exception_policy_get:
4269 * This is a VM internal routine.
4271 * Gets the runtime policy for handling unhandled exceptions.
4273 MonoRuntimeUnhandledExceptionPolicy
4274 mono_runtime_unhandled_exception_policy_get (void) {
4275 return runtime_unhandled_exception_policy;
4279 * mono_unhandled_exception:
4280 * @exc: exception thrown
4282 * This is a VM internal routine.
4284 * We call this function when we detect an unhandled exception
4285 * in the default domain.
4287 * It invokes the * UnhandledException event in AppDomain or prints
4288 * a warning to the console
4291 mono_unhandled_exception (MonoObject *exc)
4293 MONO_REQ_GC_UNSAFE_MODE;
4295 MonoClassField *field;
4296 MonoDomain *current_domain, *root_domain;
4297 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4299 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4302 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4305 current_domain = mono_domain_get ();
4306 root_domain = mono_get_root_domain ();
4308 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4309 if (current_domain != root_domain)
4310 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4312 /* set exitcode only if we will abort the process */
4313 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4314 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4315 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4317 mono_environment_exitcode_set (1);
4320 mono_print_unhandled_exception (exc);
4322 if (root_appdomain_delegate)
4323 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4324 if (current_appdomain_delegate)
4325 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4330 * mono_runtime_exec_managed_code:
4331 * @domain: Application domain
4332 * @main_func: function to invoke from the execution thread
4333 * @main_args: parameter to the main_func
4335 * Launch a new thread to execute a function
4337 * main_func is called back from the thread with main_args as the
4338 * parameter. The callback function is expected to start Main()
4339 * eventually. This function then waits for all managed threads to
4341 * It is not necesseray anymore to execute managed code in a subthread,
4342 * so this function should not be used anymore by default: just
4343 * execute the code and then call mono_thread_manage ().
4346 mono_runtime_exec_managed_code (MonoDomain *domain,
4347 MonoMainThreadFunc main_func,
4350 mono_thread_create (domain, main_func, main_args);
4352 mono_thread_manage ();
4356 * Execute a standard Main() method (args doesn't contain the
4360 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4362 MONO_REQ_GC_UNSAFE_MODE;
4368 MonoCustomAttrInfo* cinfo;
4369 gboolean has_stathread_attribute;
4370 MonoInternalThread* thread = mono_thread_internal_current ();
4376 domain = mono_object_domain (args);
4377 if (!domain->entry_assembly) {
4379 MonoAssembly *assembly;
4381 assembly = method->klass->image->assembly;
4382 domain->entry_assembly = assembly;
4383 /* Domains created from another domain already have application_base and configuration_file set */
4384 if (domain->setup->application_base == NULL) {
4385 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4388 if (domain->setup->configuration_file == NULL) {
4389 str = g_strconcat (assembly->image->name, ".config", NULL);
4390 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4392 mono_domain_set_options_from_config (domain);
4396 cinfo = mono_custom_attrs_from_method (method);
4398 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4400 mono_custom_attrs_free (cinfo);
4402 has_stathread_attribute = FALSE;
4404 if (has_stathread_attribute) {
4405 thread->apartment_state = ThreadApartmentState_STA;
4407 thread->apartment_state = ThreadApartmentState_MTA;
4409 mono_thread_init_apartment_state ();
4411 /* FIXME: check signature of method */
4412 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4415 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4416 if (*exc == NULL && !mono_error_ok (&error))
4417 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4419 mono_error_cleanup (&error);
4421 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4422 mono_error_raise_exception (&error); /* FIXME don't raise here */
4426 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4430 mono_environment_exitcode_set (rval);
4433 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4434 if (*exc == NULL && !mono_error_ok (&error))
4435 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4437 mono_error_cleanup (&error);
4439 mono_runtime_invoke_checked (method, NULL, pa, &error);
4440 mono_error_raise_exception (&error); /* FIXME don't raise here */
4446 /* If the return type of Main is void, only
4447 * set the exitcode if an exception was thrown
4448 * (we don't want to blow away an
4449 * explicitly-set exit code)
4452 mono_environment_exitcode_set (rval);
4460 * mono_runtime_invoke_array:
4461 * @method: method to invoke
4462 * @obJ: object instance
4463 * @params: arguments to the method
4464 * @exc: exception information.
4466 * Invokes the method represented by @method on the object @obj.
4468 * obj is the 'this' pointer, it should be NULL for static
4469 * methods, a MonoObject* for object instances and a pointer to
4470 * the value type for value types.
4472 * The params array contains the arguments to the method with the
4473 * same convention: MonoObject* pointers for object instances and
4474 * pointers to the value type otherwise. The _invoke_array
4475 * variant takes a C# object[] as the params argument (MonoArray
4476 * *params): in this case the value types are boxed inside the
4477 * respective reference representation.
4479 * From unmanaged code you'll usually use the
4480 * mono_runtime_invoke_checked() variant.
4482 * Note that this function doesn't handle virtual methods for
4483 * you, it will exec the exact method you pass: we still need to
4484 * expose a function to lookup the derived class implementation
4485 * of a virtual method (there are examples of this in the code,
4488 * You can pass NULL as the exc argument if you don't want to
4489 * catch exceptions, otherwise, *exc will be set to the exception
4490 * thrown, if any. if an exception is thrown, you can't use the
4491 * MonoObject* result from the function.
4493 * If the method returns a value type, it is boxed in an object
4497 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4500 MONO_REQ_GC_UNSAFE_MODE;
4503 MonoMethodSignature *sig = mono_method_signature (method);
4504 gpointer *pa = NULL;
4507 gboolean has_byref_nullables = FALSE;
4509 if (NULL != params) {
4510 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4511 for (i = 0; i < mono_array_length (params); i++) {
4512 MonoType *t = sig->params [i];
4518 case MONO_TYPE_BOOLEAN:
4521 case MONO_TYPE_CHAR:
4530 case MONO_TYPE_VALUETYPE:
4531 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4532 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4533 pa [i] = mono_array_get (params, MonoObject*, i);
4535 has_byref_nullables = TRUE;
4537 /* MS seems to create the objects if a null is passed in */
4538 if (!mono_array_get (params, MonoObject*, i)) {
4539 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4540 mono_error_raise_exception (&error); /* FIXME don't raise here */
4541 mono_array_setref (params, i, o);
4546 * We can't pass the unboxed vtype byref to the callee, since
4547 * that would mean the callee would be able to modify boxed
4548 * primitive types. So we (and MS) make a copy of the boxed
4549 * object, pass that to the callee, and replace the original
4550 * boxed object in the arg array with the copy.
4552 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4553 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4554 mono_array_setref (params, i, copy);
4557 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4560 case MONO_TYPE_STRING:
4561 case MONO_TYPE_OBJECT:
4562 case MONO_TYPE_CLASS:
4563 case MONO_TYPE_ARRAY:
4564 case MONO_TYPE_SZARRAY:
4566 pa [i] = mono_array_addr (params, MonoObject*, i);
4567 // FIXME: I need to check this code path
4569 pa [i] = mono_array_get (params, MonoObject*, i);
4571 case MONO_TYPE_GENERICINST:
4573 t = &t->data.generic_class->container_class->this_arg;
4575 t = &t->data.generic_class->container_class->byval_arg;
4577 case MONO_TYPE_PTR: {
4580 /* The argument should be an IntPtr */
4581 arg = mono_array_get (params, MonoObject*, i);
4585 g_assert (arg->vtable->klass == mono_defaults.int_class);
4586 pa [i] = ((MonoIntPtr*)arg)->m_value;
4591 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4596 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4599 if (mono_class_is_nullable (method->klass)) {
4600 /* Need to create a boxed vtype instead */
4606 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4610 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4611 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4612 #ifndef DISABLE_REMOTING
4613 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4614 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4617 if (method->klass->valuetype)
4618 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4621 } else if (method->klass->valuetype) {
4622 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4626 mono_runtime_try_invoke (method, o, pa, exc, &error);
4627 if (*exc == NULL && !mono_error_ok (&error))
4628 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4630 mono_error_cleanup (&error);
4632 mono_runtime_invoke_checked (method, o, pa, &error);
4633 mono_error_raise_exception (&error); /* FIXME don't raise here */
4636 return (MonoObject *)obj;
4638 if (mono_class_is_nullable (method->klass)) {
4639 MonoObject *nullable;
4641 /* Convert the unboxed vtype into a Nullable structure */
4642 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4643 mono_error_raise_exception (&error); /* FIXME don't raise here */
4645 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4646 obj = mono_object_unbox (nullable);
4649 /* obj must be already unboxed if needed */
4651 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4652 if (*exc == NULL && !mono_error_ok (&error))
4653 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4655 mono_error_cleanup (&error);
4657 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4658 mono_error_raise_exception (&error); /* FIXME don't raise here */
4661 if (sig->ret->type == MONO_TYPE_PTR) {
4662 MonoClass *pointer_class;
4663 static MonoMethod *box_method;
4665 MonoObject *box_exc;
4668 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4669 * convert it to a Pointer object.
4671 pointer_class = mono_class_get_pointer_class ();
4673 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4675 g_assert (res->vtable->klass == mono_defaults.int_class);
4676 box_args [0] = ((MonoIntPtr*)res)->m_value;
4677 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4678 mono_error_raise_exception (&error); /* FIXME don't raise here */
4680 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4681 g_assert (box_exc == NULL);
4682 mono_error_assert_ok (&error);
4685 if (has_byref_nullables) {
4687 * The runtime invoke wrapper already converted byref nullables back,
4688 * and stored them in pa, we just need to copy them back to the
4691 for (i = 0; i < mono_array_length (params); i++) {
4692 MonoType *t = sig->params [i];
4694 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4695 mono_array_setref (params, i, pa [i]);
4705 * @klass: the class of the object that we want to create
4707 * Returns: a newly created object whose definition is
4708 * looked up using @klass. This will not invoke any constructors,
4709 * so the consumer of this routine has to invoke any constructors on
4710 * its own to initialize the object.
4712 * It returns NULL on failure.
4715 mono_object_new (MonoDomain *domain, MonoClass *klass)
4717 MONO_REQ_GC_UNSAFE_MODE;
4721 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4723 mono_error_raise_exception (&error);
4728 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4730 MONO_REQ_GC_UNSAFE_MODE;
4734 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4736 mono_error_raise_exception (&error);
4741 * mono_object_new_checked:
4742 * @klass: the class of the object that we want to create
4743 * @error: set on error
4745 * Returns: a newly created object whose definition is
4746 * looked up using @klass. This will not invoke any constructors,
4747 * so the consumer of this routine has to invoke any constructors on
4748 * its own to initialize the object.
4750 * It returns NULL on failure and sets @error.
4753 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4755 MONO_REQ_GC_UNSAFE_MODE;
4759 vtable = mono_class_vtable (domain, klass);
4760 g_assert (vtable); /* FIXME don't swallow the error */
4762 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4767 * mono_object_new_pinned:
4769 * Same as mono_object_new, but the returned object will be pinned.
4770 * For SGEN, these objects will only be freed at appdomain unload.
4773 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4775 MONO_REQ_GC_UNSAFE_MODE;
4779 mono_error_init (error);
4781 vtable = mono_class_vtable (domain, klass);
4782 g_assert (vtable); /* FIXME don't swallow the error */
4784 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4786 if (G_UNLIKELY (!o))
4787 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4788 else if (G_UNLIKELY (vtable->klass->has_finalize))
4789 mono_object_register_finalizer (o, error);
4795 * mono_object_new_specific:
4796 * @vtable: the vtable of the object that we want to create
4798 * Returns: A newly created object with class and domain specified
4802 mono_object_new_specific (MonoVTable *vtable)
4805 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4806 mono_error_raise_exception (&error);
4812 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4814 MONO_REQ_GC_UNSAFE_MODE;
4818 mono_error_init (error);
4820 /* check for is_com_object for COM Interop */
4821 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4824 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4827 MonoClass *klass = mono_class_get_activation_services_class ();
4830 mono_class_init (klass);
4832 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4834 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4837 vtable->domain->create_proxy_for_type_method = im;
4840 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4841 if (!mono_error_ok (error))
4844 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4845 if (!mono_error_ok (error))
4852 return mono_object_new_alloc_specific_checked (vtable, error);
4856 ves_icall_object_new_specific (MonoVTable *vtable)
4859 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4860 mono_error_raise_exception (&error);
4866 * mono_object_new_alloc_specific:
4867 * @vtable: virtual table for the object.
4869 * This function allocates a new `MonoObject` with the type derived
4870 * from the @vtable information. If the class of this object has a
4871 * finalizer, then the object will be tracked for finalization.
4873 * This method might raise an exception on errors. Use the
4874 * `mono_object_new_fast_checked` method if you want to manually raise
4877 * Returns: the allocated object.
4880 mono_object_new_alloc_specific (MonoVTable *vtable)
4883 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4884 mono_error_raise_exception (&error);
4890 * mono_object_new_alloc_specific_checked:
4891 * @vtable: virtual table for the object.
4892 * @error: holds the error return value.
4894 * This function allocates a new `MonoObject` with the type derived
4895 * from the @vtable information. If the class of this object has a
4896 * finalizer, then the object will be tracked for finalization.
4898 * If there is not enough memory, the @error parameter will be set
4899 * and will contain a user-visible message with the amount of bytes
4900 * that were requested.
4902 * Returns: the allocated object, or NULL if there is not enough memory
4906 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4908 MONO_REQ_GC_UNSAFE_MODE;
4912 mono_error_init (error);
4914 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4916 if (G_UNLIKELY (!o))
4917 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4918 else if (G_UNLIKELY (vtable->klass->has_finalize))
4919 mono_object_register_finalizer (o, error);
4925 * mono_object_new_fast:
4926 * @vtable: virtual table for the object.
4928 * This function allocates a new `MonoObject` with the type derived
4929 * from the @vtable information. The returned object is not tracked
4930 * for finalization. If your object implements a finalizer, you should
4931 * use `mono_object_new_alloc_specific` instead.
4933 * This method might raise an exception on errors. Use the
4934 * `mono_object_new_fast_checked` method if you want to manually raise
4937 * Returns: the allocated object.
4940 mono_object_new_fast (MonoVTable *vtable)
4943 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4944 mono_error_raise_exception (&error);
4950 * mono_object_new_fast_checked:
4951 * @vtable: virtual table for the object.
4952 * @error: holds the error return value.
4954 * This function allocates a new `MonoObject` with the type derived
4955 * from the @vtable information. The returned object is not tracked
4956 * for finalization. If your object implements a finalizer, you should
4957 * use `mono_object_new_alloc_specific_checked` instead.
4959 * If there is not enough memory, the @error parameter will be set
4960 * and will contain a user-visible message with the amount of bytes
4961 * that were requested.
4963 * Returns: the allocated object, or NULL if there is not enough memory
4967 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4969 MONO_REQ_GC_UNSAFE_MODE;
4973 mono_error_init (error);
4975 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4977 if (G_UNLIKELY (!o))
4978 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4984 ves_icall_object_new_fast (MonoVTable *vtable)
4987 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4988 mono_error_raise_exception (&error);
4994 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4996 MONO_REQ_GC_UNSAFE_MODE;
5000 mono_error_init (error);
5002 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5004 if (G_UNLIKELY (!o))
5005 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5006 else if (G_UNLIKELY (vtable->klass->has_finalize))
5007 mono_object_register_finalizer (o, error);
5013 * mono_class_get_allocation_ftn:
5015 * @for_box: the object will be used for boxing
5016 * @pass_size_in_words:
5018 * Return the allocation function appropriate for the given class.
5022 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5024 MONO_REQ_GC_NEUTRAL_MODE;
5026 *pass_size_in_words = FALSE;
5028 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5029 return ves_icall_object_new_specific;
5031 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5033 return ves_icall_object_new_fast;
5036 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5037 * of the overhead of parameter passing.
5040 *pass_size_in_words = TRUE;
5041 #ifdef GC_REDIRECT_TO_LOCAL
5042 return GC_local_gcj_fast_malloc;
5044 return GC_gcj_fast_malloc;
5049 return ves_icall_object_new_specific;
5053 * mono_object_new_from_token:
5054 * @image: Context where the type_token is hosted
5055 * @token: a token of the type that we want to create
5057 * Returns: A newly created object whose definition is
5058 * looked up using @token in the @image image
5061 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5063 MONO_REQ_GC_UNSAFE_MODE;
5069 klass = mono_class_get_checked (image, token, &error);
5070 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5072 result = mono_object_new_checked (domain, klass, &error);
5074 mono_error_raise_exception (&error); /* FIXME don't raise here */
5081 * mono_object_clone:
5082 * @obj: the object to clone
5084 * Returns: A newly created object who is a shallow copy of @obj
5087 mono_object_clone (MonoObject *obj)
5090 MonoObject *o = mono_object_clone_checked (obj, &error);
5091 mono_error_raise_exception (&error);
5097 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5099 MONO_REQ_GC_UNSAFE_MODE;
5104 mono_error_init (error);
5106 size = obj->vtable->klass->instance_size;
5108 if (obj->vtable->klass->rank)
5109 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5111 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5113 if (G_UNLIKELY (!o)) {
5114 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5118 /* If the object doesn't contain references this will do a simple memmove. */
5119 mono_gc_wbarrier_object_copy (o, obj);
5121 if (obj->vtable->klass->has_finalize)
5122 mono_object_register_finalizer (o, error);
5127 * mono_array_full_copy:
5128 * @src: source array to copy
5129 * @dest: destination array
5131 * Copies the content of one array to another with exactly the same type and size.
5134 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5136 MONO_REQ_GC_UNSAFE_MODE;
5139 MonoClass *klass = src->obj.vtable->klass;
5141 g_assert (klass == dest->obj.vtable->klass);
5143 size = mono_array_length (src);
5144 g_assert (size == mono_array_length (dest));
5145 size *= mono_array_element_size (klass);
5147 if (klass->element_class->valuetype) {
5148 if (klass->element_class->has_references)
5149 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5151 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5153 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5156 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5161 * mono_array_clone_in_domain:
5162 * @domain: the domain in which the array will be cloned into
5163 * @array: the array to clone
5165 * This routine returns a copy of the array that is hosted on the
5166 * specified MonoDomain.
5169 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5171 MONO_REQ_GC_UNSAFE_MODE;
5177 MonoClass *klass = array->obj.vtable->klass;
5179 if (array->bounds == NULL) {
5180 size = mono_array_length (array);
5181 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5182 mono_error_raise_exception (&error); /* FIXME don't raise here */
5184 size *= mono_array_element_size (klass);
5186 if (klass->element_class->valuetype) {
5187 if (klass->element_class->has_references)
5188 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5190 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5192 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5195 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5200 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5201 size = mono_array_element_size (klass);
5202 for (i = 0; i < klass->rank; ++i) {
5203 sizes [i] = array->bounds [i].length;
5204 size *= array->bounds [i].length;
5205 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5207 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5208 mono_error_raise_exception (&error); /* FIXME don't raise here */
5210 if (klass->element_class->valuetype) {
5211 if (klass->element_class->has_references)
5212 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5214 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5216 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5219 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5227 * @array: the array to clone
5229 * Returns: A newly created array who is a shallow copy of @array
5232 mono_array_clone (MonoArray *array)
5234 MONO_REQ_GC_UNSAFE_MODE;
5236 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5239 /* helper macros to check for overflow when calculating the size of arrays */
5240 #ifdef MONO_BIG_ARRAYS
5241 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5242 #define MYGUINT_MAX MYGUINT64_MAX
5243 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5244 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5245 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5246 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5247 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5249 #define MYGUINT32_MAX 4294967295U
5250 #define MYGUINT_MAX MYGUINT32_MAX
5251 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5252 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5253 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5254 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5255 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5259 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5261 MONO_REQ_GC_NEUTRAL_MODE;
5265 byte_len = mono_array_element_size (klass);
5266 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5269 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5271 byte_len += MONO_SIZEOF_MONO_ARRAY;
5279 * mono_array_new_full:
5280 * @domain: domain where the object is created
5281 * @array_class: array class
5282 * @lengths: lengths for each dimension in the array
5283 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5285 * This routine creates a new array objects with the given dimensions,
5286 * lower bounds and type.
5289 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5292 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5293 mono_error_raise_exception (&error);
5299 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5301 MONO_REQ_GC_UNSAFE_MODE;
5303 uintptr_t byte_len = 0, len, bounds_size;
5306 MonoArrayBounds *bounds;
5310 mono_error_init (error);
5312 if (!array_class->inited)
5313 mono_class_init (array_class);
5317 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5318 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5320 if (len > MONO_ARRAY_MAX_INDEX) {
5321 mono_error_set_generic_error (error, "System", "OverflowException", "");
5326 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5328 for (i = 0; i < array_class->rank; ++i) {
5329 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5330 mono_error_set_generic_error (error, "System", "OverflowException", "");
5333 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5334 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5341 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5342 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5348 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5349 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5352 byte_len = (byte_len + 3) & ~3;
5353 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5354 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5357 byte_len += bounds_size;
5360 * Following three lines almost taken from mono_object_new ():
5361 * they need to be kept in sync.
5363 vtable = mono_class_vtable_full (domain, array_class, error);
5364 return_val_if_nok (error, NULL);
5367 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5369 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5371 if (G_UNLIKELY (!o)) {
5372 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5376 array = (MonoArray*)o;
5378 bounds = array->bounds;
5381 for (i = 0; i < array_class->rank; ++i) {
5382 bounds [i].length = lengths [i];
5384 bounds [i].lower_bound = lower_bounds [i];
5393 * @domain: domain where the object is created
5394 * @eclass: element class
5395 * @n: number of array elements
5397 * This routine creates a new szarray with @n elements of type @eclass.
5400 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5402 MONO_REQ_GC_UNSAFE_MODE;
5408 ac = mono_array_class_get (eclass, 1);
5411 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5412 mono_error_raise_exception (&error); /* FIXME don't raise here */
5414 arr = mono_array_new_specific_checked (vtable, n, &error);
5415 mono_error_raise_exception (&error); /* FIXME don't raise here */
5421 * mono_array_new_specific:
5422 * @vtable: a vtable in the appropriate domain for an initialized class
5423 * @n: number of array elements
5425 * This routine is a fast alternative to mono_array_new() for code which
5426 * can be sure about the domain it operates in.
5429 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5432 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5433 mono_error_raise_exception (&error); /* FIXME don't raise here */
5439 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5441 MONO_REQ_GC_UNSAFE_MODE;
5446 mono_error_init (error);
5448 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5449 mono_error_set_generic_error (error, "System", "OverflowException", "");
5453 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5454 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5457 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5459 if (G_UNLIKELY (!o)) {
5460 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5464 return (MonoArray*)o;
5468 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5471 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5472 mono_error_raise_exception (&error);
5478 * mono_string_new_utf16:
5479 * @text: a pointer to an utf16 string
5480 * @len: the length of the string
5482 * Returns: A newly created string object which contains @text.
5485 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5487 MONO_REQ_GC_UNSAFE_MODE;
5490 MonoString *res = NULL;
5491 res = mono_string_new_utf16_checked (domain, text, len, &error);
5492 mono_error_raise_exception (&error);
5498 * mono_string_new_utf16_checked:
5499 * @text: a pointer to an utf16 string
5500 * @len: the length of the string
5501 * @error: written on error.
5503 * Returns: A newly created string object which contains @text.
5504 * On error, returns NULL and sets @error.
5507 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5509 MONO_REQ_GC_UNSAFE_MODE;
5513 mono_error_init (error);
5515 s = mono_string_new_size_checked (domain, len, error);
5517 memcpy (mono_string_chars (s), text, len * 2);
5523 * mono_string_new_utf32:
5524 * @text: a pointer to an utf32 string
5525 * @len: the length of the string
5527 * Returns: A newly created string object which contains @text.
5530 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5532 MONO_REQ_GC_UNSAFE_MODE;
5536 mono_unichar2 *utf16_output = NULL;
5537 gint32 utf16_len = 0;
5538 GError *gerror = NULL;
5539 glong items_written;
5541 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5544 g_error_free (gerror);
5546 while (utf16_output [utf16_len]) utf16_len++;
5548 s = mono_string_new_size_checked (domain, utf16_len, &error);
5549 mono_error_raise_exception (&error); /* FIXME don't raise here */
5551 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5553 g_free (utf16_output);
5559 * mono_string_new_size:
5560 * @text: a pointer to an utf16 string
5561 * @len: the length of the string
5563 * Returns: A newly created string object of @len
5566 mono_string_new_size (MonoDomain *domain, gint32 len)
5569 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5570 mono_error_raise_exception (&error);
5576 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5578 MONO_REQ_GC_UNSAFE_MODE;
5584 mono_error_init (error);
5586 /* check for overflow */
5587 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5588 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5592 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5593 g_assert (size > 0);
5595 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5598 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5600 if (G_UNLIKELY (!s)) {
5601 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5609 * mono_string_new_len:
5610 * @text: a pointer to an utf8 string
5611 * @length: number of bytes in @text to consider
5613 * Returns: A newly created string object which contains @text.
5616 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5618 MONO_REQ_GC_UNSAFE_MODE;
5621 GError *eg_error = NULL;
5622 MonoString *o = NULL;
5624 glong items_written;
5626 mono_error_init (&error);
5628 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5631 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5633 g_error_free (eg_error);
5637 mono_error_raise_exception (&error); /* FIXME don't raise here */
5643 * @text: a pointer to an utf8 string
5645 * Returns: A newly created string object which contains @text.
5647 * This function asserts if it cannot allocate a new string.
5649 * @deprecated Use mono_string_new_checked in new code.
5652 mono_string_new (MonoDomain *domain, const char *text)
5655 MonoString *res = NULL;
5656 res = mono_string_new_checked (domain, text, &error);
5657 mono_error_assert_ok (&error);
5662 * mono_string_new_checked:
5663 * @text: a pointer to an utf8 string
5664 * @merror: set on error
5666 * Returns: A newly created string object which contains @text.
5667 * On error returns NULL and sets @merror.
5670 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5672 MONO_REQ_GC_UNSAFE_MODE;
5674 GError *eg_error = NULL;
5675 MonoString *o = NULL;
5677 glong items_written;
5680 mono_error_init (error);
5684 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5687 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5689 g_error_free (eg_error);
5692 mono_error_raise_exception (error);
5694 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5699 MonoString *o = NULL;
5701 if (!g_utf8_validate (text, -1, &end)) {
5702 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5706 len = g_utf8_strlen (text, -1);
5707 o = mono_string_new_size_checked (domain, len, error);
5710 str = mono_string_chars (o);
5712 while (text < end) {
5713 *str++ = g_utf8_get_char (text);
5714 text = g_utf8_next_char (text);
5723 * mono_string_new_wrapper:
5724 * @text: pointer to utf8 characters.
5726 * Helper function to create a string object from @text in the current domain.
5729 mono_string_new_wrapper (const char *text)
5731 MONO_REQ_GC_UNSAFE_MODE;
5733 MonoDomain *domain = mono_domain_get ();
5736 return mono_string_new (domain, text);
5743 * @class: the class of the value
5744 * @value: a pointer to the unboxed data
5746 * Returns: A newly created object which contains @value.
5749 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5751 MONO_REQ_GC_UNSAFE_MODE;
5758 g_assert (klass->valuetype);
5759 if (mono_class_is_nullable (klass))
5760 return mono_nullable_box ((guint8 *)value, klass);
5762 vtable = mono_class_vtable (domain, klass);
5765 size = mono_class_instance_size (klass);
5766 res = mono_object_new_alloc_specific_checked (vtable, &error);
5767 mono_error_raise_exception (&error); /* FIXME don't raise here */
5769 size = size - sizeof (MonoObject);
5772 g_assert (size == mono_class_value_size (klass, NULL));
5773 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5775 #if NO_UNALIGNED_ACCESS
5776 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5780 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5783 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5786 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5789 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5792 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5796 if (klass->has_finalize) {
5797 mono_object_register_finalizer (res, &error);
5798 mono_error_raise_exception (&error); /* FIXME don't raise here */
5805 * @dest: destination pointer
5806 * @src: source pointer
5807 * @klass: a valuetype class
5809 * Copy a valuetype from @src to @dest. This function must be used
5810 * when @klass contains references fields.
5813 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5815 MONO_REQ_GC_UNSAFE_MODE;
5817 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5821 * mono_value_copy_array:
5822 * @dest: destination array
5823 * @dest_idx: index in the @dest array
5824 * @src: source pointer
5825 * @count: number of items
5827 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5828 * This function must be used when @klass contains references fields.
5829 * Overlap is handled.
5832 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5834 MONO_REQ_GC_UNSAFE_MODE;
5836 int size = mono_array_element_size (dest->obj.vtable->klass);
5837 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5838 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5839 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5843 * mono_object_get_domain:
5844 * @obj: object to query
5846 * Returns: the MonoDomain where the object is hosted
5849 mono_object_get_domain (MonoObject *obj)
5851 MONO_REQ_GC_UNSAFE_MODE;
5853 return mono_object_domain (obj);
5857 * mono_object_get_class:
5858 * @obj: object to query
5860 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5862 * Returns: the MonoClass of the object.
5865 mono_object_get_class (MonoObject *obj)
5867 MONO_REQ_GC_UNSAFE_MODE;
5869 return mono_object_class (obj);
5872 * mono_object_get_size:
5873 * @o: object to query
5875 * Returns: the size, in bytes, of @o
5878 mono_object_get_size (MonoObject* o)
5880 MONO_REQ_GC_UNSAFE_MODE;
5882 MonoClass* klass = mono_object_class (o);
5883 if (klass == mono_defaults.string_class) {
5884 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5885 } else if (o->vtable->rank) {
5886 MonoArray *array = (MonoArray*)o;
5887 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5888 if (array->bounds) {
5891 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5895 return mono_class_instance_size (klass);
5900 * mono_object_unbox:
5901 * @obj: object to unbox
5903 * Returns: a pointer to the start of the valuetype boxed in this
5906 * This method will assert if the object passed is not a valuetype.
5909 mono_object_unbox (MonoObject *obj)
5911 MONO_REQ_GC_UNSAFE_MODE;
5913 /* add assert for valuetypes? */
5914 g_assert (obj->vtable->klass->valuetype);
5915 return ((char*)obj) + sizeof (MonoObject);
5919 * mono_object_isinst:
5921 * @klass: a pointer to a class
5923 * Returns: @obj if @obj is derived from @klass
5926 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5928 MONO_REQ_GC_UNSAFE_MODE;
5931 mono_class_init (klass);
5933 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5934 return mono_object_isinst_mbyref (obj, klass);
5939 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5943 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5945 MONO_REQ_GC_UNSAFE_MODE;
5955 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5956 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5960 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5961 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5964 MonoClass *oklass = vt->klass;
5965 if (mono_class_is_transparent_proxy (oklass))
5966 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5968 mono_class_setup_supertypes (klass);
5969 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5972 #ifndef DISABLE_REMOTING
5973 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5975 MonoDomain *domain = mono_domain_get ();
5977 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5978 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5979 MonoMethod *im = NULL;
5982 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5984 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5985 im = mono_object_get_virtual_method (rp, im);
5988 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5989 mono_error_raise_exception (&error); /* FIXME don't raise here */
5992 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5993 mono_error_raise_exception (&error); /* FIXME don't raise here */
5995 if (*(MonoBoolean *) mono_object_unbox(res)) {
5996 /* Update the vtable of the remote type, so it can safely cast to this new type */
5997 mono_upgrade_remote_class (domain, obj, klass);
6001 #endif /* DISABLE_REMOTING */
6006 * mono_object_castclass_mbyref:
6008 * @klass: a pointer to a class
6010 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6013 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6015 MONO_REQ_GC_UNSAFE_MODE;
6017 if (!obj) return NULL;
6018 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6020 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6022 "InvalidCastException"));
6027 MonoDomain *orig_domain;
6033 str_lookup (MonoDomain *domain, gpointer user_data)
6035 MONO_REQ_GC_UNSAFE_MODE;
6037 LDStrInfo *info = (LDStrInfo *)user_data;
6038 if (info->res || domain == info->orig_domain)
6040 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6044 mono_string_get_pinned (MonoString *str, MonoError *error)
6046 MONO_REQ_GC_UNSAFE_MODE;
6048 mono_error_init (error);
6050 /* We only need to make a pinned version of a string if this is a moving GC */
6051 if (!mono_gc_is_moving ())
6055 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6056 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6058 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6059 news->length = mono_string_length (str);
6061 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6067 mono_string_is_interned_lookup (MonoString *str, int insert)
6069 MONO_REQ_GC_UNSAFE_MODE;
6072 MonoGHashTable *ldstr_table;
6073 MonoString *s, *res;
6076 domain = ((MonoObject *)str)->vtable->domain;
6077 ldstr_table = domain->ldstr_table;
6079 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6085 /* Allocate outside the lock */
6087 s = mono_string_get_pinned (str, &error);
6088 mono_error_raise_exception (&error); /* FIXME don't raise here */
6091 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6096 mono_g_hash_table_insert (ldstr_table, s, s);
6101 LDStrInfo ldstr_info;
6102 ldstr_info.orig_domain = domain;
6103 ldstr_info.ins = str;
6104 ldstr_info.res = NULL;
6106 mono_domain_foreach (str_lookup, &ldstr_info);
6107 if (ldstr_info.res) {
6109 * the string was already interned in some other domain:
6110 * intern it in the current one as well.
6112 mono_g_hash_table_insert (ldstr_table, str, str);
6122 * mono_string_is_interned:
6123 * @o: String to probe
6125 * Returns whether the string has been interned.
6128 mono_string_is_interned (MonoString *o)
6130 MONO_REQ_GC_UNSAFE_MODE;
6132 return mono_string_is_interned_lookup (o, FALSE);
6136 * mono_string_intern:
6137 * @o: String to intern
6139 * Interns the string passed.
6140 * Returns: The interned string.
6143 mono_string_intern (MonoString *str)
6145 MONO_REQ_GC_UNSAFE_MODE;
6147 return mono_string_is_interned_lookup (str, TRUE);
6152 * @domain: the domain where the string will be used.
6153 * @image: a metadata context
6154 * @idx: index into the user string table.
6156 * Implementation for the ldstr opcode.
6157 * Returns: a loaded string from the @image/@idx combination.
6160 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6162 MONO_REQ_GC_UNSAFE_MODE;
6164 if (image->dynamic) {
6165 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6168 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6169 return NULL; /*FIXME we should probably be raising an exception here*/
6170 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6175 * mono_ldstr_metadata_sig
6176 * @domain: the domain for the string
6177 * @sig: the signature of a metadata string
6179 * Returns: a MonoString for a string stored in the metadata
6182 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6184 MONO_REQ_GC_UNSAFE_MODE;
6187 const char *str = sig;
6188 MonoString *o, *interned;
6191 len2 = mono_metadata_decode_blob_size (str, &str);
6194 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6195 mono_error_raise_exception (&error); /* FIXME don't raise here */
6196 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6199 guint16 *p2 = (guint16*)mono_string_chars (o);
6200 for (i = 0; i < len2; ++i) {
6201 *p2 = GUINT16_FROM_LE (*p2);
6207 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6210 return interned; /* o will get garbage collected */
6212 o = mono_string_get_pinned (o, &error);
6213 mono_error_raise_exception (&error); /* FIXME don't raise here */
6216 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6218 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6228 * mono_string_to_utf8:
6229 * @s: a System.String
6231 * Returns the UTF8 representation for @s.
6232 * The resulting buffer needs to be freed with mono_free().
6234 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6237 mono_string_to_utf8 (MonoString *s)
6239 MONO_REQ_GC_UNSAFE_MODE;
6242 char *result = mono_string_to_utf8_checked (s, &error);
6244 if (!mono_error_ok (&error))
6245 mono_error_raise_exception (&error);
6250 * mono_string_to_utf8_checked:
6251 * @s: a System.String
6252 * @error: a MonoError.
6254 * Converts a MonoString to its UTF8 representation. May fail; check
6255 * @error to determine whether the conversion was successful.
6256 * The resulting buffer should be freed with mono_free().
6259 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6261 MONO_REQ_GC_UNSAFE_MODE;
6265 GError *gerror = NULL;
6267 mono_error_init (error);
6273 return g_strdup ("");
6275 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6277 mono_error_set_argument (error, "string", "%s", gerror->message);
6278 g_error_free (gerror);
6281 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6282 if (s->length > written) {
6283 /* allocate the total length and copy the part of the string that has been converted */
6284 char *as2 = (char *)g_malloc0 (s->length);
6285 memcpy (as2, as, written);
6294 * mono_string_to_utf8_ignore:
6297 * Converts a MonoString to its UTF8 representation. Will ignore
6298 * invalid surrogate pairs.
6299 * The resulting buffer should be freed with mono_free().
6303 mono_string_to_utf8_ignore (MonoString *s)
6305 MONO_REQ_GC_UNSAFE_MODE;
6314 return g_strdup ("");
6316 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6318 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6319 if (s->length > written) {
6320 /* allocate the total length and copy the part of the string that has been converted */
6321 char *as2 = (char *)g_malloc0 (s->length);
6322 memcpy (as2, as, written);
6331 * mono_string_to_utf8_image_ignore:
6332 * @s: a System.String
6334 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6337 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6339 MONO_REQ_GC_UNSAFE_MODE;
6341 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6345 * mono_string_to_utf8_mp_ignore:
6346 * @s: a System.String
6348 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6351 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6353 MONO_REQ_GC_UNSAFE_MODE;
6355 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6360 * mono_string_to_utf16:
6363 * Return an null-terminated array of the utf-16 chars
6364 * contained in @s. The result must be freed with g_free().
6365 * This is a temporary helper until our string implementation
6366 * is reworked to always include the null terminating char.
6369 mono_string_to_utf16 (MonoString *s)
6371 MONO_REQ_GC_UNSAFE_MODE;
6378 as = (char *)g_malloc ((s->length * 2) + 2);
6379 as [(s->length * 2)] = '\0';
6380 as [(s->length * 2) + 1] = '\0';
6383 return (gunichar2 *)(as);
6386 memcpy (as, mono_string_chars(s), s->length * 2);
6387 return (gunichar2 *)(as);
6391 * mono_string_to_utf32:
6394 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6395 * contained in @s. The result must be freed with g_free().
6398 mono_string_to_utf32 (MonoString *s)
6400 MONO_REQ_GC_UNSAFE_MODE;
6402 mono_unichar4 *utf32_output = NULL;
6403 GError *error = NULL;
6404 glong items_written;
6409 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6412 g_error_free (error);
6414 return utf32_output;
6418 * mono_string_from_utf16:
6419 * @data: the UTF16 string (LPWSTR) to convert
6421 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6423 * Returns: a MonoString.
6426 mono_string_from_utf16 (gunichar2 *data)
6428 MONO_REQ_GC_UNSAFE_MODE;
6431 MonoString *res = NULL;
6432 MonoDomain *domain = mono_domain_get ();
6438 while (data [len]) len++;
6440 res = mono_string_new_utf16_checked (domain, data, len, &error);
6441 mono_error_raise_exception (&error); /* FIXME don't raise here */
6446 * mono_string_from_utf32:
6447 * @data: the UTF32 string (LPWSTR) to convert
6449 * Converts a UTF32 (UCS-4)to a MonoString.
6451 * Returns: a MonoString.
6454 mono_string_from_utf32 (mono_unichar4 *data)
6456 MONO_REQ_GC_UNSAFE_MODE;
6458 MonoString* result = NULL;
6459 mono_unichar2 *utf16_output = NULL;
6460 GError *error = NULL;
6461 glong items_written;
6467 while (data [len]) len++;
6469 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6472 g_error_free (error);
6474 result = mono_string_from_utf16 (utf16_output);
6475 g_free (utf16_output);
6480 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6482 MONO_REQ_GC_UNSAFE_MODE;
6489 r = mono_string_to_utf8_ignore (s);
6491 r = mono_string_to_utf8_checked (s, error);
6492 if (!mono_error_ok (error))
6499 len = strlen (r) + 1;
6501 mp_s = (char *)mono_mempool_alloc (mp, len);
6503 mp_s = (char *)mono_image_alloc (image, len);
6505 memcpy (mp_s, r, len);
6513 * mono_string_to_utf8_image:
6514 * @s: a System.String
6516 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6519 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6521 MONO_REQ_GC_UNSAFE_MODE;
6523 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6527 * mono_string_to_utf8_mp:
6528 * @s: a System.String
6530 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6533 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6535 MONO_REQ_GC_UNSAFE_MODE;
6537 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6541 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6544 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6546 eh_callbacks = *cbs;
6549 MonoRuntimeExceptionHandlingCallbacks *
6550 mono_get_eh_callbacks (void)
6552 return &eh_callbacks;
6556 * mono_raise_exception:
6557 * @ex: exception object
6559 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6562 mono_raise_exception (MonoException *ex)
6564 MONO_REQ_GC_UNSAFE_MODE;
6567 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6568 * that will cause gcc to omit the function epilog, causing problems when
6569 * the JIT tries to walk the stack, since the return address on the stack
6570 * will point into the next function in the executable, not this one.
6572 eh_callbacks.mono_raise_exception (ex);
6576 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6578 MONO_REQ_GC_UNSAFE_MODE;
6580 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6584 * mono_wait_handle_new:
6585 * @domain: Domain where the object will be created
6586 * @handle: Handle for the wait handle
6588 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6591 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6593 MONO_REQ_GC_UNSAFE_MODE;
6596 MonoWaitHandle *res;
6597 gpointer params [1];
6598 static MonoMethod *handle_set;
6600 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6601 mono_error_raise_exception (&error); /* FIXME don't raise here */
6603 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6605 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6607 params [0] = &handle;
6609 mono_runtime_invoke_checked (handle_set, res, params, &error);
6610 mono_error_raise_exception (&error); /* FIXME don't raise here */
6616 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6618 MONO_REQ_GC_UNSAFE_MODE;
6620 static MonoClassField *f_safe_handle = NULL;
6623 if (!f_safe_handle) {
6624 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6625 g_assert (f_safe_handle);
6628 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6634 mono_runtime_capture_context (MonoDomain *domain)
6636 MONO_REQ_GC_UNSAFE_MODE;
6638 RuntimeInvokeFunction runtime_invoke;
6640 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6641 MonoMethod *method = mono_get_context_capture_method ();
6642 MonoMethod *wrapper;
6645 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6646 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6647 domain->capture_context_method = mono_compile_method (method);
6650 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6652 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6655 * mono_async_result_new:
6656 * @domain:domain where the object will be created.
6657 * @handle: wait handle.
6658 * @state: state to pass to AsyncResult
6659 * @data: C closure data.
6661 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6662 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6666 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6668 MONO_REQ_GC_UNSAFE_MODE;
6671 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6672 mono_error_raise_exception (&error); /* FIXME don't raise here */
6673 MonoObject *context = mono_runtime_capture_context (domain);
6674 /* we must capture the execution context from the original thread */
6676 MONO_OBJECT_SETREF (res, execution_context, context);
6677 /* note: result may be null if the flow is suppressed */
6680 res->data = (void **)data;
6681 MONO_OBJECT_SETREF (res, object_data, object_data);
6682 MONO_OBJECT_SETREF (res, async_state, state);
6684 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6686 res->sync_completed = FALSE;
6687 res->completed = FALSE;
6693 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6695 MONO_REQ_GC_UNSAFE_MODE;
6702 g_assert (ares->async_delegate);
6704 ac = (MonoAsyncCall*) ares->object_data;
6706 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6708 gpointer wait_event = NULL;
6710 ac->msg->exc = NULL;
6711 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6712 MONO_OBJECT_SETREF (ac, res, res);
6714 mono_monitor_enter ((MonoObject*) ares);
6715 ares->completed = 1;
6717 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6718 mono_monitor_exit ((MonoObject*) ares);
6720 if (wait_event != NULL)
6721 SetEvent (wait_event);
6723 if (ac->cb_method) {
6724 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6725 mono_error_raise_exception (&error);
6733 mono_message_init (MonoDomain *domain,
6734 MonoMethodMessage *this_obj,
6735 MonoReflectionMethod *method,
6736 MonoArray *out_args)
6738 MONO_REQ_GC_UNSAFE_MODE;
6740 static MonoClass *object_array_klass;
6741 static MonoClass *byte_array_klass;
6742 static MonoClass *string_array_klass;
6744 MonoMethodSignature *sig = mono_method_signature (method->method);
6751 if (!object_array_klass) {
6754 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6756 byte_array_klass = klass;
6758 klass = mono_array_class_get (mono_defaults.string_class, 1);
6760 string_array_klass = klass;
6762 klass = mono_array_class_get (mono_defaults.object_class, 1);
6765 mono_atomic_store_release (&object_array_klass, klass);
6768 MONO_OBJECT_SETREF (this_obj, method, method);
6770 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6771 mono_error_raise_exception (&error); /* FIXME don't raise here */
6773 MONO_OBJECT_SETREF (this_obj, args, arr);
6775 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6776 mono_error_raise_exception (&error); /* FIXME don't raise here */
6778 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6780 this_obj->async_result = NULL;
6781 this_obj->call_type = CallType_Sync;
6783 names = g_new (char *, sig->param_count);
6784 mono_method_get_param_names (method->method, (const char **) names);
6786 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6787 mono_error_raise_exception (&error); /* FIXME don't raise here */
6789 MONO_OBJECT_SETREF (this_obj, names, arr);
6791 for (i = 0; i < sig->param_count; i++) {
6792 name = mono_string_new (domain, names [i]);
6793 mono_array_setref (this_obj->names, i, name);
6797 for (i = 0, j = 0; i < sig->param_count; i++) {
6798 if (sig->params [i]->byref) {
6800 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6801 mono_array_setref (this_obj->args, i, arg);
6805 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6809 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6812 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6816 #ifndef DISABLE_REMOTING
6818 * mono_remoting_invoke:
6819 * @real_proxy: pointer to a RealProxy object
6820 * @msg: The MonoMethodMessage to execute
6821 * @exc: used to store exceptions
6822 * @out_args: used to store output arguments
6824 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6825 * IMessage interface and it is not trivial to extract results from there. So
6826 * we call an helper method PrivateInvoke instead of calling
6827 * RealProxy::Invoke() directly.
6829 * Returns: the result object.
6832 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6833 MonoObject **exc, MonoArray **out_args)
6835 MONO_REQ_GC_UNSAFE_MODE;
6839 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6842 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6845 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6847 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6848 real_proxy->vtable->domain->private_invoke_method = im;
6851 pa [0] = real_proxy;
6857 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6859 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6861 mono_error_raise_exception (&error); /* FIXME don't raise here */
6868 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6869 MonoObject **exc, MonoArray **out_args)
6871 MONO_REQ_GC_UNSAFE_MODE;
6873 static MonoClass *object_array_klass;
6877 MonoMethodSignature *sig;
6880 int i, j, outarg_count = 0;
6882 #ifndef DISABLE_REMOTING
6883 if (target && mono_object_is_transparent_proxy (target)) {
6884 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6885 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6886 target = tp->rp->unwrapped_server;
6888 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6893 domain = mono_domain_get ();
6894 method = msg->method->method;
6895 sig = mono_method_signature (method);
6897 for (i = 0; i < sig->param_count; i++) {
6898 if (sig->params [i]->byref)
6902 if (!object_array_klass) {
6905 klass = mono_array_class_get (mono_defaults.object_class, 1);
6908 mono_memory_barrier ();
6909 object_array_klass = klass;
6912 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6913 mono_error_raise_exception (&error); /* FIXME don't raise here */
6915 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6918 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6920 for (i = 0, j = 0; i < sig->param_count; i++) {
6921 if (sig->params [i]->byref) {
6923 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6924 mono_array_setref (*out_args, j, arg);
6933 * mono_object_to_string:
6935 * @exc: Any exception thrown by ToString (). May be NULL.
6937 * Returns: the result of calling ToString () on an object.
6940 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6942 MONO_REQ_GC_UNSAFE_MODE;
6944 static MonoMethod *to_string = NULL;
6953 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6955 method = mono_object_get_virtual_method (obj, to_string);
6957 // Unbox value type if needed
6958 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6959 target = mono_object_unbox (obj);
6963 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6964 if (*exc == NULL && !mono_error_ok (&error))
6965 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6967 mono_error_cleanup (&error);
6969 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6970 mono_error_raise_exception (&error); /* FIXME don't raise here */
6977 * mono_print_unhandled_exception:
6978 * @exc: The exception
6980 * Prints the unhandled exception.
6983 mono_print_unhandled_exception (MonoObject *exc)
6985 MONO_REQ_GC_UNSAFE_MODE;
6988 char *message = (char*)"";
6989 gboolean free_message = FALSE;
6992 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6993 message = g_strdup ("OutOfMemoryException");
6994 free_message = TRUE;
6995 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6996 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6997 free_message = TRUE;
7000 if (((MonoException*)exc)->native_trace_ips) {
7001 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7002 free_message = TRUE;
7004 MonoObject *other_exc = NULL;
7005 str = mono_object_to_string (exc, &other_exc);
7007 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7008 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7010 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7011 original_backtrace, nested_backtrace);
7013 g_free (original_backtrace);
7014 g_free (nested_backtrace);
7015 free_message = TRUE;
7017 message = mono_string_to_utf8_checked (str, &error);
7018 if (!mono_error_ok (&error)) {
7019 mono_error_cleanup (&error);
7020 message = (char *) "";
7022 free_message = TRUE;
7029 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7030 * exc->vtable->klass->name, message);
7032 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7039 * mono_delegate_ctor:
7040 * @this: pointer to an uninitialized delegate object
7041 * @target: target object
7042 * @addr: pointer to native code
7045 * Initialize a delegate and sets a specific method, not the one
7046 * associated with addr. This is useful when sharing generic code.
7047 * In that case addr will most probably not be associated with the
7048 * correct instantiation of the method.
7051 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7053 MONO_REQ_GC_UNSAFE_MODE;
7055 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7057 g_assert (this_obj);
7060 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7063 delegate->method = method;
7065 mono_stats.delegate_creations++;
7067 #ifndef DISABLE_REMOTING
7068 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7070 method = mono_marshal_get_remoting_invoke (method);
7071 delegate->method_ptr = mono_compile_method (method);
7072 MONO_OBJECT_SETREF (delegate, target, target);
7076 delegate->method_ptr = addr;
7077 MONO_OBJECT_SETREF (delegate, target, target);
7080 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7081 if (callbacks.init_delegate)
7082 callbacks.init_delegate (delegate);
7086 * mono_delegate_ctor:
7087 * @this: pointer to an uninitialized delegate object
7088 * @target: target object
7089 * @addr: pointer to native code
7091 * This is used to initialize a delegate.
7094 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7096 MONO_REQ_GC_UNSAFE_MODE;
7098 MonoDomain *domain = mono_domain_get ();
7100 MonoMethod *method = NULL;
7104 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7106 if (!ji && domain != mono_get_root_domain ())
7107 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7109 method = mono_jit_info_get_method (ji);
7110 g_assert (!method->klass->generic_container);
7113 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7117 * mono_method_call_message_new:
7118 * @method: method to encapsulate
7119 * @params: parameters to the method
7120 * @invoke: optional, delegate invoke.
7121 * @cb: async callback delegate.
7122 * @state: state passed to the async callback.
7124 * Translates arguments pointers into a MonoMethodMessage.
7127 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7128 MonoDelegate **cb, MonoObject **state)
7130 MONO_REQ_GC_UNSAFE_MODE;
7134 MonoDomain *domain = mono_domain_get ();
7135 MonoMethodSignature *sig = mono_method_signature (method);
7136 MonoMethodMessage *msg;
7139 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7140 mono_error_raise_exception (&error); /* FIXME don't raise here */
7143 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7144 mono_error_raise_exception (&error); /* FIXME don't raise here */
7145 mono_message_init (domain, msg, rm, NULL);
7146 count = sig->param_count - 2;
7148 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7149 mono_error_raise_exception (&error); /* FIXME don't raise here */
7150 mono_message_init (domain, msg, rm, NULL);
7151 count = sig->param_count;
7154 for (i = 0; i < count; i++) {
7159 if (sig->params [i]->byref)
7160 vpos = *((gpointer *)params [i]);
7164 klass = mono_class_from_mono_type (sig->params [i]);
7166 if (klass->valuetype)
7167 arg = mono_value_box (domain, klass, vpos);
7169 arg = *((MonoObject **)vpos);
7171 mono_array_setref (msg->args, i, arg);
7174 if (cb != NULL && state != NULL) {
7175 *cb = *((MonoDelegate **)params [i]);
7177 *state = *((MonoObject **)params [i]);
7184 * mono_method_return_message_restore:
7186 * Restore results from message based processing back to arguments pointers
7189 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7191 MONO_REQ_GC_UNSAFE_MODE;
7193 MonoMethodSignature *sig = mono_method_signature (method);
7194 int i, j, type, size, out_len;
7196 if (out_args == NULL)
7198 out_len = mono_array_length (out_args);
7202 for (i = 0, j = 0; i < sig->param_count; i++) {
7203 MonoType *pt = sig->params [i];
7208 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7210 arg = (char *)mono_array_get (out_args, gpointer, j);
7213 g_assert (type != MONO_TYPE_VOID);
7215 if (MONO_TYPE_IS_REFERENCE (pt)) {
7216 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7219 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7220 size = mono_class_value_size (klass, NULL);
7221 if (klass->has_references)
7222 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7224 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7226 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7227 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7236 #ifndef DISABLE_REMOTING
7239 * mono_load_remote_field:
7240 * @this: pointer to an object
7241 * @klass: klass of the object containing @field
7242 * @field: the field to load
7243 * @res: a storage to store the result
7245 * This method is called by the runtime on attempts to load fields of
7246 * transparent proxy objects. @this points to such TP, @klass is the class of
7247 * the object containing @field. @res is a storage location which can be
7248 * used to store the result.
7250 * Returns: an address pointing to the value of field.
7253 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7255 MONO_REQ_GC_UNSAFE_MODE;
7259 static MonoMethod *getter = NULL;
7260 MonoDomain *domain = mono_domain_get ();
7261 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7262 MonoClass *field_class;
7263 MonoMethodMessage *msg;
7264 MonoArray *out_args;
7268 g_assert (mono_object_is_transparent_proxy (this_obj));
7269 g_assert (res != NULL);
7271 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7272 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7277 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7279 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7282 field_class = mono_class_from_mono_type (field->type);
7284 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7285 mono_error_raise_exception (&error); /* FIXME don't raise here */
7286 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7287 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7288 mono_error_raise_exception (&error); /* FIXME don't raise here */
7289 mono_message_init (domain, msg, rm, out_args);
7291 full_name = mono_type_get_full_name (klass);
7292 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7293 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7296 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7298 if (exc) mono_raise_exception ((MonoException *)exc);
7300 if (mono_array_length (out_args) == 0)
7303 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7305 if (field_class->valuetype) {
7306 return ((char *)*res) + sizeof (MonoObject);
7312 * mono_load_remote_field_new:
7317 * Missing documentation.
7320 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7322 MONO_REQ_GC_UNSAFE_MODE;
7326 static MonoMethod *getter = NULL;
7327 MonoDomain *domain = mono_domain_get ();
7328 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7329 MonoClass *field_class;
7330 MonoMethodMessage *msg;
7331 MonoArray *out_args;
7332 MonoObject *exc, *res;
7335 g_assert (mono_object_is_transparent_proxy (this_obj));
7337 field_class = mono_class_from_mono_type (field->type);
7339 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7341 if (field_class->valuetype) {
7342 res = mono_object_new_checked (domain, field_class, &error);
7343 mono_error_raise_exception (&error); /* FIXME don't raise here */
7344 val = ((gchar *) res) + sizeof (MonoObject);
7348 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7353 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7355 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7358 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7359 mono_error_raise_exception (&error); /* FIXME don't raise here */
7360 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7362 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7363 mono_error_raise_exception (&error); /* FIXME don't raise here */
7364 mono_message_init (domain, msg, rm, out_args);
7366 full_name = mono_type_get_full_name (klass);
7367 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7368 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7371 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7373 if (exc) mono_raise_exception ((MonoException *)exc);
7375 if (mono_array_length (out_args) == 0)
7378 res = mono_array_get (out_args, MonoObject *, 0);
7384 * mono_store_remote_field:
7385 * @this_obj: pointer to an object
7386 * @klass: klass of the object containing @field
7387 * @field: the field to load
7388 * @val: the value/object to store
7390 * This method is called by the runtime on attempts to store fields of
7391 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7392 * the object containing @field. @val is the new value to store in @field.
7395 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7397 MONO_REQ_GC_UNSAFE_MODE;
7401 static MonoMethod *setter = NULL;
7402 MonoDomain *domain = mono_domain_get ();
7403 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7404 MonoClass *field_class;
7405 MonoMethodMessage *msg;
7406 MonoArray *out_args;
7411 g_assert (mono_object_is_transparent_proxy (this_obj));
7413 field_class = mono_class_from_mono_type (field->type);
7415 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7416 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7417 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7422 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7424 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7427 if (field_class->valuetype)
7428 arg = mono_value_box (domain, field_class, val);
7430 arg = *((MonoObject **)val);
7433 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7434 mono_error_raise_exception (&error); /* FIXME don't raise here */
7435 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7436 mono_error_raise_exception (&error); /* FIXME don't raise here */
7437 mono_message_init (domain, msg, rm, NULL);
7439 full_name = mono_type_get_full_name (klass);
7440 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7441 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7442 mono_array_setref (msg->args, 2, arg);
7445 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7447 if (exc) mono_raise_exception ((MonoException *)exc);
7451 * mono_store_remote_field_new:
7457 * Missing documentation
7460 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7462 MONO_REQ_GC_UNSAFE_MODE;
7466 static MonoMethod *setter = NULL;
7467 MonoDomain *domain = mono_domain_get ();
7468 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7469 MonoClass *field_class;
7470 MonoMethodMessage *msg;
7471 MonoArray *out_args;
7475 g_assert (mono_object_is_transparent_proxy (this_obj));
7477 field_class = mono_class_from_mono_type (field->type);
7479 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7480 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7481 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7486 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7488 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7491 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7492 mono_error_raise_exception (&error); /* FIXME don't raise here */
7493 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7494 mono_error_raise_exception (&error); /* FIXME don't raise here */
7495 mono_message_init (domain, msg, rm, NULL);
7497 full_name = mono_type_get_full_name (klass);
7498 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7499 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7500 mono_array_setref (msg->args, 2, arg);
7503 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7505 if (exc) mono_raise_exception ((MonoException *)exc);
7510 * mono_create_ftnptr:
7512 * Given a function address, create a function descriptor for it.
7513 * This is only needed on some platforms.
7516 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7518 return callbacks.create_ftnptr (domain, addr);
7522 * mono_get_addr_from_ftnptr:
7524 * Given a pointer to a function descriptor, return the function address.
7525 * This is only needed on some platforms.
7528 mono_get_addr_from_ftnptr (gpointer descr)
7530 return callbacks.get_addr_from_ftnptr (descr);
7534 * mono_string_chars:
7537 * Returns a pointer to the UCS16 characters stored in the MonoString
7540 mono_string_chars (MonoString *s)
7542 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7548 * mono_string_length:
7551 * Returns the lenght in characters of the string
7554 mono_string_length (MonoString *s)
7556 MONO_REQ_GC_UNSAFE_MODE;
7562 * mono_array_length:
7563 * @array: a MonoArray*
7565 * Returns the total number of elements in the array. This works for
7566 * both vectors and multidimensional arrays.
7569 mono_array_length (MonoArray *array)
7571 MONO_REQ_GC_UNSAFE_MODE;
7573 return array->max_length;
7577 * mono_array_addr_with_size:
7578 * @array: a MonoArray*
7579 * @size: size of the array elements
7580 * @idx: index into the array
7582 * Use this function to obtain the address for the @idx item on the
7583 * @array containing elements of size @size.
7585 * This method performs no bounds checking or type checking.
7587 * Returns the address of the @idx element in the array.
7590 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7592 MONO_REQ_GC_UNSAFE_MODE;
7594 return ((char*)(array)->vector) + size * idx;
7599 mono_glist_to_array (GList *list, MonoClass *eclass)
7601 MonoDomain *domain = mono_domain_get ();
7608 len = g_list_length (list);
7609 res = mono_array_new (domain, eclass, len);
7611 for (i = 0; list; list = list->next, i++)
7612 mono_array_set (res, gpointer, i, list->data);
7619 * The following section is purely to declare prototypes and
7620 * document the API, as these C files are processed by our
7626 * @array: array to alter
7627 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7628 * @index: index into the array
7629 * @value: value to set
7631 * Value Type version: This sets the @index's element of the @array
7632 * with elements of size sizeof(type) to the provided @value.
7634 * This macro does not attempt to perform type checking or bounds checking.
7636 * Use this to set value types in a `MonoArray`.
7638 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7643 * mono_array_setref:
7644 * @array: array to alter
7645 * @index: index into the array
7646 * @value: value to set
7648 * Reference Type version: This sets the @index's element of the
7649 * @array with elements of size sizeof(type) to the provided @value.
7651 * This macro does not attempt to perform type checking or bounds checking.
7653 * Use this to reference types in a `MonoArray`.
7655 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7661 * @array: array on which to operate on
7662 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7663 * @index: index into the array
7665 * Use this macro to retrieve the @index element of an @array and
7666 * extract the value assuming that the elements of the array match
7667 * the provided type value.
7669 * This method can be used with both arrays holding value types and
7670 * reference types. For reference types, the @type parameter should
7671 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7673 * This macro does not attempt to perform type checking or bounds checking.
7675 * Returns: The element at the @index position in the @array.
7677 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)