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 if (!mono_error_ok (&error))
2165 mono_error_raise_exception (&error); /* FIXME: Don't raise here */
2170 if (imt_table_bytes) {
2171 /* Now that the vtable is full, we can actually fill up the IMT */
2172 for (i = 0; i < MONO_IMT_SIZE; ++i)
2173 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2177 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2178 * re-acquire them and check if another thread has created the vtable in the meantime.
2180 /* Special case System.MonoType to avoid infinite recursion */
2181 if (klass != mono_defaults.monotype_class) {
2182 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2183 if (!is_ok (error)) {
2184 mono_domain_unlock (domain);
2185 mono_loader_unlock ();
2189 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2190 /* This is unregistered in
2191 unregister_vtable_reflection_type() in
2193 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2196 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2198 /* class_vtable_array keeps an array of created vtables
2200 g_ptr_array_add (domain->class_vtable_array, vt);
2201 /* klass->runtime_info is protected by the loader lock, both when
2202 * it it enlarged and when it is stored info.
2206 * Store the vtable in klass->runtime_info.
2207 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2209 mono_memory_barrier ();
2211 old_info = klass->runtime_info;
2212 if (old_info && old_info->max_domain >= domain->domain_id) {
2213 /* someone already created a large enough runtime info */
2214 old_info->domain_vtables [domain->domain_id] = vt;
2216 int new_size = domain->domain_id;
2218 new_size = MAX (new_size, old_info->max_domain);
2220 /* make the new size a power of two */
2222 while (new_size > i)
2225 /* this is a bounded memory retention issue: may want to
2226 * handle it differently when we'll have a rcu-like system.
2228 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2229 runtime_info->max_domain = new_size - 1;
2230 /* copy the stuff from the older info */
2232 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2234 runtime_info->domain_vtables [domain->domain_id] = vt;
2236 mono_memory_barrier ();
2237 klass->runtime_info = runtime_info;
2240 if (klass == mono_defaults.monotype_class) {
2241 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2242 if (!is_ok (error)) {
2243 mono_domain_unlock (domain);
2244 mono_loader_unlock ();
2248 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2249 /* This is unregistered in
2250 unregister_vtable_reflection_type() in
2252 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2255 mono_domain_unlock (domain);
2256 mono_loader_unlock ();
2258 /* make sure the parent is initialized */
2259 /*FIXME shouldn't this fail the current type?*/
2261 mono_class_vtable_full (domain, klass->parent, error);
2266 #ifndef DISABLE_REMOTING
2268 * mono_class_proxy_vtable:
2269 * @domain: the application domain
2270 * @remove_class: the remote class
2272 * Creates a vtable for transparent proxies. It is basically
2273 * a copy of the real vtable of the class wrapped in @remote_class,
2274 * but all function pointers invoke the remoting functions, and
2275 * vtable->klass points to the transparent proxy class, and not to @class.
2278 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2280 MONO_REQ_GC_UNSAFE_MODE;
2283 MonoVTable *vt, *pvt;
2284 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2286 GSList *extra_interfaces = NULL;
2287 MonoClass *klass = remote_class->proxy_class;
2288 gpointer *interface_offsets;
2291 size_t imt_table_bytes;
2293 #ifdef COMPRESSED_INTERFACE_BITMAP
2297 vt = mono_class_vtable (domain, klass);
2298 g_assert (vt); /*FIXME property handle failure*/
2299 max_interface_id = vt->max_interface_id;
2301 /* Calculate vtable space for extra interfaces */
2302 for (j = 0; j < remote_class->interface_count; j++) {
2303 MonoClass* iclass = remote_class->interfaces[j];
2307 /*FIXME test for interfaces with variant generic arguments*/
2308 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2309 continue; /* interface implemented by the class */
2310 if (g_slist_find (extra_interfaces, iclass))
2313 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2315 method_count = mono_class_num_methods (iclass);
2317 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2318 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2320 for (i = 0; i < ifaces->len; ++i) {
2321 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2322 /*FIXME test for interfaces with variant generic arguments*/
2323 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2324 continue; /* interface implemented by the class */
2325 if (g_slist_find (extra_interfaces, ic))
2327 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2328 method_count += mono_class_num_methods (ic);
2330 g_ptr_array_free (ifaces, TRUE);
2333 extra_interface_vtsize += method_count * sizeof (gpointer);
2334 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2337 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2338 mono_stats.imt_number_of_tables++;
2339 mono_stats.imt_tables_size += imt_table_bytes;
2341 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2343 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2345 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2346 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2347 g_assert (!((gsize)pvt & 7));
2349 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2351 pvt->klass = mono_defaults.transparent_proxy_class;
2352 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2353 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2355 /* initialize vtable */
2356 mono_class_setup_vtable (klass);
2357 for (i = 0; i < klass->vtable_size; ++i) {
2360 if ((cm = klass->vtable [i]))
2361 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2363 pvt->vtable [i] = NULL;
2366 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2367 /* create trampolines for abstract methods */
2368 for (k = klass; k; k = k->parent) {
2370 gpointer iter = NULL;
2371 while ((m = mono_class_get_methods (k, &iter)))
2372 if (!pvt->vtable [m->slot])
2373 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2377 pvt->max_interface_id = max_interface_id;
2378 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2379 #ifdef COMPRESSED_INTERFACE_BITMAP
2380 bitmap = (uint8_t *)g_malloc0 (bsize);
2382 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2385 for (i = 0; i < klass->interface_offsets_count; ++i) {
2386 int interface_id = klass->interfaces_packed [i]->interface_id;
2387 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2390 if (extra_interfaces) {
2391 int slot = klass->vtable_size;
2397 /* Create trampolines for the methods of the interfaces */
2398 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2399 interf = (MonoClass *)list_item->data;
2401 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2405 while ((cm = mono_class_get_methods (interf, &iter)))
2406 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2408 slot += mono_class_num_methods (interf);
2412 /* Now that the vtable is full, we can actually fill up the IMT */
2413 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2414 if (extra_interfaces) {
2415 g_slist_free (extra_interfaces);
2418 #ifdef COMPRESSED_INTERFACE_BITMAP
2419 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2420 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2421 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2424 pvt->interface_bitmap = bitmap;
2429 #endif /* DISABLE_REMOTING */
2432 * mono_class_field_is_special_static:
2434 * Returns whether @field is a thread/context static field.
2437 mono_class_field_is_special_static (MonoClassField *field)
2439 MONO_REQ_GC_NEUTRAL_MODE
2441 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2443 if (mono_field_is_deleted (field))
2445 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2446 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2453 * mono_class_field_get_special_static_type:
2454 * @field: The MonoClassField describing the field.
2456 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2457 * SPECIAL_STATIC_NONE otherwise.
2460 mono_class_field_get_special_static_type (MonoClassField *field)
2462 MONO_REQ_GC_NEUTRAL_MODE
2464 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2465 return SPECIAL_STATIC_NONE;
2466 if (mono_field_is_deleted (field))
2467 return SPECIAL_STATIC_NONE;
2468 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2469 return field_is_special_static (field->parent, field);
2470 return SPECIAL_STATIC_NONE;
2474 * mono_class_has_special_static_fields:
2476 * Returns whenever @klass has any thread/context static fields.
2479 mono_class_has_special_static_fields (MonoClass *klass)
2481 MONO_REQ_GC_NEUTRAL_MODE
2483 MonoClassField *field;
2487 while ((field = mono_class_get_fields (klass, &iter))) {
2488 g_assert (field->parent == klass);
2489 if (mono_class_field_is_special_static (field))
2496 #ifndef DISABLE_REMOTING
2498 * create_remote_class_key:
2499 * Creates an array of pointers that can be used as a hash key for a remote class.
2500 * The first element of the array is the number of pointers.
2503 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2505 MONO_REQ_GC_NEUTRAL_MODE;
2510 if (remote_class == NULL) {
2511 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2512 key = (void **)g_malloc (sizeof(gpointer) * 3);
2513 key [0] = GINT_TO_POINTER (2);
2514 key [1] = mono_defaults.marshalbyrefobject_class;
2515 key [2] = extra_class;
2517 key = (void **)g_malloc (sizeof(gpointer) * 2);
2518 key [0] = GINT_TO_POINTER (1);
2519 key [1] = extra_class;
2522 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2523 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2524 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2525 key [1] = remote_class->proxy_class;
2527 // Keep the list of interfaces sorted
2528 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2529 if (extra_class && remote_class->interfaces [i] > extra_class) {
2530 key [j++] = extra_class;
2533 key [j] = remote_class->interfaces [i];
2536 key [j] = extra_class;
2538 // Replace the old class. The interface list is the same
2539 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2540 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2541 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2542 for (i = 0; i < remote_class->interface_count; i++)
2543 key [2 + i] = remote_class->interfaces [i];
2551 * copy_remote_class_key:
2553 * Make a copy of KEY in the domain and return the copy.
2556 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2558 MONO_REQ_GC_NEUTRAL_MODE
2560 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2561 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2563 memcpy (mp_key, key, key_size);
2569 * mono_remote_class:
2570 * @domain: the application domain
2571 * @class_name: name of the remote class
2573 * Creates and initializes a MonoRemoteClass object for a remote type.
2575 * Can raise an exception on failure.
2578 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2580 MONO_REQ_GC_UNSAFE_MODE;
2583 MonoRemoteClass *rc;
2584 gpointer* key, *mp_key;
2587 key = create_remote_class_key (NULL, proxy_class);
2589 mono_domain_lock (domain);
2590 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2594 mono_domain_unlock (domain);
2598 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2599 if (!mono_error_ok (&error)) {
2601 mono_domain_unlock (domain);
2602 mono_error_raise_exception (&error);
2605 mp_key = copy_remote_class_key (domain, key);
2609 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2610 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2611 rc->interface_count = 1;
2612 rc->interfaces [0] = proxy_class;
2613 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2615 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2616 rc->interface_count = 0;
2617 rc->proxy_class = proxy_class;
2620 rc->default_vtable = NULL;
2621 rc->xdomain_vtable = NULL;
2622 rc->proxy_class_name = name;
2623 #ifndef DISABLE_PERFCOUNTERS
2624 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2627 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2629 mono_domain_unlock (domain);
2634 * clone_remote_class:
2635 * Creates a copy of the remote_class, adding the provided class or interface
2637 static MonoRemoteClass*
2638 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2640 MONO_REQ_GC_NEUTRAL_MODE;
2642 MonoRemoteClass *rc;
2643 gpointer* key, *mp_key;
2645 key = create_remote_class_key (remote_class, extra_class);
2646 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2652 mp_key = copy_remote_class_key (domain, key);
2656 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2658 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2659 rc->proxy_class = remote_class->proxy_class;
2660 rc->interface_count = remote_class->interface_count + 1;
2662 // Keep the list of interfaces sorted, since the hash key of
2663 // the remote class depends on this
2664 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2665 if (remote_class->interfaces [i] > extra_class && i == j)
2666 rc->interfaces [j++] = extra_class;
2667 rc->interfaces [j] = remote_class->interfaces [i];
2670 rc->interfaces [j] = extra_class;
2672 // Replace the old class. The interface array is the same
2673 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2674 rc->proxy_class = extra_class;
2675 rc->interface_count = remote_class->interface_count;
2676 if (rc->interface_count > 0)
2677 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2680 rc->default_vtable = NULL;
2681 rc->xdomain_vtable = NULL;
2682 rc->proxy_class_name = remote_class->proxy_class_name;
2684 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2690 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2692 MONO_REQ_GC_UNSAFE_MODE;
2694 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2695 mono_domain_lock (domain);
2696 if (rp->target_domain_id != -1) {
2697 if (remote_class->xdomain_vtable == NULL)
2698 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2699 mono_domain_unlock (domain);
2700 mono_loader_unlock ();
2701 return remote_class->xdomain_vtable;
2703 if (remote_class->default_vtable == NULL) {
2706 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2707 klass = mono_class_from_mono_type (type);
2709 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)))
2710 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2713 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2716 mono_domain_unlock (domain);
2717 mono_loader_unlock ();
2718 return remote_class->default_vtable;
2722 * mono_upgrade_remote_class:
2723 * @domain: the application domain
2724 * @tproxy: the proxy whose remote class has to be upgraded.
2725 * @klass: class to which the remote class can be casted.
2727 * Updates the vtable of the remote class by adding the necessary method slots
2728 * and interface offsets so it can be safely casted to klass. klass can be a
2729 * class or an interface.
2732 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2734 MONO_REQ_GC_UNSAFE_MODE;
2736 MonoTransparentProxy *tproxy;
2737 MonoRemoteClass *remote_class;
2738 gboolean redo_vtable;
2740 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2741 mono_domain_lock (domain);
2743 tproxy = (MonoTransparentProxy*) proxy_object;
2744 remote_class = tproxy->remote_class;
2746 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2749 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2750 if (remote_class->interfaces [i] == klass)
2751 redo_vtable = FALSE;
2754 redo_vtable = (remote_class->proxy_class != klass);
2758 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2759 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2762 mono_domain_unlock (domain);
2763 mono_loader_unlock ();
2765 #endif /* DISABLE_REMOTING */
2769 * mono_object_get_virtual_method:
2770 * @obj: object to operate on.
2773 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2774 * the instance of a callvirt of method.
2777 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2779 MONO_REQ_GC_UNSAFE_MODE;
2782 MonoMethod **vtable;
2783 gboolean is_proxy = FALSE;
2784 MonoMethod *res = NULL;
2786 klass = mono_object_class (obj);
2787 #ifndef DISABLE_REMOTING
2788 if (klass == mono_defaults.transparent_proxy_class) {
2789 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2794 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2797 mono_class_setup_vtable (klass);
2798 vtable = klass->vtable;
2800 if (method->slot == -1) {
2801 /* method->slot might not be set for instances of generic methods */
2802 if (method->is_inflated) {
2803 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2804 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2807 g_assert_not_reached ();
2811 /* check method->slot is a valid index: perform isinstance? */
2812 if (method->slot != -1) {
2813 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2815 gboolean variance_used = FALSE;
2816 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2817 g_assert (iface_offset > 0);
2818 res = vtable [iface_offset + method->slot];
2821 res = vtable [method->slot];
2825 #ifndef DISABLE_REMOTING
2827 /* It may be an interface, abstract class method or generic method */
2828 if (!res || mono_method_signature (res)->generic_param_count)
2831 /* generic methods demand invoke_with_check */
2832 if (mono_method_signature (res)->generic_param_count)
2833 res = mono_marshal_get_remoting_invoke_with_check (res);
2836 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2837 res = mono_cominterop_get_invoke (res);
2840 res = mono_marshal_get_remoting_invoke (res);
2845 if (method->is_inflated) {
2847 /* Have to inflate the result */
2848 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2849 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2859 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2861 MONO_REQ_GC_UNSAFE_MODE;
2863 MonoObject *result = NULL;
2865 g_assert (callbacks.runtime_invoke);
2867 mono_error_init (error);
2869 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2870 mono_profiler_method_start_invoke (method);
2872 MONO_PREPARE_RESET_BLOCKING;
2874 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2876 MONO_FINISH_RESET_BLOCKING;
2878 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2879 mono_profiler_method_end_invoke (method);
2881 if (!mono_error_ok (error))
2888 * mono_runtime_invoke:
2889 * @method: method to invoke
2890 * @obJ: object instance
2891 * @params: arguments to the method
2892 * @exc: exception information.
2894 * Invokes the method represented by @method on the object @obj.
2896 * obj is the 'this' pointer, it should be NULL for static
2897 * methods, a MonoObject* for object instances and a pointer to
2898 * the value type for value types.
2900 * The params array contains the arguments to the method with the
2901 * same convention: MonoObject* pointers for object instances and
2902 * pointers to the value type otherwise.
2904 * From unmanaged code you'll usually use the
2905 * mono_runtime_invoke() variant.
2907 * Note that this function doesn't handle virtual methods for
2908 * you, it will exec the exact method you pass: we still need to
2909 * expose a function to lookup the derived class implementation
2910 * of a virtual method (there are examples of this in the code,
2913 * You can pass NULL as the exc argument if you don't want to
2914 * catch exceptions, otherwise, *exc will be set to the exception
2915 * thrown, if any. if an exception is thrown, you can't use the
2916 * MonoObject* result from the function.
2918 * If the method returns a value type, it is boxed in an object
2922 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2927 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2928 if (*exc == NULL && !mono_error_ok(&error)) {
2929 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2931 mono_error_cleanup (&error);
2933 res = mono_runtime_invoke_checked (method, obj, params, &error);
2934 mono_error_raise_exception (&error);
2940 * mono_runtime_try_invoke:
2941 * @method: method to invoke
2942 * @obJ: object instance
2943 * @params: arguments to the method
2944 * @exc: exception information.
2945 * @error: set on error
2947 * Invokes the method represented by @method on the object @obj.
2949 * obj is the 'this' pointer, it should be NULL for static
2950 * methods, a MonoObject* for object instances and a pointer to
2951 * the value type for value types.
2953 * The params array contains the arguments to the method with the
2954 * same convention: MonoObject* pointers for object instances and
2955 * pointers to the value type otherwise.
2957 * From unmanaged code you'll usually use the
2958 * mono_runtime_invoke() variant.
2960 * Note that this function doesn't handle virtual methods for
2961 * you, it will exec the exact method you pass: we still need to
2962 * expose a function to lookup the derived class implementation
2963 * of a virtual method (there are examples of this in the code,
2966 * For this function, you must not pass NULL as the exc argument if
2967 * you don't want to catch exceptions, use
2968 * mono_runtime_invoke_checked(). If an exception is thrown, you
2969 * can't use the MonoObject* result from the function.
2971 * If this method cannot be invoked, @error will be set and @exc and
2972 * the return value must not be used.
2974 * If the method returns a value type, it is boxed in an object
2978 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2980 MONO_REQ_GC_UNSAFE_MODE;
2982 g_assert (exc != NULL);
2984 if (mono_runtime_get_no_exec ())
2985 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2987 return do_runtime_invoke (method, obj, params, exc, error);
2991 * mono_runtime_invoke_checked:
2992 * @method: method to invoke
2993 * @obJ: object instance
2994 * @params: arguments to the method
2995 * @error: set on error
2997 * Invokes the method represented by @method on the object @obj.
2999 * obj is the 'this' pointer, it should be NULL for static
3000 * methods, a MonoObject* for object instances and a pointer to
3001 * the value type for value types.
3003 * The params array contains the arguments to the method with the
3004 * same convention: MonoObject* pointers for object instances and
3005 * pointers to the value type otherwise.
3007 * From unmanaged code you'll usually use the
3008 * mono_runtime_invoke() variant.
3010 * Note that this function doesn't handle virtual methods for
3011 * you, it will exec the exact method you pass: we still need to
3012 * expose a function to lookup the derived class implementation
3013 * of a virtual method (there are examples of this in the code,
3016 * If an exception is thrown, you can't use the MonoObject* result
3017 * from the function.
3019 * If this method cannot be invoked, @error will be set. If the
3020 * method throws an exception (and we're in coop mode) the exception
3021 * will be set in @error.
3023 * If the method returns a value type, it is boxed in an object
3027 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3029 MONO_REQ_GC_UNSAFE_MODE;
3031 if (mono_runtime_get_no_exec ())
3032 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3034 return do_runtime_invoke (method, obj, params, NULL, error);
3038 * mono_method_get_unmanaged_thunk:
3039 * @method: method to generate a thunk for.
3041 * Returns an unmanaged->managed thunk that can be used to call
3042 * a managed method directly from C.
3044 * The thunk's C signature closely matches the managed signature:
3046 * C#: public bool Equals (object obj);
3047 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3048 * MonoObject*, MonoException**);
3050 * The 1st ("this") parameter must not be used with static methods:
3052 * C#: public static bool ReferenceEquals (object a, object b);
3053 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3056 * The last argument must be a non-null pointer of a MonoException* pointer.
3057 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3058 * exception has been thrown in managed code. Otherwise it will point
3059 * to the MonoException* caught by the thunk. In this case, the result of
3060 * the thunk is undefined:
3062 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3063 * MonoException *ex = NULL;
3064 * Equals func = mono_method_get_unmanaged_thunk (method);
3065 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3067 * // handle exception
3070 * The calling convention of the thunk matches the platform's default
3071 * convention. This means that under Windows, C declarations must
3072 * contain the __stdcall attribute:
3074 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3075 * MonoObject*, MonoException**);
3079 * Value type arguments and return values are treated as they were objects:
3081 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3082 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3084 * Arguments must be properly boxed upon trunk's invocation, while return
3085 * values must be unboxed.
3088 mono_method_get_unmanaged_thunk (MonoMethod *method)
3090 MONO_REQ_GC_NEUTRAL_MODE;
3091 MONO_REQ_API_ENTRYPOINT;
3095 MONO_PREPARE_RESET_BLOCKING;
3096 method = mono_marshal_get_thunk_invoke_wrapper (method);
3097 res = mono_compile_method (method);
3098 MONO_FINISH_RESET_BLOCKING;
3104 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3106 MONO_REQ_GC_UNSAFE_MODE;
3110 /* object fields cannot be byref, so we don't need a
3112 gpointer *p = (gpointer*)dest;
3119 case MONO_TYPE_BOOLEAN:
3121 case MONO_TYPE_U1: {
3122 guint8 *p = (guint8*)dest;
3123 *p = value ? *(guint8*)value : 0;
3128 case MONO_TYPE_CHAR: {
3129 guint16 *p = (guint16*)dest;
3130 *p = value ? *(guint16*)value : 0;
3133 #if SIZEOF_VOID_P == 4
3138 case MONO_TYPE_U4: {
3139 gint32 *p = (gint32*)dest;
3140 *p = value ? *(gint32*)value : 0;
3143 #if SIZEOF_VOID_P == 8
3148 case MONO_TYPE_U8: {
3149 gint64 *p = (gint64*)dest;
3150 *p = value ? *(gint64*)value : 0;
3153 case MONO_TYPE_R4: {
3154 float *p = (float*)dest;
3155 *p = value ? *(float*)value : 0;
3158 case MONO_TYPE_R8: {
3159 double *p = (double*)dest;
3160 *p = value ? *(double*)value : 0;
3163 case MONO_TYPE_STRING:
3164 case MONO_TYPE_SZARRAY:
3165 case MONO_TYPE_CLASS:
3166 case MONO_TYPE_OBJECT:
3167 case MONO_TYPE_ARRAY:
3168 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3170 case MONO_TYPE_FNPTR:
3171 case MONO_TYPE_PTR: {
3172 gpointer *p = (gpointer*)dest;
3173 *p = deref_pointer? *(gpointer*)value: value;
3176 case MONO_TYPE_VALUETYPE:
3177 /* note that 't' and 'type->type' can be different */
3178 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3179 t = mono_class_enum_basetype (type->data.klass)->type;
3182 MonoClass *klass = mono_class_from_mono_type (type);
3183 int size = mono_class_value_size (klass, NULL);
3185 mono_gc_bzero_atomic (dest, size);
3187 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3190 case MONO_TYPE_GENERICINST:
3191 t = type->data.generic_class->container_class->byval_arg.type;
3194 g_error ("got type %x", type->type);
3199 * mono_field_set_value:
3200 * @obj: Instance object
3201 * @field: MonoClassField describing the field to set
3202 * @value: The value to be set
3204 * Sets the value of the field described by @field in the object instance @obj
3205 * to the value passed in @value. This method should only be used for instance
3206 * fields. For static fields, use mono_field_static_set_value.
3208 * The value must be on the native format of the field type.
3211 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3213 MONO_REQ_GC_UNSAFE_MODE;
3217 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3219 dest = (char*)obj + field->offset;
3220 mono_copy_value (field->type, dest, value, FALSE);
3224 * mono_field_static_set_value:
3225 * @field: MonoClassField describing the field to set
3226 * @value: The value to be set
3228 * Sets the value of the static field described by @field
3229 * to the value passed in @value.
3231 * The value must be on the native format of the field type.
3234 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3236 MONO_REQ_GC_UNSAFE_MODE;
3240 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3241 /* you cant set a constant! */
3242 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3244 if (field->offset == -1) {
3245 /* Special static */
3248 mono_domain_lock (vt->domain);
3249 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3250 mono_domain_unlock (vt->domain);
3251 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3253 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3255 mono_copy_value (field->type, dest, value, FALSE);
3259 * mono_vtable_get_static_field_data:
3261 * Internal use function: return a pointer to the memory holding the static fields
3262 * for a class or NULL if there are no static fields.
3263 * This is exported only for use by the debugger.
3266 mono_vtable_get_static_field_data (MonoVTable *vt)
3268 MONO_REQ_GC_NEUTRAL_MODE
3270 if (!vt->has_static_fields)
3272 return vt->vtable [vt->klass->vtable_size];
3276 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3278 MONO_REQ_GC_UNSAFE_MODE;
3282 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3283 if (field->offset == -1) {
3284 /* Special static */
3287 mono_domain_lock (vt->domain);
3288 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3289 mono_domain_unlock (vt->domain);
3290 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3292 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3295 src = (guint8*)obj + field->offset;
3302 * mono_field_get_value:
3303 * @obj: Object instance
3304 * @field: MonoClassField describing the field to fetch information from
3305 * @value: pointer to the location where the value will be stored
3307 * Use this routine to get the value of the field @field in the object
3310 * The pointer provided by value must be of the field type, for reference
3311 * types this is a MonoObject*, for value types its the actual pointer to
3316 * mono_field_get_value (obj, int_field, &i);
3319 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3321 MONO_REQ_GC_UNSAFE_MODE;
3327 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3329 src = (char*)obj + field->offset;
3330 mono_copy_value (field->type, value, src, TRUE);
3334 * mono_field_get_value_object:
3335 * @domain: domain where the object will be created (if boxing)
3336 * @field: MonoClassField describing the field to fetch information from
3337 * @obj: The object instance for the field.
3339 * Returns: a new MonoObject with the value from the given field. If the
3340 * field represents a value type, the value is boxed.
3344 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3346 MONO_REQ_GC_UNSAFE_MODE;
3351 MonoVTable *vtable = NULL;
3353 gboolean is_static = FALSE;
3354 gboolean is_ref = FALSE;
3355 gboolean is_literal = FALSE;
3356 gboolean is_ptr = FALSE;
3357 MonoType *type = mono_field_get_type_checked (field, &error);
3359 if (!mono_error_ok (&error))
3360 mono_error_raise_exception (&error); /* FIXME don't raise here */
3362 switch (type->type) {
3363 case MONO_TYPE_STRING:
3364 case MONO_TYPE_OBJECT:
3365 case MONO_TYPE_CLASS:
3366 case MONO_TYPE_ARRAY:
3367 case MONO_TYPE_SZARRAY:
3372 case MONO_TYPE_BOOLEAN:
3375 case MONO_TYPE_CHAR:
3384 case MONO_TYPE_VALUETYPE:
3385 is_ref = type->byref;
3387 case MONO_TYPE_GENERICINST:
3388 is_ref = !mono_type_generic_inst_is_valuetype (type);
3394 g_error ("type 0x%x not handled in "
3395 "mono_field_get_value_object", type->type);
3399 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3402 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3406 vtable = mono_class_vtable_full (domain, field->parent, &error);
3407 mono_error_raise_exception (&error); /* FIXME don't raise here */
3409 if (!vtable->initialized) {
3410 mono_runtime_class_init_full (vtable, &error);
3411 mono_error_raise_exception (&error); /* FIXME don't raise here */
3420 get_default_field_value (domain, field, &o);
3421 } else if (is_static) {
3422 mono_field_static_get_value (vtable, field, &o);
3424 mono_field_get_value (obj, field, &o);
3430 static MonoMethod *m;
3436 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3437 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3443 get_default_field_value (domain, field, v);
3444 } else if (is_static) {
3445 mono_field_static_get_value (vtable, field, v);
3447 mono_field_get_value (obj, field, v);
3450 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3451 args [0] = ptr ? *ptr : NULL;
3452 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3453 mono_error_raise_exception (&error); /* FIXME don't raise here */
3455 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3456 mono_error_raise_exception (&error); /* FIXME don't raise here */
3461 /* boxed value type */
3462 klass = mono_class_from_mono_type (type);
3464 if (mono_class_is_nullable (klass))
3465 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3467 o = mono_object_new_checked (domain, klass, &error);
3468 mono_error_raise_exception (&error); /* FIXME don't raise here */
3469 v = ((gchar *) o) + sizeof (MonoObject);
3472 get_default_field_value (domain, field, v);
3473 } else if (is_static) {
3474 mono_field_static_get_value (vtable, field, v);
3476 mono_field_get_value (obj, field, v);
3483 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3485 MONO_REQ_GC_UNSAFE_MODE;
3488 const char *p = blob;
3489 mono_metadata_decode_blob_size (p, &p);
3492 case MONO_TYPE_BOOLEAN:
3495 *(guint8 *) value = *p;
3497 case MONO_TYPE_CHAR:
3500 *(guint16*) value = read16 (p);
3504 *(guint32*) value = read32 (p);
3508 *(guint64*) value = read64 (p);
3511 readr4 (p, (float*) value);
3514 readr8 (p, (double*) value);
3516 case MONO_TYPE_STRING:
3517 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3519 case MONO_TYPE_CLASS:
3520 *(gpointer*) value = NULL;
3524 g_warning ("type 0x%02x should not be in constant table", type);
3530 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3532 MONO_REQ_GC_NEUTRAL_MODE;
3534 MonoTypeEnum def_type;
3537 data = mono_class_get_field_default_value (field, &def_type);
3538 mono_get_constant_value_from_blob (domain, def_type, data, value);
3542 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3544 MONO_REQ_GC_UNSAFE_MODE;
3548 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3550 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3551 get_default_field_value (vt->domain, field, value);
3555 if (field->offset == -1) {
3556 /* Special static */
3557 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3558 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3560 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3562 mono_copy_value (field->type, value, src, TRUE);
3566 * mono_field_static_get_value:
3567 * @vt: vtable to the object
3568 * @field: MonoClassField describing the field to fetch information from
3569 * @value: where the value is returned
3571 * Use this routine to get the value of the static field @field value.
3573 * The pointer provided by value must be of the field type, for reference
3574 * types this is a MonoObject*, for value types its the actual pointer to
3579 * mono_field_static_get_value (vt, int_field, &i);
3582 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3584 MONO_REQ_GC_NEUTRAL_MODE;
3586 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3590 * mono_property_set_value:
3591 * @prop: MonoProperty to set
3592 * @obj: instance object on which to act
3593 * @params: parameters to pass to the propery
3594 * @exc: optional exception
3596 * Invokes the property's set method with the given arguments on the
3597 * object instance obj (or NULL for static properties).
3599 * You can pass NULL as the exc argument if you don't want to
3600 * catch exceptions, otherwise, *exc will be set to the exception
3601 * thrown, if any. if an exception is thrown, you can't use the
3602 * MonoObject* result from the function.
3605 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3607 MONO_REQ_GC_UNSAFE_MODE;
3610 do_runtime_invoke (prop->set, obj, params, exc, &error);
3611 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3612 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3614 mono_error_raise_exception (&error); /* FIXME don't raise here */
3619 * mono_property_get_value:
3620 * @prop: MonoProperty to fetch
3621 * @obj: instance object on which to act
3622 * @params: parameters to pass to the propery
3623 * @exc: optional exception
3625 * Invokes the property's get method with the given arguments on the
3626 * object instance obj (or NULL for static properties).
3628 * You can pass NULL as the exc argument if you don't want to
3629 * catch exceptions, otherwise, *exc will be set to the exception
3630 * thrown, if any. if an exception is thrown, you can't use the
3631 * MonoObject* result from the function.
3633 * Returns: the value from invoking the get method on the property.
3636 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3638 MONO_REQ_GC_UNSAFE_MODE;
3641 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3642 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3643 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3645 mono_error_raise_exception (&error); /* FIXME don't raise here */
3652 * mono_nullable_init:
3653 * @buf: The nullable structure to initialize.
3654 * @value: the value to initialize from
3655 * @klass: the type for the object
3657 * Initialize the nullable structure pointed to by @buf from @value which
3658 * should be a boxed value type. The size of @buf should be able to hold
3659 * as much data as the @klass->instance_size (which is the number of bytes
3660 * that will be copies).
3662 * Since Nullables have variable structure, we can not define a C
3663 * structure for them.
3666 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3668 MONO_REQ_GC_UNSAFE_MODE;
3670 MonoClass *param_class = klass->cast_class;
3672 mono_class_setup_fields_locking (klass);
3673 g_assert (klass->fields_inited);
3675 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3676 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3678 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3680 if (param_class->has_references)
3681 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3683 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3685 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3690 * mono_nullable_box:
3691 * @buf: The buffer representing the data to be boxed
3692 * @klass: the type to box it as.
3694 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3698 mono_nullable_box (guint8 *buf, MonoClass *klass)
3700 MONO_REQ_GC_UNSAFE_MODE;
3704 MonoClass *param_class = klass->cast_class;
3706 mono_class_setup_fields_locking (klass);
3707 g_assert (klass->fields_inited);
3709 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3710 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3712 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3713 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3714 mono_error_raise_exception (&error); /* FIXME don't raise here */
3715 if (param_class->has_references)
3716 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3718 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3726 * mono_get_delegate_invoke:
3727 * @klass: The delegate class
3729 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3732 mono_get_delegate_invoke (MonoClass *klass)
3734 MONO_REQ_GC_NEUTRAL_MODE;
3738 /* This is called at runtime, so avoid the slower search in metadata */
3739 mono_class_setup_methods (klass);
3740 if (mono_class_has_failure (klass))
3742 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3747 * mono_get_delegate_begin_invoke:
3748 * @klass: The delegate class
3750 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3753 mono_get_delegate_begin_invoke (MonoClass *klass)
3755 MONO_REQ_GC_NEUTRAL_MODE;
3759 /* This is called at runtime, so avoid the slower search in metadata */
3760 mono_class_setup_methods (klass);
3761 if (mono_class_has_failure (klass))
3763 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3768 * mono_get_delegate_end_invoke:
3769 * @klass: The delegate class
3771 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3774 mono_get_delegate_end_invoke (MonoClass *klass)
3776 MONO_REQ_GC_NEUTRAL_MODE;
3780 /* This is called at runtime, so avoid the slower search in metadata */
3781 mono_class_setup_methods (klass);
3782 if (mono_class_has_failure (klass))
3784 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3789 * mono_runtime_delegate_invoke:
3790 * @delegate: pointer to a delegate object.
3791 * @params: parameters for the delegate.
3792 * @exc: Pointer to the exception result.
3794 * Invokes the delegate method @delegate with the parameters provided.
3796 * You can pass NULL as the exc argument if you don't want to
3797 * catch exceptions, otherwise, *exc will be set to the exception
3798 * thrown, if any. if an exception is thrown, you can't use the
3799 * MonoObject* result from the function.
3802 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3804 MONO_REQ_GC_UNSAFE_MODE;
3808 MonoClass *klass = delegate->vtable->klass;
3811 im = mono_get_delegate_invoke (klass);
3813 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3816 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3817 if (*exc == NULL && !mono_error_ok (&error))
3818 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3820 mono_error_cleanup (&error);
3822 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3823 mono_error_raise_exception (&error); /* FIXME don't raise here */
3829 static char **main_args = NULL;
3830 static int num_main_args = 0;
3833 * mono_runtime_get_main_args:
3835 * Returns: a MonoArray with the arguments passed to the main program
3838 mono_runtime_get_main_args (void)
3840 MONO_REQ_GC_UNSAFE_MODE;
3844 MonoDomain *domain = mono_domain_get ();
3846 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3848 for (i = 0; i < num_main_args; ++i)
3849 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3855 free_main_args (void)
3857 MONO_REQ_GC_NEUTRAL_MODE;
3861 for (i = 0; i < num_main_args; ++i)
3862 g_free (main_args [i]);
3869 * mono_runtime_set_main_args:
3870 * @argc: number of arguments from the command line
3871 * @argv: array of strings from the command line
3873 * Set the command line arguments from an embedding application that doesn't otherwise call
3874 * mono_runtime_run_main ().
3877 mono_runtime_set_main_args (int argc, char* argv[])
3879 MONO_REQ_GC_NEUTRAL_MODE;
3884 main_args = g_new0 (char*, argc);
3885 num_main_args = argc;
3887 for (i = 0; i < argc; ++i) {
3890 utf8_arg = mono_utf8_from_external (argv[i]);
3891 if (utf8_arg == NULL) {
3892 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3893 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3897 main_args [i] = utf8_arg;
3904 * mono_runtime_run_main:
3905 * @method: the method to start the application with (usually Main)
3906 * @argc: number of arguments from the command line
3907 * @argv: array of strings from the command line
3908 * @exc: excetption results
3910 * Execute a standard Main() method (argc/argv contains the
3911 * executable name). This method also sets the command line argument value
3912 * needed by System.Environment.
3917 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3920 MONO_REQ_GC_UNSAFE_MODE;
3923 MonoArray *args = NULL;
3924 MonoDomain *domain = mono_domain_get ();
3925 gchar *utf8_fullpath;
3926 MonoMethodSignature *sig;
3928 g_assert (method != NULL);
3930 mono_thread_set_main (mono_thread_current ());
3932 main_args = g_new0 (char*, argc);
3933 num_main_args = argc;
3935 if (!g_path_is_absolute (argv [0])) {
3936 gchar *basename = g_path_get_basename (argv [0]);
3937 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3941 utf8_fullpath = mono_utf8_from_external (fullpath);
3942 if(utf8_fullpath == NULL) {
3943 /* Printing the arg text will cause glib to
3944 * whinge about "Invalid UTF-8", but at least
3945 * its relevant, and shows the problem text
3948 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3949 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3956 utf8_fullpath = mono_utf8_from_external (argv[0]);
3957 if(utf8_fullpath == NULL) {
3958 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3959 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3964 main_args [0] = utf8_fullpath;
3966 for (i = 1; i < argc; ++i) {
3969 utf8_arg=mono_utf8_from_external (argv[i]);
3970 if(utf8_arg==NULL) {
3971 /* Ditto the comment about Invalid UTF-8 here */
3972 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3973 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3977 main_args [i] = utf8_arg;
3982 sig = mono_method_signature (method);
3984 g_print ("Unable to load Main method.\n");
3988 if (sig->param_count) {
3989 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3990 for (i = 0; i < argc; ++i) {
3991 /* The encodings should all work, given that
3992 * we've checked all these args for the
3995 gchar *str = mono_utf8_from_external (argv [i]);
3996 MonoString *arg = mono_string_new (domain, str);
3997 mono_array_setref (args, i, arg);
4001 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4004 mono_assembly_set_main (method->klass->image->assembly);
4006 return mono_runtime_exec_main (method, args, exc);
4010 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4012 static MonoMethod *serialize_method;
4018 if (!serialize_method) {
4019 MonoClass *klass = mono_class_get_remoting_services_class ();
4020 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4023 if (!serialize_method) {
4028 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4033 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4034 if (*exc == NULL && !mono_error_ok (&error))
4035 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4037 mono_error_cleanup (&error);
4046 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4048 MONO_REQ_GC_UNSAFE_MODE;
4050 static MonoMethod *deserialize_method;
4056 if (!deserialize_method) {
4057 MonoClass *klass = mono_class_get_remoting_services_class ();
4058 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4060 if (!deserialize_method) {
4068 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4069 if (*exc == NULL && !mono_error_ok (&error))
4070 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4072 mono_error_cleanup (&error);
4080 #ifndef DISABLE_REMOTING
4082 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4084 MONO_REQ_GC_UNSAFE_MODE;
4086 static MonoMethod *get_proxy_method;
4089 MonoDomain *domain = mono_domain_get ();
4090 MonoRealProxy *real_proxy;
4091 MonoReflectionType *reflection_type;
4092 MonoTransparentProxy *transparent_proxy;
4094 if (!get_proxy_method)
4095 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4097 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4099 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4100 mono_error_raise_exception (&error); /* FIXME don't raise here */
4101 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4102 mono_error_raise_exception (&error); /* FIXME don't raise here */
4104 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4105 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4109 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4110 if (*exc == NULL && !mono_error_ok (&error))
4111 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4113 mono_error_cleanup (&error);
4117 return (MonoObject*) transparent_proxy;
4119 #endif /* DISABLE_REMOTING */
4122 * mono_object_xdomain_representation
4124 * @target_domain: a domain
4125 * @exc: pointer to a MonoObject*
4127 * Creates a representation of obj in the domain target_domain. This
4128 * is either a copy of obj arrived through via serialization and
4129 * deserialization or a proxy, depending on whether the object is
4130 * serializable or marshal by ref. obj must not be in target_domain.
4132 * If the object cannot be represented in target_domain, NULL is
4133 * returned and *exc is set to an appropriate exception.
4136 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4138 MONO_REQ_GC_UNSAFE_MODE;
4140 MonoObject *deserialized = NULL;
4141 gboolean failure = FALSE;
4143 g_assert (exc != NULL);
4146 #ifndef DISABLE_REMOTING
4147 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4148 deserialized = make_transparent_proxy (obj, &failure, exc);
4153 MonoDomain *domain = mono_domain_get ();
4154 MonoObject *serialized;
4156 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4157 serialized = serialize_object (obj, &failure, exc);
4158 mono_domain_set_internal_with_options (target_domain, FALSE);
4160 deserialized = deserialize_object (serialized, &failure, exc);
4161 if (domain != target_domain)
4162 mono_domain_set_internal_with_options (domain, FALSE);
4165 return deserialized;
4168 /* Used in call_unhandled_exception_delegate */
4170 create_unhandled_exception_eventargs (MonoObject *exc)
4172 MONO_REQ_GC_UNSAFE_MODE;
4177 MonoMethod *method = NULL;
4178 MonoBoolean is_terminating = TRUE;
4181 klass = mono_class_get_unhandled_exception_event_args_class ();
4182 mono_class_init (klass);
4184 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4185 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4189 args [1] = &is_terminating;
4191 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4192 mono_error_raise_exception (&error); /* FIXME don't raise here */
4194 mono_runtime_invoke_checked (method, obj, args, &error);
4195 mono_error_raise_exception (&error); /* FIXME don't raise here */
4200 /* Used in mono_unhandled_exception */
4202 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4203 MONO_REQ_GC_UNSAFE_MODE;
4205 MonoObject *e = NULL;
4207 MonoDomain *current_domain = mono_domain_get ();
4209 if (domain != current_domain)
4210 mono_domain_set_internal_with_options (domain, FALSE);
4212 g_assert (domain == mono_object_domain (domain->domain));
4214 if (mono_object_domain (exc) != domain) {
4215 MonoObject *serialization_exc;
4217 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4219 if (serialization_exc) {
4221 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4224 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4225 "System.Runtime.Serialization", "SerializationException",
4226 "Could not serialize unhandled exception.");
4230 g_assert (mono_object_domain (exc) == domain);
4232 pa [0] = domain->domain;
4233 pa [1] = create_unhandled_exception_eventargs (exc);
4234 mono_runtime_delegate_invoke (delegate, pa, &e);
4236 if (domain != current_domain)
4237 mono_domain_set_internal_with_options (current_domain, FALSE);
4241 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4242 if (!mono_error_ok (&error)) {
4243 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4244 mono_error_cleanup (&error);
4246 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4252 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4255 * mono_runtime_unhandled_exception_policy_set:
4256 * @policy: the new policy
4258 * This is a VM internal routine.
4260 * Sets the runtime policy for handling unhandled exceptions.
4263 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4264 runtime_unhandled_exception_policy = policy;
4268 * mono_runtime_unhandled_exception_policy_get:
4270 * This is a VM internal routine.
4272 * Gets the runtime policy for handling unhandled exceptions.
4274 MonoRuntimeUnhandledExceptionPolicy
4275 mono_runtime_unhandled_exception_policy_get (void) {
4276 return runtime_unhandled_exception_policy;
4280 * mono_unhandled_exception:
4281 * @exc: exception thrown
4283 * This is a VM internal routine.
4285 * We call this function when we detect an unhandled exception
4286 * in the default domain.
4288 * It invokes the * UnhandledException event in AppDomain or prints
4289 * a warning to the console
4292 mono_unhandled_exception (MonoObject *exc)
4294 MONO_REQ_GC_UNSAFE_MODE;
4296 MonoClassField *field;
4297 MonoDomain *current_domain, *root_domain;
4298 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4300 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4303 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4306 current_domain = mono_domain_get ();
4307 root_domain = mono_get_root_domain ();
4309 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4310 if (current_domain != root_domain)
4311 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4313 /* set exitcode only if we will abort the process */
4314 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4315 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4316 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4318 mono_environment_exitcode_set (1);
4321 mono_print_unhandled_exception (exc);
4323 if (root_appdomain_delegate)
4324 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4325 if (current_appdomain_delegate)
4326 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4331 * mono_runtime_exec_managed_code:
4332 * @domain: Application domain
4333 * @main_func: function to invoke from the execution thread
4334 * @main_args: parameter to the main_func
4336 * Launch a new thread to execute a function
4338 * main_func is called back from the thread with main_args as the
4339 * parameter. The callback function is expected to start Main()
4340 * eventually. This function then waits for all managed threads to
4342 * It is not necesseray anymore to execute managed code in a subthread,
4343 * so this function should not be used anymore by default: just
4344 * execute the code and then call mono_thread_manage ().
4347 mono_runtime_exec_managed_code (MonoDomain *domain,
4348 MonoMainThreadFunc main_func,
4351 mono_thread_create (domain, main_func, main_args);
4353 mono_thread_manage ();
4357 * Execute a standard Main() method (args doesn't contain the
4361 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4363 MONO_REQ_GC_UNSAFE_MODE;
4369 MonoCustomAttrInfo* cinfo;
4370 gboolean has_stathread_attribute;
4371 MonoInternalThread* thread = mono_thread_internal_current ();
4377 domain = mono_object_domain (args);
4378 if (!domain->entry_assembly) {
4380 MonoAssembly *assembly;
4382 assembly = method->klass->image->assembly;
4383 domain->entry_assembly = assembly;
4384 /* Domains created from another domain already have application_base and configuration_file set */
4385 if (domain->setup->application_base == NULL) {
4386 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4389 if (domain->setup->configuration_file == NULL) {
4390 str = g_strconcat (assembly->image->name, ".config", NULL);
4391 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4393 mono_domain_set_options_from_config (domain);
4397 cinfo = mono_custom_attrs_from_method (method);
4399 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4401 mono_custom_attrs_free (cinfo);
4403 has_stathread_attribute = FALSE;
4405 if (has_stathread_attribute) {
4406 thread->apartment_state = ThreadApartmentState_STA;
4408 thread->apartment_state = ThreadApartmentState_MTA;
4410 mono_thread_init_apartment_state ();
4412 /* FIXME: check signature of method */
4413 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4416 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4417 if (*exc == NULL && !mono_error_ok (&error))
4418 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4420 mono_error_cleanup (&error);
4422 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4423 mono_error_raise_exception (&error); /* FIXME don't raise here */
4427 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4431 mono_environment_exitcode_set (rval);
4434 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4435 if (*exc == NULL && !mono_error_ok (&error))
4436 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4438 mono_error_cleanup (&error);
4440 mono_runtime_invoke_checked (method, NULL, pa, &error);
4441 mono_error_raise_exception (&error); /* FIXME don't raise here */
4447 /* If the return type of Main is void, only
4448 * set the exitcode if an exception was thrown
4449 * (we don't want to blow away an
4450 * explicitly-set exit code)
4453 mono_environment_exitcode_set (rval);
4461 * mono_runtime_invoke_array:
4462 * @method: method to invoke
4463 * @obJ: object instance
4464 * @params: arguments to the method
4465 * @exc: exception information.
4467 * Invokes the method represented by @method on the object @obj.
4469 * obj is the 'this' pointer, it should be NULL for static
4470 * methods, a MonoObject* for object instances and a pointer to
4471 * the value type for value types.
4473 * The params array contains the arguments to the method with the
4474 * same convention: MonoObject* pointers for object instances and
4475 * pointers to the value type otherwise. The _invoke_array
4476 * variant takes a C# object[] as the params argument (MonoArray
4477 * *params): in this case the value types are boxed inside the
4478 * respective reference representation.
4480 * From unmanaged code you'll usually use the
4481 * mono_runtime_invoke_checked() variant.
4483 * Note that this function doesn't handle virtual methods for
4484 * you, it will exec the exact method you pass: we still need to
4485 * expose a function to lookup the derived class implementation
4486 * of a virtual method (there are examples of this in the code,
4489 * You can pass NULL as the exc argument if you don't want to
4490 * catch exceptions, otherwise, *exc will be set to the exception
4491 * thrown, if any. if an exception is thrown, you can't use the
4492 * MonoObject* result from the function.
4494 * If the method returns a value type, it is boxed in an object
4498 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4501 MONO_REQ_GC_UNSAFE_MODE;
4504 MonoMethodSignature *sig = mono_method_signature (method);
4505 gpointer *pa = NULL;
4508 gboolean has_byref_nullables = FALSE;
4510 if (NULL != params) {
4511 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4512 for (i = 0; i < mono_array_length (params); i++) {
4513 MonoType *t = sig->params [i];
4519 case MONO_TYPE_BOOLEAN:
4522 case MONO_TYPE_CHAR:
4531 case MONO_TYPE_VALUETYPE:
4532 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4533 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4534 pa [i] = mono_array_get (params, MonoObject*, i);
4536 has_byref_nullables = TRUE;
4538 /* MS seems to create the objects if a null is passed in */
4539 if (!mono_array_get (params, MonoObject*, i)) {
4540 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4541 mono_error_raise_exception (&error); /* FIXME don't raise here */
4542 mono_array_setref (params, i, o);
4547 * We can't pass the unboxed vtype byref to the callee, since
4548 * that would mean the callee would be able to modify boxed
4549 * primitive types. So we (and MS) make a copy of the boxed
4550 * object, pass that to the callee, and replace the original
4551 * boxed object in the arg array with the copy.
4553 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4554 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4555 mono_array_setref (params, i, copy);
4558 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4561 case MONO_TYPE_STRING:
4562 case MONO_TYPE_OBJECT:
4563 case MONO_TYPE_CLASS:
4564 case MONO_TYPE_ARRAY:
4565 case MONO_TYPE_SZARRAY:
4567 pa [i] = mono_array_addr (params, MonoObject*, i);
4568 // FIXME: I need to check this code path
4570 pa [i] = mono_array_get (params, MonoObject*, i);
4572 case MONO_TYPE_GENERICINST:
4574 t = &t->data.generic_class->container_class->this_arg;
4576 t = &t->data.generic_class->container_class->byval_arg;
4578 case MONO_TYPE_PTR: {
4581 /* The argument should be an IntPtr */
4582 arg = mono_array_get (params, MonoObject*, i);
4586 g_assert (arg->vtable->klass == mono_defaults.int_class);
4587 pa [i] = ((MonoIntPtr*)arg)->m_value;
4592 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4597 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4600 if (mono_class_is_nullable (method->klass)) {
4601 /* Need to create a boxed vtype instead */
4607 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4611 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4612 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4613 #ifndef DISABLE_REMOTING
4614 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4615 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4618 if (method->klass->valuetype)
4619 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4622 } else if (method->klass->valuetype) {
4623 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4627 mono_runtime_try_invoke (method, o, pa, exc, &error);
4628 if (*exc == NULL && !mono_error_ok (&error))
4629 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4631 mono_error_cleanup (&error);
4633 mono_runtime_invoke_checked (method, o, pa, &error);
4634 mono_error_raise_exception (&error); /* FIXME don't raise here */
4637 return (MonoObject *)obj;
4639 if (mono_class_is_nullable (method->klass)) {
4640 MonoObject *nullable;
4642 /* Convert the unboxed vtype into a Nullable structure */
4643 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4644 mono_error_raise_exception (&error); /* FIXME don't raise here */
4646 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4647 obj = mono_object_unbox (nullable);
4650 /* obj must be already unboxed if needed */
4652 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4653 if (*exc == NULL && !mono_error_ok (&error))
4654 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4656 mono_error_cleanup (&error);
4658 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4659 mono_error_raise_exception (&error); /* FIXME don't raise here */
4662 if (sig->ret->type == MONO_TYPE_PTR) {
4663 MonoClass *pointer_class;
4664 static MonoMethod *box_method;
4666 MonoObject *box_exc;
4669 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4670 * convert it to a Pointer object.
4672 pointer_class = mono_class_get_pointer_class ();
4674 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4676 g_assert (res->vtable->klass == mono_defaults.int_class);
4677 box_args [0] = ((MonoIntPtr*)res)->m_value;
4678 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4679 mono_error_raise_exception (&error); /* FIXME don't raise here */
4681 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4682 g_assert (box_exc == NULL);
4683 mono_error_assert_ok (&error);
4686 if (has_byref_nullables) {
4688 * The runtime invoke wrapper already converted byref nullables back,
4689 * and stored them in pa, we just need to copy them back to the
4692 for (i = 0; i < mono_array_length (params); i++) {
4693 MonoType *t = sig->params [i];
4695 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4696 mono_array_setref (params, i, pa [i]);
4706 * @klass: the class of the object that we want to create
4708 * Returns: a newly created object whose definition is
4709 * looked up using @klass. This will not invoke any constructors,
4710 * so the consumer of this routine has to invoke any constructors on
4711 * its own to initialize the object.
4713 * It returns NULL on failure.
4716 mono_object_new (MonoDomain *domain, MonoClass *klass)
4718 MONO_REQ_GC_UNSAFE_MODE;
4722 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4724 mono_error_raise_exception (&error);
4729 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4731 MONO_REQ_GC_UNSAFE_MODE;
4735 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4737 mono_error_raise_exception (&error);
4742 * mono_object_new_checked:
4743 * @klass: the class of the object that we want to create
4744 * @error: set on error
4746 * Returns: a newly created object whose definition is
4747 * looked up using @klass. This will not invoke any constructors,
4748 * so the consumer of this routine has to invoke any constructors on
4749 * its own to initialize the object.
4751 * It returns NULL on failure and sets @error.
4754 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4756 MONO_REQ_GC_UNSAFE_MODE;
4760 vtable = mono_class_vtable (domain, klass);
4761 g_assert (vtable); /* FIXME don't swallow the error */
4763 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4768 * mono_object_new_pinned:
4770 * Same as mono_object_new, but the returned object will be pinned.
4771 * For SGEN, these objects will only be freed at appdomain unload.
4774 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4776 MONO_REQ_GC_UNSAFE_MODE;
4780 mono_error_init (error);
4782 vtable = mono_class_vtable (domain, klass);
4783 g_assert (vtable); /* FIXME don't swallow the error */
4785 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4787 if (G_UNLIKELY (!o))
4788 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4789 else if (G_UNLIKELY (vtable->klass->has_finalize))
4790 mono_object_register_finalizer (o, error);
4796 * mono_object_new_specific:
4797 * @vtable: the vtable of the object that we want to create
4799 * Returns: A newly created object with class and domain specified
4803 mono_object_new_specific (MonoVTable *vtable)
4806 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4807 mono_error_raise_exception (&error);
4813 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4815 MONO_REQ_GC_UNSAFE_MODE;
4819 mono_error_init (error);
4821 /* check for is_com_object for COM Interop */
4822 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4825 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4828 MonoClass *klass = mono_class_get_activation_services_class ();
4831 mono_class_init (klass);
4833 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4835 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4838 vtable->domain->create_proxy_for_type_method = im;
4841 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4842 if (!mono_error_ok (error))
4845 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4846 if (!mono_error_ok (error))
4853 return mono_object_new_alloc_specific_checked (vtable, error);
4857 ves_icall_object_new_specific (MonoVTable *vtable)
4860 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4861 mono_error_raise_exception (&error);
4867 * mono_object_new_alloc_specific:
4868 * @vtable: virtual table for the object.
4870 * This function allocates a new `MonoObject` with the type derived
4871 * from the @vtable information. If the class of this object has a
4872 * finalizer, then the object will be tracked for finalization.
4874 * This method might raise an exception on errors. Use the
4875 * `mono_object_new_fast_checked` method if you want to manually raise
4878 * Returns: the allocated object.
4881 mono_object_new_alloc_specific (MonoVTable *vtable)
4884 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4885 mono_error_raise_exception (&error);
4891 * mono_object_new_alloc_specific_checked:
4892 * @vtable: virtual table for the object.
4893 * @error: holds the error return value.
4895 * This function allocates a new `MonoObject` with the type derived
4896 * from the @vtable information. If the class of this object has a
4897 * finalizer, then the object will be tracked for finalization.
4899 * If there is not enough memory, the @error parameter will be set
4900 * and will contain a user-visible message with the amount of bytes
4901 * that were requested.
4903 * Returns: the allocated object, or NULL if there is not enough memory
4907 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4909 MONO_REQ_GC_UNSAFE_MODE;
4913 mono_error_init (error);
4915 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4917 if (G_UNLIKELY (!o))
4918 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4919 else if (G_UNLIKELY (vtable->klass->has_finalize))
4920 mono_object_register_finalizer (o, error);
4926 * mono_object_new_fast:
4927 * @vtable: virtual table for the object.
4929 * This function allocates a new `MonoObject` with the type derived
4930 * from the @vtable information. The returned object is not tracked
4931 * for finalization. If your object implements a finalizer, you should
4932 * use `mono_object_new_alloc_specific` instead.
4934 * This method might raise an exception on errors. Use the
4935 * `mono_object_new_fast_checked` method if you want to manually raise
4938 * Returns: the allocated object.
4941 mono_object_new_fast (MonoVTable *vtable)
4944 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4945 mono_error_raise_exception (&error);
4951 * mono_object_new_fast_checked:
4952 * @vtable: virtual table for the object.
4953 * @error: holds the error return value.
4955 * This function allocates a new `MonoObject` with the type derived
4956 * from the @vtable information. The returned object is not tracked
4957 * for finalization. If your object implements a finalizer, you should
4958 * use `mono_object_new_alloc_specific_checked` instead.
4960 * If there is not enough memory, the @error parameter will be set
4961 * and will contain a user-visible message with the amount of bytes
4962 * that were requested.
4964 * Returns: the allocated object, or NULL if there is not enough memory
4968 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4970 MONO_REQ_GC_UNSAFE_MODE;
4974 mono_error_init (error);
4976 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4978 if (G_UNLIKELY (!o))
4979 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4985 ves_icall_object_new_fast (MonoVTable *vtable)
4988 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4989 mono_error_raise_exception (&error);
4995 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
4997 MONO_REQ_GC_UNSAFE_MODE;
5001 mono_error_init (error);
5003 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5005 if (G_UNLIKELY (!o))
5006 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5007 else if (G_UNLIKELY (vtable->klass->has_finalize))
5008 mono_object_register_finalizer (o, error);
5014 * mono_class_get_allocation_ftn:
5016 * @for_box: the object will be used for boxing
5017 * @pass_size_in_words:
5019 * Return the allocation function appropriate for the given class.
5023 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5025 MONO_REQ_GC_NEUTRAL_MODE;
5027 *pass_size_in_words = FALSE;
5029 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5030 return ves_icall_object_new_specific;
5032 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5034 return ves_icall_object_new_fast;
5037 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5038 * of the overhead of parameter passing.
5041 *pass_size_in_words = TRUE;
5042 #ifdef GC_REDIRECT_TO_LOCAL
5043 return GC_local_gcj_fast_malloc;
5045 return GC_gcj_fast_malloc;
5050 return ves_icall_object_new_specific;
5054 * mono_object_new_from_token:
5055 * @image: Context where the type_token is hosted
5056 * @token: a token of the type that we want to create
5058 * Returns: A newly created object whose definition is
5059 * looked up using @token in the @image image
5062 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5064 MONO_REQ_GC_UNSAFE_MODE;
5070 klass = mono_class_get_checked (image, token, &error);
5071 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5073 result = mono_object_new_checked (domain, klass, &error);
5075 mono_error_raise_exception (&error); /* FIXME don't raise here */
5082 * mono_object_clone:
5083 * @obj: the object to clone
5085 * Returns: A newly created object who is a shallow copy of @obj
5088 mono_object_clone (MonoObject *obj)
5091 MonoObject *o = mono_object_clone_checked (obj, &error);
5092 mono_error_raise_exception (&error);
5098 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5100 MONO_REQ_GC_UNSAFE_MODE;
5105 mono_error_init (error);
5107 size = obj->vtable->klass->instance_size;
5109 if (obj->vtable->klass->rank)
5110 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5112 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5114 if (G_UNLIKELY (!o)) {
5115 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5119 /* If the object doesn't contain references this will do a simple memmove. */
5120 mono_gc_wbarrier_object_copy (o, obj);
5122 if (obj->vtable->klass->has_finalize)
5123 mono_object_register_finalizer (o, error);
5128 * mono_array_full_copy:
5129 * @src: source array to copy
5130 * @dest: destination array
5132 * Copies the content of one array to another with exactly the same type and size.
5135 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5137 MONO_REQ_GC_UNSAFE_MODE;
5140 MonoClass *klass = src->obj.vtable->klass;
5142 g_assert (klass == dest->obj.vtable->klass);
5144 size = mono_array_length (src);
5145 g_assert (size == mono_array_length (dest));
5146 size *= mono_array_element_size (klass);
5148 if (klass->element_class->valuetype) {
5149 if (klass->element_class->has_references)
5150 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5152 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5154 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5157 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5162 * mono_array_clone_in_domain:
5163 * @domain: the domain in which the array will be cloned into
5164 * @array: the array to clone
5166 * This routine returns a copy of the array that is hosted on the
5167 * specified MonoDomain.
5170 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5172 MONO_REQ_GC_UNSAFE_MODE;
5178 MonoClass *klass = array->obj.vtable->klass;
5180 if (array->bounds == NULL) {
5181 size = mono_array_length (array);
5182 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5183 mono_error_raise_exception (&error); /* FIXME don't raise here */
5185 size *= mono_array_element_size (klass);
5187 if (klass->element_class->valuetype) {
5188 if (klass->element_class->has_references)
5189 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5191 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5193 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5196 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5201 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5202 size = mono_array_element_size (klass);
5203 for (i = 0; i < klass->rank; ++i) {
5204 sizes [i] = array->bounds [i].length;
5205 size *= array->bounds [i].length;
5206 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5208 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5209 mono_error_raise_exception (&error); /* FIXME don't raise here */
5211 if (klass->element_class->valuetype) {
5212 if (klass->element_class->has_references)
5213 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5215 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5217 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5220 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5228 * @array: the array to clone
5230 * Returns: A newly created array who is a shallow copy of @array
5233 mono_array_clone (MonoArray *array)
5235 MONO_REQ_GC_UNSAFE_MODE;
5237 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5240 /* helper macros to check for overflow when calculating the size of arrays */
5241 #ifdef MONO_BIG_ARRAYS
5242 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5243 #define MYGUINT_MAX MYGUINT64_MAX
5244 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5245 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5246 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5247 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5248 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5250 #define MYGUINT32_MAX 4294967295U
5251 #define MYGUINT_MAX MYGUINT32_MAX
5252 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5253 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5254 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5255 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5256 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5260 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5262 MONO_REQ_GC_NEUTRAL_MODE;
5266 byte_len = mono_array_element_size (klass);
5267 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5270 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5272 byte_len += MONO_SIZEOF_MONO_ARRAY;
5280 * mono_array_new_full:
5281 * @domain: domain where the object is created
5282 * @array_class: array class
5283 * @lengths: lengths for each dimension in the array
5284 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5286 * This routine creates a new array objects with the given dimensions,
5287 * lower bounds and type.
5290 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5293 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5294 mono_error_raise_exception (&error);
5300 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5302 MONO_REQ_GC_UNSAFE_MODE;
5304 uintptr_t byte_len = 0, len, bounds_size;
5307 MonoArrayBounds *bounds;
5311 mono_error_init (error);
5313 if (!array_class->inited)
5314 mono_class_init (array_class);
5318 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5319 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5321 if (len > MONO_ARRAY_MAX_INDEX) {
5322 mono_error_set_generic_error (error, "System", "OverflowException", "");
5327 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5329 for (i = 0; i < array_class->rank; ++i) {
5330 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5331 mono_error_set_generic_error (error, "System", "OverflowException", "");
5334 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5335 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5342 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5343 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5349 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5350 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5353 byte_len = (byte_len + 3) & ~3;
5354 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5355 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5358 byte_len += bounds_size;
5361 * Following three lines almost taken from mono_object_new ():
5362 * they need to be kept in sync.
5364 vtable = mono_class_vtable_full (domain, array_class, error);
5365 return_val_if_nok (error, NULL);
5368 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5370 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5372 if (G_UNLIKELY (!o)) {
5373 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5377 array = (MonoArray*)o;
5379 bounds = array->bounds;
5382 for (i = 0; i < array_class->rank; ++i) {
5383 bounds [i].length = lengths [i];
5385 bounds [i].lower_bound = lower_bounds [i];
5394 * @domain: domain where the object is created
5395 * @eclass: element class
5396 * @n: number of array elements
5398 * This routine creates a new szarray with @n elements of type @eclass.
5401 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5403 MONO_REQ_GC_UNSAFE_MODE;
5409 ac = mono_array_class_get (eclass, 1);
5412 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5413 mono_error_raise_exception (&error); /* FIXME don't raise here */
5415 arr = mono_array_new_specific_checked (vtable, n, &error);
5416 mono_error_raise_exception (&error); /* FIXME don't raise here */
5422 * mono_array_new_specific:
5423 * @vtable: a vtable in the appropriate domain for an initialized class
5424 * @n: number of array elements
5426 * This routine is a fast alternative to mono_array_new() for code which
5427 * can be sure about the domain it operates in.
5430 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5433 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5434 mono_error_raise_exception (&error); /* FIXME don't raise here */
5440 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5442 MONO_REQ_GC_UNSAFE_MODE;
5447 mono_error_init (error);
5449 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5450 mono_error_set_generic_error (error, "System", "OverflowException", "");
5454 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5455 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5458 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5460 if (G_UNLIKELY (!o)) {
5461 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5465 return (MonoArray*)o;
5469 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5472 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5473 mono_error_raise_exception (&error);
5479 * mono_string_new_utf16:
5480 * @text: a pointer to an utf16 string
5481 * @len: the length of the string
5483 * Returns: A newly created string object which contains @text.
5486 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5488 MONO_REQ_GC_UNSAFE_MODE;
5491 MonoString *res = NULL;
5492 res = mono_string_new_utf16_checked (domain, text, len, &error);
5493 mono_error_raise_exception (&error);
5499 * mono_string_new_utf16_checked:
5500 * @text: a pointer to an utf16 string
5501 * @len: the length of the string
5502 * @error: written on error.
5504 * Returns: A newly created string object which contains @text.
5505 * On error, returns NULL and sets @error.
5508 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5510 MONO_REQ_GC_UNSAFE_MODE;
5514 mono_error_init (error);
5516 s = mono_string_new_size_checked (domain, len, error);
5518 memcpy (mono_string_chars (s), text, len * 2);
5524 * mono_string_new_utf32:
5525 * @text: a pointer to an utf32 string
5526 * @len: the length of the string
5528 * Returns: A newly created string object which contains @text.
5531 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5533 MONO_REQ_GC_UNSAFE_MODE;
5537 mono_unichar2 *utf16_output = NULL;
5538 gint32 utf16_len = 0;
5539 GError *gerror = NULL;
5540 glong items_written;
5542 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5545 g_error_free (gerror);
5547 while (utf16_output [utf16_len]) utf16_len++;
5549 s = mono_string_new_size_checked (domain, utf16_len, &error);
5550 mono_error_raise_exception (&error); /* FIXME don't raise here */
5552 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5554 g_free (utf16_output);
5560 * mono_string_new_size:
5561 * @text: a pointer to an utf16 string
5562 * @len: the length of the string
5564 * Returns: A newly created string object of @len
5567 mono_string_new_size (MonoDomain *domain, gint32 len)
5570 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5571 mono_error_raise_exception (&error);
5577 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5579 MONO_REQ_GC_UNSAFE_MODE;
5585 mono_error_init (error);
5587 /* check for overflow */
5588 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5589 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5593 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5594 g_assert (size > 0);
5596 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5599 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5601 if (G_UNLIKELY (!s)) {
5602 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5610 * mono_string_new_len:
5611 * @text: a pointer to an utf8 string
5612 * @length: number of bytes in @text to consider
5614 * Returns: A newly created string object which contains @text.
5617 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5619 MONO_REQ_GC_UNSAFE_MODE;
5622 GError *eg_error = NULL;
5623 MonoString *o = NULL;
5625 glong items_written;
5627 mono_error_init (&error);
5629 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5632 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5634 g_error_free (eg_error);
5638 mono_error_raise_exception (&error); /* FIXME don't raise here */
5644 * @text: a pointer to an utf8 string
5646 * Returns: A newly created string object which contains @text.
5648 * This function asserts if it cannot allocate a new string.
5650 * @deprecated Use mono_string_new_checked in new code.
5653 mono_string_new (MonoDomain *domain, const char *text)
5656 MonoString *res = NULL;
5657 res = mono_string_new_checked (domain, text, &error);
5658 mono_error_assert_ok (&error);
5663 * mono_string_new_checked:
5664 * @text: a pointer to an utf8 string
5665 * @merror: set on error
5667 * Returns: A newly created string object which contains @text.
5668 * On error returns NULL and sets @merror.
5671 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5673 MONO_REQ_GC_UNSAFE_MODE;
5675 GError *eg_error = NULL;
5676 MonoString *o = NULL;
5678 glong items_written;
5681 mono_error_init (error);
5685 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5688 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5690 g_error_free (eg_error);
5693 mono_error_raise_exception (error);
5695 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5700 MonoString *o = NULL;
5702 if (!g_utf8_validate (text, -1, &end)) {
5703 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5707 len = g_utf8_strlen (text, -1);
5708 o = mono_string_new_size_checked (domain, len, error);
5711 str = mono_string_chars (o);
5713 while (text < end) {
5714 *str++ = g_utf8_get_char (text);
5715 text = g_utf8_next_char (text);
5724 * mono_string_new_wrapper:
5725 * @text: pointer to utf8 characters.
5727 * Helper function to create a string object from @text in the current domain.
5730 mono_string_new_wrapper (const char *text)
5732 MONO_REQ_GC_UNSAFE_MODE;
5734 MonoDomain *domain = mono_domain_get ();
5737 return mono_string_new (domain, text);
5744 * @class: the class of the value
5745 * @value: a pointer to the unboxed data
5747 * Returns: A newly created object which contains @value.
5750 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5752 MONO_REQ_GC_UNSAFE_MODE;
5759 g_assert (klass->valuetype);
5760 if (mono_class_is_nullable (klass))
5761 return mono_nullable_box ((guint8 *)value, klass);
5763 vtable = mono_class_vtable (domain, klass);
5766 size = mono_class_instance_size (klass);
5767 res = mono_object_new_alloc_specific_checked (vtable, &error);
5768 mono_error_raise_exception (&error); /* FIXME don't raise here */
5770 size = size - sizeof (MonoObject);
5773 g_assert (size == mono_class_value_size (klass, NULL));
5774 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5776 #if NO_UNALIGNED_ACCESS
5777 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5781 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5784 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5787 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5790 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5793 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5797 if (klass->has_finalize) {
5798 mono_object_register_finalizer (res, &error);
5799 mono_error_raise_exception (&error); /* FIXME don't raise here */
5806 * @dest: destination pointer
5807 * @src: source pointer
5808 * @klass: a valuetype class
5810 * Copy a valuetype from @src to @dest. This function must be used
5811 * when @klass contains references fields.
5814 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5816 MONO_REQ_GC_UNSAFE_MODE;
5818 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5822 * mono_value_copy_array:
5823 * @dest: destination array
5824 * @dest_idx: index in the @dest array
5825 * @src: source pointer
5826 * @count: number of items
5828 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5829 * This function must be used when @klass contains references fields.
5830 * Overlap is handled.
5833 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5835 MONO_REQ_GC_UNSAFE_MODE;
5837 int size = mono_array_element_size (dest->obj.vtable->klass);
5838 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5839 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5840 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5844 * mono_object_get_domain:
5845 * @obj: object to query
5847 * Returns: the MonoDomain where the object is hosted
5850 mono_object_get_domain (MonoObject *obj)
5852 MONO_REQ_GC_UNSAFE_MODE;
5854 return mono_object_domain (obj);
5858 * mono_object_get_class:
5859 * @obj: object to query
5861 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5863 * Returns: the MonoClass of the object.
5866 mono_object_get_class (MonoObject *obj)
5868 MONO_REQ_GC_UNSAFE_MODE;
5870 return mono_object_class (obj);
5873 * mono_object_get_size:
5874 * @o: object to query
5876 * Returns: the size, in bytes, of @o
5879 mono_object_get_size (MonoObject* o)
5881 MONO_REQ_GC_UNSAFE_MODE;
5883 MonoClass* klass = mono_object_class (o);
5884 if (klass == mono_defaults.string_class) {
5885 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5886 } else if (o->vtable->rank) {
5887 MonoArray *array = (MonoArray*)o;
5888 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5889 if (array->bounds) {
5892 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5896 return mono_class_instance_size (klass);
5901 * mono_object_unbox:
5902 * @obj: object to unbox
5904 * Returns: a pointer to the start of the valuetype boxed in this
5907 * This method will assert if the object passed is not a valuetype.
5910 mono_object_unbox (MonoObject *obj)
5912 MONO_REQ_GC_UNSAFE_MODE;
5914 /* add assert for valuetypes? */
5915 g_assert (obj->vtable->klass->valuetype);
5916 return ((char*)obj) + sizeof (MonoObject);
5920 * mono_object_isinst:
5922 * @klass: a pointer to a class
5924 * Returns: @obj if @obj is derived from @klass
5927 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5929 MONO_REQ_GC_UNSAFE_MODE;
5932 mono_class_init (klass);
5934 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5935 return mono_object_isinst_mbyref (obj, klass);
5940 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5944 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5946 MONO_REQ_GC_UNSAFE_MODE;
5956 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5957 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5961 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5962 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5965 MonoClass *oklass = vt->klass;
5966 if (mono_class_is_transparent_proxy (oklass))
5967 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5969 mono_class_setup_supertypes (klass);
5970 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5973 #ifndef DISABLE_REMOTING
5974 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5976 MonoDomain *domain = mono_domain_get ();
5978 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5979 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5980 MonoMethod *im = NULL;
5983 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5985 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5986 im = mono_object_get_virtual_method (rp, im);
5989 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5990 mono_error_raise_exception (&error); /* FIXME don't raise here */
5993 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5994 mono_error_raise_exception (&error); /* FIXME don't raise here */
5996 if (*(MonoBoolean *) mono_object_unbox(res)) {
5997 /* Update the vtable of the remote type, so it can safely cast to this new type */
5998 mono_upgrade_remote_class (domain, obj, klass);
6002 #endif /* DISABLE_REMOTING */
6007 * mono_object_castclass_mbyref:
6009 * @klass: a pointer to a class
6011 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6014 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6016 MONO_REQ_GC_UNSAFE_MODE;
6018 if (!obj) return NULL;
6019 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6021 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6023 "InvalidCastException"));
6028 MonoDomain *orig_domain;
6034 str_lookup (MonoDomain *domain, gpointer user_data)
6036 MONO_REQ_GC_UNSAFE_MODE;
6038 LDStrInfo *info = (LDStrInfo *)user_data;
6039 if (info->res || domain == info->orig_domain)
6041 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6045 mono_string_get_pinned (MonoString *str, MonoError *error)
6047 MONO_REQ_GC_UNSAFE_MODE;
6049 mono_error_init (error);
6051 /* We only need to make a pinned version of a string if this is a moving GC */
6052 if (!mono_gc_is_moving ())
6056 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6057 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6059 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6060 news->length = mono_string_length (str);
6062 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6068 mono_string_is_interned_lookup (MonoString *str, int insert)
6070 MONO_REQ_GC_UNSAFE_MODE;
6073 MonoGHashTable *ldstr_table;
6074 MonoString *s, *res;
6077 domain = ((MonoObject *)str)->vtable->domain;
6078 ldstr_table = domain->ldstr_table;
6080 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6086 /* Allocate outside the lock */
6088 s = mono_string_get_pinned (str, &error);
6089 mono_error_raise_exception (&error); /* FIXME don't raise here */
6092 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6097 mono_g_hash_table_insert (ldstr_table, s, s);
6102 LDStrInfo ldstr_info;
6103 ldstr_info.orig_domain = domain;
6104 ldstr_info.ins = str;
6105 ldstr_info.res = NULL;
6107 mono_domain_foreach (str_lookup, &ldstr_info);
6108 if (ldstr_info.res) {
6110 * the string was already interned in some other domain:
6111 * intern it in the current one as well.
6113 mono_g_hash_table_insert (ldstr_table, str, str);
6123 * mono_string_is_interned:
6124 * @o: String to probe
6126 * Returns whether the string has been interned.
6129 mono_string_is_interned (MonoString *o)
6131 MONO_REQ_GC_UNSAFE_MODE;
6133 return mono_string_is_interned_lookup (o, FALSE);
6137 * mono_string_intern:
6138 * @o: String to intern
6140 * Interns the string passed.
6141 * Returns: The interned string.
6144 mono_string_intern (MonoString *str)
6146 MONO_REQ_GC_UNSAFE_MODE;
6148 return mono_string_is_interned_lookup (str, TRUE);
6153 * @domain: the domain where the string will be used.
6154 * @image: a metadata context
6155 * @idx: index into the user string table.
6157 * Implementation for the ldstr opcode.
6158 * Returns: a loaded string from the @image/@idx combination.
6161 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6163 MONO_REQ_GC_UNSAFE_MODE;
6165 if (image->dynamic) {
6166 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6169 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6170 return NULL; /*FIXME we should probably be raising an exception here*/
6171 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6176 * mono_ldstr_metadata_sig
6177 * @domain: the domain for the string
6178 * @sig: the signature of a metadata string
6180 * Returns: a MonoString for a string stored in the metadata
6183 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6185 MONO_REQ_GC_UNSAFE_MODE;
6188 const char *str = sig;
6189 MonoString *o, *interned;
6192 len2 = mono_metadata_decode_blob_size (str, &str);
6195 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6196 mono_error_raise_exception (&error); /* FIXME don't raise here */
6197 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6200 guint16 *p2 = (guint16*)mono_string_chars (o);
6201 for (i = 0; i < len2; ++i) {
6202 *p2 = GUINT16_FROM_LE (*p2);
6208 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6211 return interned; /* o will get garbage collected */
6213 o = mono_string_get_pinned (o, &error);
6214 mono_error_raise_exception (&error); /* FIXME don't raise here */
6217 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6219 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6229 * mono_string_to_utf8:
6230 * @s: a System.String
6232 * Returns the UTF8 representation for @s.
6233 * The resulting buffer needs to be freed with mono_free().
6235 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6238 mono_string_to_utf8 (MonoString *s)
6240 MONO_REQ_GC_UNSAFE_MODE;
6243 char *result = mono_string_to_utf8_checked (s, &error);
6245 if (!mono_error_ok (&error))
6246 mono_error_raise_exception (&error);
6251 * mono_string_to_utf8_checked:
6252 * @s: a System.String
6253 * @error: a MonoError.
6255 * Converts a MonoString to its UTF8 representation. May fail; check
6256 * @error to determine whether the conversion was successful.
6257 * The resulting buffer should be freed with mono_free().
6260 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6262 MONO_REQ_GC_UNSAFE_MODE;
6266 GError *gerror = NULL;
6268 mono_error_init (error);
6274 return g_strdup ("");
6276 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6278 mono_error_set_argument (error, "string", "%s", gerror->message);
6279 g_error_free (gerror);
6282 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6283 if (s->length > written) {
6284 /* allocate the total length and copy the part of the string that has been converted */
6285 char *as2 = (char *)g_malloc0 (s->length);
6286 memcpy (as2, as, written);
6295 * mono_string_to_utf8_ignore:
6298 * Converts a MonoString to its UTF8 representation. Will ignore
6299 * invalid surrogate pairs.
6300 * The resulting buffer should be freed with mono_free().
6304 mono_string_to_utf8_ignore (MonoString *s)
6306 MONO_REQ_GC_UNSAFE_MODE;
6315 return g_strdup ("");
6317 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6319 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6320 if (s->length > written) {
6321 /* allocate the total length and copy the part of the string that has been converted */
6322 char *as2 = (char *)g_malloc0 (s->length);
6323 memcpy (as2, as, written);
6332 * mono_string_to_utf8_image_ignore:
6333 * @s: a System.String
6335 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6338 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6340 MONO_REQ_GC_UNSAFE_MODE;
6342 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6346 * mono_string_to_utf8_mp_ignore:
6347 * @s: a System.String
6349 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6352 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6354 MONO_REQ_GC_UNSAFE_MODE;
6356 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6361 * mono_string_to_utf16:
6364 * Return an null-terminated array of the utf-16 chars
6365 * contained in @s. The result must be freed with g_free().
6366 * This is a temporary helper until our string implementation
6367 * is reworked to always include the null terminating char.
6370 mono_string_to_utf16 (MonoString *s)
6372 MONO_REQ_GC_UNSAFE_MODE;
6379 as = (char *)g_malloc ((s->length * 2) + 2);
6380 as [(s->length * 2)] = '\0';
6381 as [(s->length * 2) + 1] = '\0';
6384 return (gunichar2 *)(as);
6387 memcpy (as, mono_string_chars(s), s->length * 2);
6388 return (gunichar2 *)(as);
6392 * mono_string_to_utf32:
6395 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6396 * contained in @s. The result must be freed with g_free().
6399 mono_string_to_utf32 (MonoString *s)
6401 MONO_REQ_GC_UNSAFE_MODE;
6403 mono_unichar4 *utf32_output = NULL;
6404 GError *error = NULL;
6405 glong items_written;
6410 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6413 g_error_free (error);
6415 return utf32_output;
6419 * mono_string_from_utf16:
6420 * @data: the UTF16 string (LPWSTR) to convert
6422 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6424 * Returns: a MonoString.
6427 mono_string_from_utf16 (gunichar2 *data)
6429 MONO_REQ_GC_UNSAFE_MODE;
6432 MonoString *res = NULL;
6433 MonoDomain *domain = mono_domain_get ();
6439 while (data [len]) len++;
6441 res = mono_string_new_utf16_checked (domain, data, len, &error);
6442 mono_error_raise_exception (&error); /* FIXME don't raise here */
6447 * mono_string_from_utf32:
6448 * @data: the UTF32 string (LPWSTR) to convert
6450 * Converts a UTF32 (UCS-4)to a MonoString.
6452 * Returns: a MonoString.
6455 mono_string_from_utf32 (mono_unichar4 *data)
6457 MONO_REQ_GC_UNSAFE_MODE;
6459 MonoString* result = NULL;
6460 mono_unichar2 *utf16_output = NULL;
6461 GError *error = NULL;
6462 glong items_written;
6468 while (data [len]) len++;
6470 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6473 g_error_free (error);
6475 result = mono_string_from_utf16 (utf16_output);
6476 g_free (utf16_output);
6481 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6483 MONO_REQ_GC_UNSAFE_MODE;
6490 r = mono_string_to_utf8_ignore (s);
6492 r = mono_string_to_utf8_checked (s, error);
6493 if (!mono_error_ok (error))
6500 len = strlen (r) + 1;
6502 mp_s = (char *)mono_mempool_alloc (mp, len);
6504 mp_s = (char *)mono_image_alloc (image, len);
6506 memcpy (mp_s, r, len);
6514 * mono_string_to_utf8_image:
6515 * @s: a System.String
6517 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6520 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6522 MONO_REQ_GC_UNSAFE_MODE;
6524 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6528 * mono_string_to_utf8_mp:
6529 * @s: a System.String
6531 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6534 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6536 MONO_REQ_GC_UNSAFE_MODE;
6538 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6542 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6545 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6547 eh_callbacks = *cbs;
6550 MonoRuntimeExceptionHandlingCallbacks *
6551 mono_get_eh_callbacks (void)
6553 return &eh_callbacks;
6557 * mono_raise_exception:
6558 * @ex: exception object
6560 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6563 mono_raise_exception (MonoException *ex)
6565 MONO_REQ_GC_UNSAFE_MODE;
6568 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6569 * that will cause gcc to omit the function epilog, causing problems when
6570 * the JIT tries to walk the stack, since the return address on the stack
6571 * will point into the next function in the executable, not this one.
6573 eh_callbacks.mono_raise_exception (ex);
6577 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6579 MONO_REQ_GC_UNSAFE_MODE;
6581 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6585 * mono_wait_handle_new:
6586 * @domain: Domain where the object will be created
6587 * @handle: Handle for the wait handle
6589 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6592 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6594 MONO_REQ_GC_UNSAFE_MODE;
6597 MonoWaitHandle *res;
6598 gpointer params [1];
6599 static MonoMethod *handle_set;
6601 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6602 mono_error_raise_exception (&error); /* FIXME don't raise here */
6604 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6606 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6608 params [0] = &handle;
6610 mono_runtime_invoke_checked (handle_set, res, params, &error);
6611 mono_error_raise_exception (&error); /* FIXME don't raise here */
6617 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6619 MONO_REQ_GC_UNSAFE_MODE;
6621 static MonoClassField *f_safe_handle = NULL;
6624 if (!f_safe_handle) {
6625 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6626 g_assert (f_safe_handle);
6629 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6635 mono_runtime_capture_context (MonoDomain *domain)
6637 MONO_REQ_GC_UNSAFE_MODE;
6639 RuntimeInvokeFunction runtime_invoke;
6641 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6642 MonoMethod *method = mono_get_context_capture_method ();
6643 MonoMethod *wrapper;
6646 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6647 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6648 domain->capture_context_method = mono_compile_method (method);
6651 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6653 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6656 * mono_async_result_new:
6657 * @domain:domain where the object will be created.
6658 * @handle: wait handle.
6659 * @state: state to pass to AsyncResult
6660 * @data: C closure data.
6662 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6663 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6667 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6669 MONO_REQ_GC_UNSAFE_MODE;
6672 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6673 mono_error_raise_exception (&error); /* FIXME don't raise here */
6674 MonoObject *context = mono_runtime_capture_context (domain);
6675 /* we must capture the execution context from the original thread */
6677 MONO_OBJECT_SETREF (res, execution_context, context);
6678 /* note: result may be null if the flow is suppressed */
6681 res->data = (void **)data;
6682 MONO_OBJECT_SETREF (res, object_data, object_data);
6683 MONO_OBJECT_SETREF (res, async_state, state);
6685 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6687 res->sync_completed = FALSE;
6688 res->completed = FALSE;
6694 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6696 MONO_REQ_GC_UNSAFE_MODE;
6703 g_assert (ares->async_delegate);
6705 ac = (MonoAsyncCall*) ares->object_data;
6707 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6709 gpointer wait_event = NULL;
6711 ac->msg->exc = NULL;
6712 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6713 MONO_OBJECT_SETREF (ac, res, res);
6715 mono_monitor_enter ((MonoObject*) ares);
6716 ares->completed = 1;
6718 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6719 mono_monitor_exit ((MonoObject*) ares);
6721 if (wait_event != NULL)
6722 SetEvent (wait_event);
6724 if (ac->cb_method) {
6725 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6726 mono_error_raise_exception (&error);
6734 mono_message_init (MonoDomain *domain,
6735 MonoMethodMessage *this_obj,
6736 MonoReflectionMethod *method,
6737 MonoArray *out_args)
6739 MONO_REQ_GC_UNSAFE_MODE;
6741 static MonoClass *object_array_klass;
6742 static MonoClass *byte_array_klass;
6743 static MonoClass *string_array_klass;
6745 MonoMethodSignature *sig = mono_method_signature (method->method);
6752 if (!object_array_klass) {
6755 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6757 byte_array_klass = klass;
6759 klass = mono_array_class_get (mono_defaults.string_class, 1);
6761 string_array_klass = klass;
6763 klass = mono_array_class_get (mono_defaults.object_class, 1);
6766 mono_atomic_store_release (&object_array_klass, klass);
6769 MONO_OBJECT_SETREF (this_obj, method, method);
6771 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6772 mono_error_raise_exception (&error); /* FIXME don't raise here */
6774 MONO_OBJECT_SETREF (this_obj, args, arr);
6776 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6777 mono_error_raise_exception (&error); /* FIXME don't raise here */
6779 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6781 this_obj->async_result = NULL;
6782 this_obj->call_type = CallType_Sync;
6784 names = g_new (char *, sig->param_count);
6785 mono_method_get_param_names (method->method, (const char **) names);
6787 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6788 mono_error_raise_exception (&error); /* FIXME don't raise here */
6790 MONO_OBJECT_SETREF (this_obj, names, arr);
6792 for (i = 0; i < sig->param_count; i++) {
6793 name = mono_string_new (domain, names [i]);
6794 mono_array_setref (this_obj->names, i, name);
6798 for (i = 0, j = 0; i < sig->param_count; i++) {
6799 if (sig->params [i]->byref) {
6801 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6802 mono_array_setref (this_obj->args, i, arg);
6806 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6810 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6813 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6817 #ifndef DISABLE_REMOTING
6819 * mono_remoting_invoke:
6820 * @real_proxy: pointer to a RealProxy object
6821 * @msg: The MonoMethodMessage to execute
6822 * @exc: used to store exceptions
6823 * @out_args: used to store output arguments
6825 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6826 * IMessage interface and it is not trivial to extract results from there. So
6827 * we call an helper method PrivateInvoke instead of calling
6828 * RealProxy::Invoke() directly.
6830 * Returns: the result object.
6833 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6834 MonoObject **exc, MonoArray **out_args)
6836 MONO_REQ_GC_UNSAFE_MODE;
6840 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6843 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6846 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6848 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6849 real_proxy->vtable->domain->private_invoke_method = im;
6852 pa [0] = real_proxy;
6858 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6860 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6862 mono_error_raise_exception (&error); /* FIXME don't raise here */
6869 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6870 MonoObject **exc, MonoArray **out_args)
6872 MONO_REQ_GC_UNSAFE_MODE;
6874 static MonoClass *object_array_klass;
6878 MonoMethodSignature *sig;
6881 int i, j, outarg_count = 0;
6883 #ifndef DISABLE_REMOTING
6884 if (target && mono_object_is_transparent_proxy (target)) {
6885 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6886 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6887 target = tp->rp->unwrapped_server;
6889 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6894 domain = mono_domain_get ();
6895 method = msg->method->method;
6896 sig = mono_method_signature (method);
6898 for (i = 0; i < sig->param_count; i++) {
6899 if (sig->params [i]->byref)
6903 if (!object_array_klass) {
6906 klass = mono_array_class_get (mono_defaults.object_class, 1);
6909 mono_memory_barrier ();
6910 object_array_klass = klass;
6913 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6914 mono_error_raise_exception (&error); /* FIXME don't raise here */
6916 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6919 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6921 for (i = 0, j = 0; i < sig->param_count; i++) {
6922 if (sig->params [i]->byref) {
6924 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6925 mono_array_setref (*out_args, j, arg);
6934 * mono_object_to_string:
6936 * @exc: Any exception thrown by ToString (). May be NULL.
6938 * Returns: the result of calling ToString () on an object.
6941 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6943 MONO_REQ_GC_UNSAFE_MODE;
6945 static MonoMethod *to_string = NULL;
6954 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6956 method = mono_object_get_virtual_method (obj, to_string);
6958 // Unbox value type if needed
6959 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6960 target = mono_object_unbox (obj);
6964 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6965 if (*exc == NULL && !mono_error_ok (&error))
6966 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6968 mono_error_cleanup (&error);
6970 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6971 mono_error_raise_exception (&error); /* FIXME don't raise here */
6978 * mono_print_unhandled_exception:
6979 * @exc: The exception
6981 * Prints the unhandled exception.
6984 mono_print_unhandled_exception (MonoObject *exc)
6986 MONO_REQ_GC_UNSAFE_MODE;
6989 char *message = (char*)"";
6990 gboolean free_message = FALSE;
6993 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6994 message = g_strdup ("OutOfMemoryException");
6995 free_message = TRUE;
6996 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6997 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6998 free_message = TRUE;
7001 if (((MonoException*)exc)->native_trace_ips) {
7002 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7003 free_message = TRUE;
7005 MonoObject *other_exc = NULL;
7006 str = mono_object_to_string (exc, &other_exc);
7008 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7009 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7011 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7012 original_backtrace, nested_backtrace);
7014 g_free (original_backtrace);
7015 g_free (nested_backtrace);
7016 free_message = TRUE;
7018 message = mono_string_to_utf8_checked (str, &error);
7019 if (!mono_error_ok (&error)) {
7020 mono_error_cleanup (&error);
7021 message = (char *) "";
7023 free_message = TRUE;
7030 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7031 * exc->vtable->klass->name, message);
7033 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7040 * mono_delegate_ctor:
7041 * @this: pointer to an uninitialized delegate object
7042 * @target: target object
7043 * @addr: pointer to native code
7046 * Initialize a delegate and sets a specific method, not the one
7047 * associated with addr. This is useful when sharing generic code.
7048 * In that case addr will most probably not be associated with the
7049 * correct instantiation of the method.
7052 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7054 MONO_REQ_GC_UNSAFE_MODE;
7056 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7058 g_assert (this_obj);
7061 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7064 delegate->method = method;
7066 mono_stats.delegate_creations++;
7068 #ifndef DISABLE_REMOTING
7069 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7071 method = mono_marshal_get_remoting_invoke (method);
7072 delegate->method_ptr = mono_compile_method (method);
7073 MONO_OBJECT_SETREF (delegate, target, target);
7077 delegate->method_ptr = addr;
7078 MONO_OBJECT_SETREF (delegate, target, target);
7081 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7082 if (callbacks.init_delegate)
7083 callbacks.init_delegate (delegate);
7087 * mono_delegate_ctor:
7088 * @this: pointer to an uninitialized delegate object
7089 * @target: target object
7090 * @addr: pointer to native code
7092 * This is used to initialize a delegate.
7095 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7097 MONO_REQ_GC_UNSAFE_MODE;
7099 MonoDomain *domain = mono_domain_get ();
7101 MonoMethod *method = NULL;
7105 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7107 if (!ji && domain != mono_get_root_domain ())
7108 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7110 method = mono_jit_info_get_method (ji);
7111 g_assert (!method->klass->generic_container);
7114 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7118 * mono_method_call_message_new:
7119 * @method: method to encapsulate
7120 * @params: parameters to the method
7121 * @invoke: optional, delegate invoke.
7122 * @cb: async callback delegate.
7123 * @state: state passed to the async callback.
7125 * Translates arguments pointers into a MonoMethodMessage.
7128 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7129 MonoDelegate **cb, MonoObject **state)
7131 MONO_REQ_GC_UNSAFE_MODE;
7135 MonoDomain *domain = mono_domain_get ();
7136 MonoMethodSignature *sig = mono_method_signature (method);
7137 MonoMethodMessage *msg;
7140 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7141 mono_error_raise_exception (&error); /* FIXME don't raise here */
7144 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7145 mono_error_raise_exception (&error); /* FIXME don't raise here */
7146 mono_message_init (domain, msg, rm, NULL);
7147 count = sig->param_count - 2;
7149 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7150 mono_error_raise_exception (&error); /* FIXME don't raise here */
7151 mono_message_init (domain, msg, rm, NULL);
7152 count = sig->param_count;
7155 for (i = 0; i < count; i++) {
7160 if (sig->params [i]->byref)
7161 vpos = *((gpointer *)params [i]);
7165 klass = mono_class_from_mono_type (sig->params [i]);
7167 if (klass->valuetype)
7168 arg = mono_value_box (domain, klass, vpos);
7170 arg = *((MonoObject **)vpos);
7172 mono_array_setref (msg->args, i, arg);
7175 if (cb != NULL && state != NULL) {
7176 *cb = *((MonoDelegate **)params [i]);
7178 *state = *((MonoObject **)params [i]);
7185 * mono_method_return_message_restore:
7187 * Restore results from message based processing back to arguments pointers
7190 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7192 MONO_REQ_GC_UNSAFE_MODE;
7194 MonoMethodSignature *sig = mono_method_signature (method);
7195 int i, j, type, size, out_len;
7197 if (out_args == NULL)
7199 out_len = mono_array_length (out_args);
7203 for (i = 0, j = 0; i < sig->param_count; i++) {
7204 MonoType *pt = sig->params [i];
7209 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7211 arg = (char *)mono_array_get (out_args, gpointer, j);
7214 g_assert (type != MONO_TYPE_VOID);
7216 if (MONO_TYPE_IS_REFERENCE (pt)) {
7217 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7220 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7221 size = mono_class_value_size (klass, NULL);
7222 if (klass->has_references)
7223 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7225 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7227 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7228 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7237 #ifndef DISABLE_REMOTING
7240 * mono_load_remote_field:
7241 * @this: pointer to an object
7242 * @klass: klass of the object containing @field
7243 * @field: the field to load
7244 * @res: a storage to store the result
7246 * This method is called by the runtime on attempts to load fields of
7247 * transparent proxy objects. @this points to such TP, @klass is the class of
7248 * the object containing @field. @res is a storage location which can be
7249 * used to store the result.
7251 * Returns: an address pointing to the value of field.
7254 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7256 MONO_REQ_GC_UNSAFE_MODE;
7260 static MonoMethod *getter = NULL;
7261 MonoDomain *domain = mono_domain_get ();
7262 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7263 MonoClass *field_class;
7264 MonoMethodMessage *msg;
7265 MonoArray *out_args;
7269 g_assert (mono_object_is_transparent_proxy (this_obj));
7270 g_assert (res != NULL);
7272 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7273 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7278 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7280 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7283 field_class = mono_class_from_mono_type (field->type);
7285 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7286 mono_error_raise_exception (&error); /* FIXME don't raise here */
7287 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7288 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7289 mono_error_raise_exception (&error); /* FIXME don't raise here */
7290 mono_message_init (domain, msg, rm, out_args);
7292 full_name = mono_type_get_full_name (klass);
7293 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7294 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7297 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7299 if (exc) mono_raise_exception ((MonoException *)exc);
7301 if (mono_array_length (out_args) == 0)
7304 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7306 if (field_class->valuetype) {
7307 return ((char *)*res) + sizeof (MonoObject);
7313 * mono_load_remote_field_new:
7318 * Missing documentation.
7321 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7323 MONO_REQ_GC_UNSAFE_MODE;
7327 static MonoMethod *getter = NULL;
7328 MonoDomain *domain = mono_domain_get ();
7329 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7330 MonoClass *field_class;
7331 MonoMethodMessage *msg;
7332 MonoArray *out_args;
7333 MonoObject *exc, *res;
7336 g_assert (mono_object_is_transparent_proxy (this_obj));
7338 field_class = mono_class_from_mono_type (field->type);
7340 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7342 if (field_class->valuetype) {
7343 res = mono_object_new_checked (domain, field_class, &error);
7344 mono_error_raise_exception (&error); /* FIXME don't raise here */
7345 val = ((gchar *) res) + sizeof (MonoObject);
7349 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7354 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7356 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7359 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7360 mono_error_raise_exception (&error); /* FIXME don't raise here */
7361 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7363 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7364 mono_error_raise_exception (&error); /* FIXME don't raise here */
7365 mono_message_init (domain, msg, rm, out_args);
7367 full_name = mono_type_get_full_name (klass);
7368 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7369 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7372 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7374 if (exc) mono_raise_exception ((MonoException *)exc);
7376 if (mono_array_length (out_args) == 0)
7379 res = mono_array_get (out_args, MonoObject *, 0);
7385 * mono_store_remote_field:
7386 * @this_obj: pointer to an object
7387 * @klass: klass of the object containing @field
7388 * @field: the field to load
7389 * @val: the value/object to store
7391 * This method is called by the runtime on attempts to store fields of
7392 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7393 * the object containing @field. @val is the new value to store in @field.
7396 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7398 MONO_REQ_GC_UNSAFE_MODE;
7402 static MonoMethod *setter = NULL;
7403 MonoDomain *domain = mono_domain_get ();
7404 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7405 MonoClass *field_class;
7406 MonoMethodMessage *msg;
7407 MonoArray *out_args;
7412 g_assert (mono_object_is_transparent_proxy (this_obj));
7414 field_class = mono_class_from_mono_type (field->type);
7416 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7417 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7418 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7423 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7425 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7428 if (field_class->valuetype)
7429 arg = mono_value_box (domain, field_class, val);
7431 arg = *((MonoObject **)val);
7434 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7435 mono_error_raise_exception (&error); /* FIXME don't raise here */
7436 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7437 mono_error_raise_exception (&error); /* FIXME don't raise here */
7438 mono_message_init (domain, msg, rm, NULL);
7440 full_name = mono_type_get_full_name (klass);
7441 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7442 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7443 mono_array_setref (msg->args, 2, arg);
7446 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7448 if (exc) mono_raise_exception ((MonoException *)exc);
7452 * mono_store_remote_field_new:
7458 * Missing documentation
7461 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7463 MONO_REQ_GC_UNSAFE_MODE;
7467 static MonoMethod *setter = NULL;
7468 MonoDomain *domain = mono_domain_get ();
7469 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7470 MonoClass *field_class;
7471 MonoMethodMessage *msg;
7472 MonoArray *out_args;
7476 g_assert (mono_object_is_transparent_proxy (this_obj));
7478 field_class = mono_class_from_mono_type (field->type);
7480 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7481 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7482 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7487 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7489 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7492 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7493 mono_error_raise_exception (&error); /* FIXME don't raise here */
7494 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7495 mono_error_raise_exception (&error); /* FIXME don't raise here */
7496 mono_message_init (domain, msg, rm, NULL);
7498 full_name = mono_type_get_full_name (klass);
7499 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7500 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7501 mono_array_setref (msg->args, 2, arg);
7504 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7506 if (exc) mono_raise_exception ((MonoException *)exc);
7511 * mono_create_ftnptr:
7513 * Given a function address, create a function descriptor for it.
7514 * This is only needed on some platforms.
7517 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7519 return callbacks.create_ftnptr (domain, addr);
7523 * mono_get_addr_from_ftnptr:
7525 * Given a pointer to a function descriptor, return the function address.
7526 * This is only needed on some platforms.
7529 mono_get_addr_from_ftnptr (gpointer descr)
7531 return callbacks.get_addr_from_ftnptr (descr);
7535 * mono_string_chars:
7538 * Returns a pointer to the UCS16 characters stored in the MonoString
7541 mono_string_chars (MonoString *s)
7543 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7549 * mono_string_length:
7552 * Returns the lenght in characters of the string
7555 mono_string_length (MonoString *s)
7557 MONO_REQ_GC_UNSAFE_MODE;
7563 * mono_array_length:
7564 * @array: a MonoArray*
7566 * Returns the total number of elements in the array. This works for
7567 * both vectors and multidimensional arrays.
7570 mono_array_length (MonoArray *array)
7572 MONO_REQ_GC_UNSAFE_MODE;
7574 return array->max_length;
7578 * mono_array_addr_with_size:
7579 * @array: a MonoArray*
7580 * @size: size of the array elements
7581 * @idx: index into the array
7583 * Use this function to obtain the address for the @idx item on the
7584 * @array containing elements of size @size.
7586 * This method performs no bounds checking or type checking.
7588 * Returns the address of the @idx element in the array.
7591 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7593 MONO_REQ_GC_UNSAFE_MODE;
7595 return ((char*)(array)->vector) + size * idx;
7600 mono_glist_to_array (GList *list, MonoClass *eclass)
7602 MonoDomain *domain = mono_domain_get ();
7609 len = g_list_length (list);
7610 res = mono_array_new (domain, eclass, len);
7612 for (i = 0; list; list = list->next, i++)
7613 mono_array_set (res, gpointer, i, list->data);
7620 * The following section is purely to declare prototypes and
7621 * document the API, as these C files are processed by our
7627 * @array: array to alter
7628 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7629 * @index: index into the array
7630 * @value: value to set
7632 * Value Type version: This sets the @index's element of the @array
7633 * with elements of size sizeof(type) to the provided @value.
7635 * This macro does not attempt to perform type checking or bounds checking.
7637 * Use this to set value types in a `MonoArray`.
7639 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7644 * mono_array_setref:
7645 * @array: array to alter
7646 * @index: index into the array
7647 * @value: value to set
7649 * Reference Type version: This sets the @index's element of the
7650 * @array with elements of size sizeof(type) to the provided @value.
7652 * This macro does not attempt to perform type checking or bounds checking.
7654 * Use this to reference types in a `MonoArray`.
7656 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7662 * @array: array on which to operate on
7663 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7664 * @index: index into the array
7666 * Use this macro to retrieve the @index element of an @array and
7667 * extract the value assuming that the elements of the array match
7668 * the provided type value.
7670 * This method can be used with both arrays holding value types and
7671 * reference types. For reference types, the @type parameter should
7672 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7674 * This macro does not attempt to perform type checking or bounds checking.
7676 * Returns: The element at the @index position in the @array.
7678 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)