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 (!is_ok (error)) {
2165 mono_domain_unlock (domain);
2166 mono_loader_unlock ();
2173 if (imt_table_bytes) {
2174 /* Now that the vtable is full, we can actually fill up the IMT */
2175 for (i = 0; i < MONO_IMT_SIZE; ++i)
2176 interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2180 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2181 * re-acquire them and check if another thread has created the vtable in the meantime.
2183 /* Special case System.MonoType to avoid infinite recursion */
2184 if (klass != mono_defaults.monotype_class) {
2185 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2186 if (!is_ok (error)) {
2187 mono_domain_unlock (domain);
2188 mono_loader_unlock ();
2192 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2193 /* This is unregistered in
2194 unregister_vtable_reflection_type() in
2196 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2199 mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2201 /* class_vtable_array keeps an array of created vtables
2203 g_ptr_array_add (domain->class_vtable_array, vt);
2204 /* klass->runtime_info is protected by the loader lock, both when
2205 * it it enlarged and when it is stored info.
2209 * Store the vtable in klass->runtime_info.
2210 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2212 mono_memory_barrier ();
2214 old_info = klass->runtime_info;
2215 if (old_info && old_info->max_domain >= domain->domain_id) {
2216 /* someone already created a large enough runtime info */
2217 old_info->domain_vtables [domain->domain_id] = vt;
2219 int new_size = domain->domain_id;
2221 new_size = MAX (new_size, old_info->max_domain);
2223 /* make the new size a power of two */
2225 while (new_size > i)
2228 /* this is a bounded memory retention issue: may want to
2229 * handle it differently when we'll have a rcu-like system.
2231 runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2232 runtime_info->max_domain = new_size - 1;
2233 /* copy the stuff from the older info */
2235 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2237 runtime_info->domain_vtables [domain->domain_id] = vt;
2239 mono_memory_barrier ();
2240 klass->runtime_info = runtime_info;
2243 if (klass == mono_defaults.monotype_class) {
2244 vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2245 if (!is_ok (error)) {
2246 mono_domain_unlock (domain);
2247 mono_loader_unlock ();
2251 if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.monotype_class)
2252 /* This is unregistered in
2253 unregister_vtable_reflection_type() in
2255 MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2258 mono_domain_unlock (domain);
2259 mono_loader_unlock ();
2261 /* make sure the parent is initialized */
2262 /*FIXME shouldn't this fail the current type?*/
2264 mono_class_vtable_full (domain, klass->parent, error);
2269 #ifndef DISABLE_REMOTING
2271 * mono_class_proxy_vtable:
2272 * @domain: the application domain
2273 * @remove_class: the remote class
2275 * Creates a vtable for transparent proxies. It is basically
2276 * a copy of the real vtable of the class wrapped in @remote_class,
2277 * but all function pointers invoke the remoting functions, and
2278 * vtable->klass points to the transparent proxy class, and not to @class.
2281 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
2283 MONO_REQ_GC_UNSAFE_MODE;
2286 MonoVTable *vt, *pvt;
2287 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
2289 GSList *extra_interfaces = NULL;
2290 MonoClass *klass = remote_class->proxy_class;
2291 gpointer *interface_offsets;
2294 size_t imt_table_bytes;
2296 #ifdef COMPRESSED_INTERFACE_BITMAP
2300 vt = mono_class_vtable (domain, klass);
2301 g_assert (vt); /*FIXME property handle failure*/
2302 max_interface_id = vt->max_interface_id;
2304 /* Calculate vtable space for extra interfaces */
2305 for (j = 0; j < remote_class->interface_count; j++) {
2306 MonoClass* iclass = remote_class->interfaces[j];
2310 /*FIXME test for interfaces with variant generic arguments*/
2311 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2312 continue; /* interface implemented by the class */
2313 if (g_slist_find (extra_interfaces, iclass))
2316 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2318 method_count = mono_class_num_methods (iclass);
2320 ifaces = mono_class_get_implemented_interfaces (iclass, &error);
2321 g_assert (mono_error_ok (&error)); /*FIXME do proper error handling*/
2323 for (i = 0; i < ifaces->len; ++i) {
2324 MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2325 /*FIXME test for interfaces with variant generic arguments*/
2326 if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2327 continue; /* interface implemented by the class */
2328 if (g_slist_find (extra_interfaces, ic))
2330 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2331 method_count += mono_class_num_methods (ic);
2333 g_ptr_array_free (ifaces, TRUE);
2336 extra_interface_vtsize += method_count * sizeof (gpointer);
2337 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2340 imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2341 mono_stats.imt_number_of_tables++;
2342 mono_stats.imt_tables_size += imt_table_bytes;
2344 vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2346 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
2348 interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2349 pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2350 g_assert (!((gsize)pvt & 7));
2352 memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2354 pvt->klass = mono_defaults.transparent_proxy_class;
2355 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2356 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2358 /* initialize vtable */
2359 mono_class_setup_vtable (klass);
2360 for (i = 0; i < klass->vtable_size; ++i) {
2363 if ((cm = klass->vtable [i]))
2364 pvt->vtable [i] = arch_create_remoting_trampoline (domain, cm, target_type);
2366 pvt->vtable [i] = NULL;
2369 if (klass->flags & TYPE_ATTRIBUTE_ABSTRACT) {
2370 /* create trampolines for abstract methods */
2371 for (k = klass; k; k = k->parent) {
2373 gpointer iter = NULL;
2374 while ((m = mono_class_get_methods (k, &iter)))
2375 if (!pvt->vtable [m->slot])
2376 pvt->vtable [m->slot] = arch_create_remoting_trampoline (domain, m, target_type);
2380 pvt->max_interface_id = max_interface_id;
2381 bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2382 #ifdef COMPRESSED_INTERFACE_BITMAP
2383 bitmap = (uint8_t *)g_malloc0 (bsize);
2385 bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2388 for (i = 0; i < klass->interface_offsets_count; ++i) {
2389 int interface_id = klass->interfaces_packed [i]->interface_id;
2390 bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2393 if (extra_interfaces) {
2394 int slot = klass->vtable_size;
2400 /* Create trampolines for the methods of the interfaces */
2401 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2402 interf = (MonoClass *)list_item->data;
2404 bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2408 while ((cm = mono_class_get_methods (interf, &iter)))
2409 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (domain, cm, target_type);
2411 slot += mono_class_num_methods (interf);
2415 /* Now that the vtable is full, we can actually fill up the IMT */
2416 build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2417 if (extra_interfaces) {
2418 g_slist_free (extra_interfaces);
2421 #ifdef COMPRESSED_INTERFACE_BITMAP
2422 bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2423 pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2424 mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2427 pvt->interface_bitmap = bitmap;
2432 #endif /* DISABLE_REMOTING */
2435 * mono_class_field_is_special_static:
2437 * Returns whether @field is a thread/context static field.
2440 mono_class_field_is_special_static (MonoClassField *field)
2442 MONO_REQ_GC_NEUTRAL_MODE
2444 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2446 if (mono_field_is_deleted (field))
2448 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2449 if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2456 * mono_class_field_get_special_static_type:
2457 * @field: The MonoClassField describing the field.
2459 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
2460 * SPECIAL_STATIC_NONE otherwise.
2463 mono_class_field_get_special_static_type (MonoClassField *field)
2465 MONO_REQ_GC_NEUTRAL_MODE
2467 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2468 return SPECIAL_STATIC_NONE;
2469 if (mono_field_is_deleted (field))
2470 return SPECIAL_STATIC_NONE;
2471 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2472 return field_is_special_static (field->parent, field);
2473 return SPECIAL_STATIC_NONE;
2477 * mono_class_has_special_static_fields:
2479 * Returns whenever @klass has any thread/context static fields.
2482 mono_class_has_special_static_fields (MonoClass *klass)
2484 MONO_REQ_GC_NEUTRAL_MODE
2486 MonoClassField *field;
2490 while ((field = mono_class_get_fields (klass, &iter))) {
2491 g_assert (field->parent == klass);
2492 if (mono_class_field_is_special_static (field))
2499 #ifndef DISABLE_REMOTING
2501 * create_remote_class_key:
2502 * Creates an array of pointers that can be used as a hash key for a remote class.
2503 * The first element of the array is the number of pointers.
2506 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2508 MONO_REQ_GC_NEUTRAL_MODE;
2513 if (remote_class == NULL) {
2514 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2515 key = (void **)g_malloc (sizeof(gpointer) * 3);
2516 key [0] = GINT_TO_POINTER (2);
2517 key [1] = mono_defaults.marshalbyrefobject_class;
2518 key [2] = extra_class;
2520 key = (void **)g_malloc (sizeof(gpointer) * 2);
2521 key [0] = GINT_TO_POINTER (1);
2522 key [1] = extra_class;
2525 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2526 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2527 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2528 key [1] = remote_class->proxy_class;
2530 // Keep the list of interfaces sorted
2531 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2532 if (extra_class && remote_class->interfaces [i] > extra_class) {
2533 key [j++] = extra_class;
2536 key [j] = remote_class->interfaces [i];
2539 key [j] = extra_class;
2541 // Replace the old class. The interface list is the same
2542 key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2543 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2544 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2545 for (i = 0; i < remote_class->interface_count; i++)
2546 key [2 + i] = remote_class->interfaces [i];
2554 * copy_remote_class_key:
2556 * Make a copy of KEY in the domain and return the copy.
2559 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2561 MONO_REQ_GC_NEUTRAL_MODE
2563 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2564 gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2566 memcpy (mp_key, key, key_size);
2572 * mono_remote_class:
2573 * @domain: the application domain
2574 * @class_name: name of the remote class
2576 * Creates and initializes a MonoRemoteClass object for a remote type.
2578 * Can raise an exception on failure.
2581 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
2583 MONO_REQ_GC_UNSAFE_MODE;
2586 MonoRemoteClass *rc;
2587 gpointer* key, *mp_key;
2590 key = create_remote_class_key (NULL, proxy_class);
2592 mono_domain_lock (domain);
2593 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2597 mono_domain_unlock (domain);
2601 name = mono_string_to_utf8_mp (domain->mp, class_name, &error);
2602 if (!mono_error_ok (&error)) {
2604 mono_domain_unlock (domain);
2605 mono_error_raise_exception (&error);
2608 mp_key = copy_remote_class_key (domain, key);
2612 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2613 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2614 rc->interface_count = 1;
2615 rc->interfaces [0] = proxy_class;
2616 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2618 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2619 rc->interface_count = 0;
2620 rc->proxy_class = proxy_class;
2623 rc->default_vtable = NULL;
2624 rc->xdomain_vtable = NULL;
2625 rc->proxy_class_name = name;
2626 #ifndef DISABLE_PERFCOUNTERS
2627 mono_perfcounters->loader_bytes += mono_string_length (class_name) + 1;
2630 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2632 mono_domain_unlock (domain);
2637 * clone_remote_class:
2638 * Creates a copy of the remote_class, adding the provided class or interface
2640 static MonoRemoteClass*
2641 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2643 MONO_REQ_GC_NEUTRAL_MODE;
2645 MonoRemoteClass *rc;
2646 gpointer* key, *mp_key;
2648 key = create_remote_class_key (remote_class, extra_class);
2649 rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2655 mp_key = copy_remote_class_key (domain, key);
2659 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2661 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2662 rc->proxy_class = remote_class->proxy_class;
2663 rc->interface_count = remote_class->interface_count + 1;
2665 // Keep the list of interfaces sorted, since the hash key of
2666 // the remote class depends on this
2667 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2668 if (remote_class->interfaces [i] > extra_class && i == j)
2669 rc->interfaces [j++] = extra_class;
2670 rc->interfaces [j] = remote_class->interfaces [i];
2673 rc->interfaces [j] = extra_class;
2675 // Replace the old class. The interface array is the same
2676 rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2677 rc->proxy_class = extra_class;
2678 rc->interface_count = remote_class->interface_count;
2679 if (rc->interface_count > 0)
2680 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2683 rc->default_vtable = NULL;
2684 rc->xdomain_vtable = NULL;
2685 rc->proxy_class_name = remote_class->proxy_class_name;
2687 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2693 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
2695 MONO_REQ_GC_UNSAFE_MODE;
2697 mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2698 mono_domain_lock (domain);
2699 if (rp->target_domain_id != -1) {
2700 if (remote_class->xdomain_vtable == NULL)
2701 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
2702 mono_domain_unlock (domain);
2703 mono_loader_unlock ();
2704 return remote_class->xdomain_vtable;
2706 if (remote_class->default_vtable == NULL) {
2709 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
2710 klass = mono_class_from_mono_type (type);
2712 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)))
2713 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2716 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2719 mono_domain_unlock (domain);
2720 mono_loader_unlock ();
2721 return remote_class->default_vtable;
2725 * mono_upgrade_remote_class:
2726 * @domain: the application domain
2727 * @tproxy: the proxy whose remote class has to be upgraded.
2728 * @klass: class to which the remote class can be casted.
2730 * Updates the vtable of the remote class by adding the necessary method slots
2731 * and interface offsets so it can be safely casted to klass. klass can be a
2732 * class or an interface.
2735 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2737 MONO_REQ_GC_UNSAFE_MODE;
2739 MonoTransparentProxy *tproxy;
2740 MonoRemoteClass *remote_class;
2741 gboolean redo_vtable;
2743 mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2744 mono_domain_lock (domain);
2746 tproxy = (MonoTransparentProxy*) proxy_object;
2747 remote_class = tproxy->remote_class;
2749 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2752 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2753 if (remote_class->interfaces [i] == klass)
2754 redo_vtable = FALSE;
2757 redo_vtable = (remote_class->proxy_class != klass);
2761 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2762 proxy_object->vtable = (MonoVTable *)mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2765 mono_domain_unlock (domain);
2766 mono_loader_unlock ();
2768 #endif /* DISABLE_REMOTING */
2772 * mono_object_get_virtual_method:
2773 * @obj: object to operate on.
2776 * Retrieves the MonoMethod that would be called on obj if obj is passed as
2777 * the instance of a callvirt of method.
2780 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2782 MONO_REQ_GC_UNSAFE_MODE;
2785 MonoMethod **vtable;
2786 gboolean is_proxy = FALSE;
2787 MonoMethod *res = NULL;
2789 klass = mono_object_class (obj);
2790 #ifndef DISABLE_REMOTING
2791 if (klass == mono_defaults.transparent_proxy_class) {
2792 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2797 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2800 mono_class_setup_vtable (klass);
2801 vtable = klass->vtable;
2803 if (method->slot == -1) {
2804 /* method->slot might not be set for instances of generic methods */
2805 if (method->is_inflated) {
2806 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2807 method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2810 g_assert_not_reached ();
2814 /* check method->slot is a valid index: perform isinstance? */
2815 if (method->slot != -1) {
2816 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2818 gboolean variance_used = FALSE;
2819 int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2820 g_assert (iface_offset > 0);
2821 res = vtable [iface_offset + method->slot];
2824 res = vtable [method->slot];
2828 #ifndef DISABLE_REMOTING
2830 /* It may be an interface, abstract class method or generic method */
2831 if (!res || mono_method_signature (res)->generic_param_count)
2834 /* generic methods demand invoke_with_check */
2835 if (mono_method_signature (res)->generic_param_count)
2836 res = mono_marshal_get_remoting_invoke_with_check (res);
2839 if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2840 res = mono_cominterop_get_invoke (res);
2843 res = mono_marshal_get_remoting_invoke (res);
2848 if (method->is_inflated) {
2850 /* Have to inflate the result */
2851 res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, &error);
2852 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2862 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2864 MONO_REQ_GC_UNSAFE_MODE;
2866 MonoObject *result = NULL;
2868 g_assert (callbacks.runtime_invoke);
2870 mono_error_init (error);
2872 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2873 mono_profiler_method_start_invoke (method);
2875 MONO_PREPARE_RESET_BLOCKING;
2877 result = callbacks.runtime_invoke (method, obj, params, exc, error);
2879 MONO_FINISH_RESET_BLOCKING;
2881 if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS)
2882 mono_profiler_method_end_invoke (method);
2884 if (!mono_error_ok (error))
2891 * mono_runtime_invoke:
2892 * @method: method to invoke
2893 * @obJ: object instance
2894 * @params: arguments to the method
2895 * @exc: exception information.
2897 * Invokes the method represented by @method on the object @obj.
2899 * obj is the 'this' pointer, it should be NULL for static
2900 * methods, a MonoObject* for object instances and a pointer to
2901 * the value type for value types.
2903 * The params array contains the arguments to the method with the
2904 * same convention: MonoObject* pointers for object instances and
2905 * pointers to the value type otherwise.
2907 * From unmanaged code you'll usually use the
2908 * mono_runtime_invoke() variant.
2910 * Note that this function doesn't handle virtual methods for
2911 * you, it will exec the exact method you pass: we still need to
2912 * expose a function to lookup the derived class implementation
2913 * of a virtual method (there are examples of this in the code,
2916 * You can pass NULL as the exc argument if you don't want to
2917 * catch exceptions, otherwise, *exc will be set to the exception
2918 * thrown, if any. if an exception is thrown, you can't use the
2919 * MonoObject* result from the function.
2921 * If the method returns a value type, it is boxed in an object
2925 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2930 res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2931 if (*exc == NULL && !mono_error_ok(&error)) {
2932 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
2934 mono_error_cleanup (&error);
2936 res = mono_runtime_invoke_checked (method, obj, params, &error);
2937 mono_error_raise_exception (&error);
2943 * mono_runtime_try_invoke:
2944 * @method: method to invoke
2945 * @obJ: object instance
2946 * @params: arguments to the method
2947 * @exc: exception information.
2948 * @error: set on error
2950 * Invokes the method represented by @method on the object @obj.
2952 * obj is the 'this' pointer, it should be NULL for static
2953 * methods, a MonoObject* for object instances and a pointer to
2954 * the value type for value types.
2956 * The params array contains the arguments to the method with the
2957 * same convention: MonoObject* pointers for object instances and
2958 * pointers to the value type otherwise.
2960 * From unmanaged code you'll usually use the
2961 * mono_runtime_invoke() variant.
2963 * Note that this function doesn't handle virtual methods for
2964 * you, it will exec the exact method you pass: we still need to
2965 * expose a function to lookup the derived class implementation
2966 * of a virtual method (there are examples of this in the code,
2969 * For this function, you must not pass NULL as the exc argument if
2970 * you don't want to catch exceptions, use
2971 * mono_runtime_invoke_checked(). If an exception is thrown, you
2972 * can't use the MonoObject* result from the function.
2974 * If this method cannot be invoked, @error will be set and @exc and
2975 * the return value must not be used.
2977 * If the method returns a value type, it is boxed in an object
2981 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2983 MONO_REQ_GC_UNSAFE_MODE;
2985 g_assert (exc != NULL);
2987 if (mono_runtime_get_no_exec ())
2988 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2990 return do_runtime_invoke (method, obj, params, exc, error);
2994 * mono_runtime_invoke_checked:
2995 * @method: method to invoke
2996 * @obJ: object instance
2997 * @params: arguments to the method
2998 * @error: set on error
3000 * Invokes the method represented by @method on the object @obj.
3002 * obj is the 'this' pointer, it should be NULL for static
3003 * methods, a MonoObject* for object instances and a pointer to
3004 * the value type for value types.
3006 * The params array contains the arguments to the method with the
3007 * same convention: MonoObject* pointers for object instances and
3008 * pointers to the value type otherwise.
3010 * From unmanaged code you'll usually use the
3011 * mono_runtime_invoke() variant.
3013 * Note that this function doesn't handle virtual methods for
3014 * you, it will exec the exact method you pass: we still need to
3015 * expose a function to lookup the derived class implementation
3016 * of a virtual method (there are examples of this in the code,
3019 * If an exception is thrown, you can't use the MonoObject* result
3020 * from the function.
3022 * If this method cannot be invoked, @error will be set. If the
3023 * method throws an exception (and we're in coop mode) the exception
3024 * will be set in @error.
3026 * If the method returns a value type, it is boxed in an object
3030 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3032 MONO_REQ_GC_UNSAFE_MODE;
3034 if (mono_runtime_get_no_exec ())
3035 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3037 return do_runtime_invoke (method, obj, params, NULL, error);
3041 * mono_method_get_unmanaged_thunk:
3042 * @method: method to generate a thunk for.
3044 * Returns an unmanaged->managed thunk that can be used to call
3045 * a managed method directly from C.
3047 * The thunk's C signature closely matches the managed signature:
3049 * C#: public bool Equals (object obj);
3050 * C: typedef MonoBoolean (*Equals)(MonoObject*,
3051 * MonoObject*, MonoException**);
3053 * The 1st ("this") parameter must not be used with static methods:
3055 * C#: public static bool ReferenceEquals (object a, object b);
3056 * C: typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
3059 * The last argument must be a non-null pointer of a MonoException* pointer.
3060 * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
3061 * exception has been thrown in managed code. Otherwise it will point
3062 * to the MonoException* caught by the thunk. In this case, the result of
3063 * the thunk is undefined:
3065 * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3066 * MonoException *ex = NULL;
3067 * Equals func = mono_method_get_unmanaged_thunk (method);
3068 * MonoBoolean res = func (thisObj, objToCompare, &ex);
3070 * // handle exception
3073 * The calling convention of the thunk matches the platform's default
3074 * convention. This means that under Windows, C declarations must
3075 * contain the __stdcall attribute:
3077 * C: typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
3078 * MonoObject*, MonoException**);
3082 * Value type arguments and return values are treated as they were objects:
3084 * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
3085 * C: typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
3087 * Arguments must be properly boxed upon trunk's invocation, while return
3088 * values must be unboxed.
3091 mono_method_get_unmanaged_thunk (MonoMethod *method)
3093 MONO_REQ_GC_NEUTRAL_MODE;
3094 MONO_REQ_API_ENTRYPOINT;
3098 MONO_PREPARE_RESET_BLOCKING;
3099 method = mono_marshal_get_thunk_invoke_wrapper (method);
3100 res = mono_compile_method (method);
3101 MONO_FINISH_RESET_BLOCKING;
3107 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3109 MONO_REQ_GC_UNSAFE_MODE;
3113 /* object fields cannot be byref, so we don't need a
3115 gpointer *p = (gpointer*)dest;
3122 case MONO_TYPE_BOOLEAN:
3124 case MONO_TYPE_U1: {
3125 guint8 *p = (guint8*)dest;
3126 *p = value ? *(guint8*)value : 0;
3131 case MONO_TYPE_CHAR: {
3132 guint16 *p = (guint16*)dest;
3133 *p = value ? *(guint16*)value : 0;
3136 #if SIZEOF_VOID_P == 4
3141 case MONO_TYPE_U4: {
3142 gint32 *p = (gint32*)dest;
3143 *p = value ? *(gint32*)value : 0;
3146 #if SIZEOF_VOID_P == 8
3151 case MONO_TYPE_U8: {
3152 gint64 *p = (gint64*)dest;
3153 *p = value ? *(gint64*)value : 0;
3156 case MONO_TYPE_R4: {
3157 float *p = (float*)dest;
3158 *p = value ? *(float*)value : 0;
3161 case MONO_TYPE_R8: {
3162 double *p = (double*)dest;
3163 *p = value ? *(double*)value : 0;
3166 case MONO_TYPE_STRING:
3167 case MONO_TYPE_SZARRAY:
3168 case MONO_TYPE_CLASS:
3169 case MONO_TYPE_OBJECT:
3170 case MONO_TYPE_ARRAY:
3171 mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3173 case MONO_TYPE_FNPTR:
3174 case MONO_TYPE_PTR: {
3175 gpointer *p = (gpointer*)dest;
3176 *p = deref_pointer? *(gpointer*)value: value;
3179 case MONO_TYPE_VALUETYPE:
3180 /* note that 't' and 'type->type' can be different */
3181 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3182 t = mono_class_enum_basetype (type->data.klass)->type;
3185 MonoClass *klass = mono_class_from_mono_type (type);
3186 int size = mono_class_value_size (klass, NULL);
3188 mono_gc_bzero_atomic (dest, size);
3190 mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3193 case MONO_TYPE_GENERICINST:
3194 t = type->data.generic_class->container_class->byval_arg.type;
3197 g_error ("got type %x", type->type);
3202 * mono_field_set_value:
3203 * @obj: Instance object
3204 * @field: MonoClassField describing the field to set
3205 * @value: The value to be set
3207 * Sets the value of the field described by @field in the object instance @obj
3208 * to the value passed in @value. This method should only be used for instance
3209 * fields. For static fields, use mono_field_static_set_value.
3211 * The value must be on the native format of the field type.
3214 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3216 MONO_REQ_GC_UNSAFE_MODE;
3220 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3222 dest = (char*)obj + field->offset;
3223 mono_copy_value (field->type, dest, value, FALSE);
3227 * mono_field_static_set_value:
3228 * @field: MonoClassField describing the field to set
3229 * @value: The value to be set
3231 * Sets the value of the static field described by @field
3232 * to the value passed in @value.
3234 * The value must be on the native format of the field type.
3237 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3239 MONO_REQ_GC_UNSAFE_MODE;
3243 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3244 /* you cant set a constant! */
3245 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3247 if (field->offset == -1) {
3248 /* Special static */
3251 mono_domain_lock (vt->domain);
3252 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3253 mono_domain_unlock (vt->domain);
3254 dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3256 dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3258 mono_copy_value (field->type, dest, value, FALSE);
3262 * mono_vtable_get_static_field_data:
3264 * Internal use function: return a pointer to the memory holding the static fields
3265 * for a class or NULL if there are no static fields.
3266 * This is exported only for use by the debugger.
3269 mono_vtable_get_static_field_data (MonoVTable *vt)
3271 MONO_REQ_GC_NEUTRAL_MODE
3273 if (!vt->has_static_fields)
3275 return vt->vtable [vt->klass->vtable_size];
3279 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3281 MONO_REQ_GC_UNSAFE_MODE;
3285 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3286 if (field->offset == -1) {
3287 /* Special static */
3290 mono_domain_lock (vt->domain);
3291 addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3292 mono_domain_unlock (vt->domain);
3293 src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3295 src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3298 src = (guint8*)obj + field->offset;
3305 * mono_field_get_value:
3306 * @obj: Object instance
3307 * @field: MonoClassField describing the field to fetch information from
3308 * @value: pointer to the location where the value will be stored
3310 * Use this routine to get the value of the field @field in the object
3313 * The pointer provided by value must be of the field type, for reference
3314 * types this is a MonoObject*, for value types its the actual pointer to
3319 * mono_field_get_value (obj, int_field, &i);
3322 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3324 MONO_REQ_GC_UNSAFE_MODE;
3330 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3332 src = (char*)obj + field->offset;
3333 mono_copy_value (field->type, value, src, TRUE);
3337 * mono_field_get_value_object:
3338 * @domain: domain where the object will be created (if boxing)
3339 * @field: MonoClassField describing the field to fetch information from
3340 * @obj: The object instance for the field.
3342 * Returns: a new MonoObject with the value from the given field. If the
3343 * field represents a value type, the value is boxed.
3347 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3349 MONO_REQ_GC_UNSAFE_MODE;
3354 MonoVTable *vtable = NULL;
3356 gboolean is_static = FALSE;
3357 gboolean is_ref = FALSE;
3358 gboolean is_literal = FALSE;
3359 gboolean is_ptr = FALSE;
3360 MonoType *type = mono_field_get_type_checked (field, &error);
3362 if (!mono_error_ok (&error))
3363 mono_error_raise_exception (&error); /* FIXME don't raise here */
3365 switch (type->type) {
3366 case MONO_TYPE_STRING:
3367 case MONO_TYPE_OBJECT:
3368 case MONO_TYPE_CLASS:
3369 case MONO_TYPE_ARRAY:
3370 case MONO_TYPE_SZARRAY:
3375 case MONO_TYPE_BOOLEAN:
3378 case MONO_TYPE_CHAR:
3387 case MONO_TYPE_VALUETYPE:
3388 is_ref = type->byref;
3390 case MONO_TYPE_GENERICINST:
3391 is_ref = !mono_type_generic_inst_is_valuetype (type);
3397 g_error ("type 0x%x not handled in "
3398 "mono_field_get_value_object", type->type);
3402 if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3405 if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3409 vtable = mono_class_vtable_full (domain, field->parent, &error);
3410 mono_error_raise_exception (&error); /* FIXME don't raise here */
3412 if (!vtable->initialized) {
3413 mono_runtime_class_init_full (vtable, &error);
3414 mono_error_raise_exception (&error); /* FIXME don't raise here */
3423 get_default_field_value (domain, field, &o);
3424 } else if (is_static) {
3425 mono_field_static_get_value (vtable, field, &o);
3427 mono_field_get_value (obj, field, &o);
3433 static MonoMethod *m;
3439 MonoClass *ptr_klass = mono_class_get_pointer_class ();
3440 m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3446 get_default_field_value (domain, field, v);
3447 } else if (is_static) {
3448 mono_field_static_get_value (vtable, field, v);
3450 mono_field_get_value (obj, field, v);
3453 /* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3454 args [0] = ptr ? *ptr : NULL;
3455 args [1] = mono_type_get_object_checked (mono_domain_get (), type, &error);
3456 mono_error_raise_exception (&error); /* FIXME don't raise here */
3458 o = mono_runtime_invoke_checked (m, NULL, args, &error);
3459 mono_error_raise_exception (&error); /* FIXME don't raise here */
3464 /* boxed value type */
3465 klass = mono_class_from_mono_type (type);
3467 if (mono_class_is_nullable (klass))
3468 return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass);
3470 o = mono_object_new_checked (domain, klass, &error);
3471 mono_error_raise_exception (&error); /* FIXME don't raise here */
3472 v = ((gchar *) o) + sizeof (MonoObject);
3475 get_default_field_value (domain, field, v);
3476 } else if (is_static) {
3477 mono_field_static_get_value (vtable, field, v);
3479 mono_field_get_value (obj, field, v);
3486 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
3488 MONO_REQ_GC_UNSAFE_MODE;
3491 const char *p = blob;
3492 mono_metadata_decode_blob_size (p, &p);
3495 case MONO_TYPE_BOOLEAN:
3498 *(guint8 *) value = *p;
3500 case MONO_TYPE_CHAR:
3503 *(guint16*) value = read16 (p);
3507 *(guint32*) value = read32 (p);
3511 *(guint64*) value = read64 (p);
3514 readr4 (p, (float*) value);
3517 readr8 (p, (double*) value);
3519 case MONO_TYPE_STRING:
3520 *(gpointer*) value = mono_ldstr_metadata_sig (domain, blob);
3522 case MONO_TYPE_CLASS:
3523 *(gpointer*) value = NULL;
3527 g_warning ("type 0x%02x should not be in constant table", type);
3533 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
3535 MONO_REQ_GC_NEUTRAL_MODE;
3537 MonoTypeEnum def_type;
3540 data = mono_class_get_field_default_value (field, &def_type);
3541 mono_get_constant_value_from_blob (domain, def_type, data, value);
3545 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value)
3547 MONO_REQ_GC_UNSAFE_MODE;
3551 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3553 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3554 get_default_field_value (vt->domain, field, value);
3558 if (field->offset == -1) {
3559 /* Special static */
3560 gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3561 src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3563 src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3565 mono_copy_value (field->type, value, src, TRUE);
3569 * mono_field_static_get_value:
3570 * @vt: vtable to the object
3571 * @field: MonoClassField describing the field to fetch information from
3572 * @value: where the value is returned
3574 * Use this routine to get the value of the static field @field value.
3576 * The pointer provided by value must be of the field type, for reference
3577 * types this is a MonoObject*, for value types its the actual pointer to
3582 * mono_field_static_get_value (vt, int_field, &i);
3585 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3587 MONO_REQ_GC_NEUTRAL_MODE;
3589 mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value);
3593 * mono_property_set_value:
3594 * @prop: MonoProperty to set
3595 * @obj: instance object on which to act
3596 * @params: parameters to pass to the propery
3597 * @exc: optional exception
3599 * Invokes the property's set method with the given arguments on the
3600 * object instance obj (or NULL for static properties).
3602 * You can pass NULL as the exc argument if you don't want to
3603 * catch exceptions, otherwise, *exc will be set to the exception
3604 * thrown, if any. if an exception is thrown, you can't use the
3605 * MonoObject* result from the function.
3608 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3610 MONO_REQ_GC_UNSAFE_MODE;
3613 do_runtime_invoke (prop->set, obj, params, exc, &error);
3614 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3615 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3617 mono_error_raise_exception (&error); /* FIXME don't raise here */
3622 * mono_property_get_value:
3623 * @prop: MonoProperty to fetch
3624 * @obj: instance object on which to act
3625 * @params: parameters to pass to the propery
3626 * @exc: optional exception
3628 * Invokes the property's get method with the given arguments on the
3629 * object instance obj (or NULL for static properties).
3631 * You can pass NULL as the exc argument if you don't want to
3632 * catch exceptions, otherwise, *exc will be set to the exception
3633 * thrown, if any. if an exception is thrown, you can't use the
3634 * MonoObject* result from the function.
3636 * Returns: the value from invoking the get method on the property.
3639 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3641 MONO_REQ_GC_UNSAFE_MODE;
3644 MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3645 if (exc && *exc == NULL && !mono_error_ok (&error)) {
3646 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3648 mono_error_raise_exception (&error); /* FIXME don't raise here */
3655 * mono_nullable_init:
3656 * @buf: The nullable structure to initialize.
3657 * @value: the value to initialize from
3658 * @klass: the type for the object
3660 * Initialize the nullable structure pointed to by @buf from @value which
3661 * should be a boxed value type. The size of @buf should be able to hold
3662 * as much data as the @klass->instance_size (which is the number of bytes
3663 * that will be copies).
3665 * Since Nullables have variable structure, we can not define a C
3666 * structure for them.
3669 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3671 MONO_REQ_GC_UNSAFE_MODE;
3673 MonoClass *param_class = klass->cast_class;
3675 mono_class_setup_fields_locking (klass);
3676 g_assert (klass->fields_inited);
3678 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3679 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3681 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3683 if (param_class->has_references)
3684 mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3686 mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3688 mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3693 * mono_nullable_box:
3694 * @buf: The buffer representing the data to be boxed
3695 * @klass: the type to box it as.
3697 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
3701 mono_nullable_box (guint8 *buf, MonoClass *klass)
3703 MONO_REQ_GC_UNSAFE_MODE;
3707 MonoClass *param_class = klass->cast_class;
3709 mono_class_setup_fields_locking (klass);
3710 g_assert (klass->fields_inited);
3712 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3713 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3715 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3716 MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, &error);
3717 mono_error_raise_exception (&error); /* FIXME don't raise here */
3718 if (param_class->has_references)
3719 mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3721 mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3729 * mono_get_delegate_invoke:
3730 * @klass: The delegate class
3732 * Returns: the MonoMethod for the "Invoke" method in the delegate klass or NULL if @klass is a broken delegate type
3735 mono_get_delegate_invoke (MonoClass *klass)
3737 MONO_REQ_GC_NEUTRAL_MODE;
3741 /* This is called at runtime, so avoid the slower search in metadata */
3742 mono_class_setup_methods (klass);
3743 if (mono_class_has_failure (klass))
3745 im = mono_class_get_method_from_name (klass, "Invoke", -1);
3750 * mono_get_delegate_begin_invoke:
3751 * @klass: The delegate class
3753 * Returns: the MonoMethod for the "BeginInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3756 mono_get_delegate_begin_invoke (MonoClass *klass)
3758 MONO_REQ_GC_NEUTRAL_MODE;
3762 /* This is called at runtime, so avoid the slower search in metadata */
3763 mono_class_setup_methods (klass);
3764 if (mono_class_has_failure (klass))
3766 im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3771 * mono_get_delegate_end_invoke:
3772 * @klass: The delegate class
3774 * Returns: the MonoMethod for the "EndInvoke" method in the delegate klass or NULL if @klass is a broken delegate type
3777 mono_get_delegate_end_invoke (MonoClass *klass)
3779 MONO_REQ_GC_NEUTRAL_MODE;
3783 /* This is called at runtime, so avoid the slower search in metadata */
3784 mono_class_setup_methods (klass);
3785 if (mono_class_has_failure (klass))
3787 im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3792 * mono_runtime_delegate_invoke:
3793 * @delegate: pointer to a delegate object.
3794 * @params: parameters for the delegate.
3795 * @exc: Pointer to the exception result.
3797 * Invokes the delegate method @delegate with the parameters provided.
3799 * You can pass NULL as the exc argument if you don't want to
3800 * catch exceptions, otherwise, *exc will be set to the exception
3801 * thrown, if any. if an exception is thrown, you can't use the
3802 * MonoObject* result from the function.
3805 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3807 MONO_REQ_GC_UNSAFE_MODE;
3811 MonoClass *klass = delegate->vtable->klass;
3814 im = mono_get_delegate_invoke (klass);
3816 g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
3819 o = mono_runtime_try_invoke (im, delegate, params, exc, &error);
3820 if (*exc == NULL && !mono_error_ok (&error))
3821 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
3823 mono_error_cleanup (&error);
3825 o = mono_runtime_invoke_checked (im, delegate, params, &error);
3826 mono_error_raise_exception (&error); /* FIXME don't raise here */
3832 static char **main_args = NULL;
3833 static int num_main_args = 0;
3836 * mono_runtime_get_main_args:
3838 * Returns: a MonoArray with the arguments passed to the main program
3841 mono_runtime_get_main_args (void)
3843 MONO_REQ_GC_UNSAFE_MODE;
3847 MonoDomain *domain = mono_domain_get ();
3849 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
3851 for (i = 0; i < num_main_args; ++i)
3852 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
3858 free_main_args (void)
3860 MONO_REQ_GC_NEUTRAL_MODE;
3864 for (i = 0; i < num_main_args; ++i)
3865 g_free (main_args [i]);
3872 * mono_runtime_set_main_args:
3873 * @argc: number of arguments from the command line
3874 * @argv: array of strings from the command line
3876 * Set the command line arguments from an embedding application that doesn't otherwise call
3877 * mono_runtime_run_main ().
3880 mono_runtime_set_main_args (int argc, char* argv[])
3882 MONO_REQ_GC_NEUTRAL_MODE;
3887 main_args = g_new0 (char*, argc);
3888 num_main_args = argc;
3890 for (i = 0; i < argc; ++i) {
3893 utf8_arg = mono_utf8_from_external (argv[i]);
3894 if (utf8_arg == NULL) {
3895 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
3896 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3900 main_args [i] = utf8_arg;
3907 * mono_runtime_run_main:
3908 * @method: the method to start the application with (usually Main)
3909 * @argc: number of arguments from the command line
3910 * @argv: array of strings from the command line
3911 * @exc: excetption results
3913 * Execute a standard Main() method (argc/argv contains the
3914 * executable name). This method also sets the command line argument value
3915 * needed by System.Environment.
3920 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
3923 MONO_REQ_GC_UNSAFE_MODE;
3926 MonoArray *args = NULL;
3927 MonoDomain *domain = mono_domain_get ();
3928 gchar *utf8_fullpath;
3929 MonoMethodSignature *sig;
3931 g_assert (method != NULL);
3933 mono_thread_set_main (mono_thread_current ());
3935 main_args = g_new0 (char*, argc);
3936 num_main_args = argc;
3938 if (!g_path_is_absolute (argv [0])) {
3939 gchar *basename = g_path_get_basename (argv [0]);
3940 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
3944 utf8_fullpath = mono_utf8_from_external (fullpath);
3945 if(utf8_fullpath == NULL) {
3946 /* Printing the arg text will cause glib to
3947 * whinge about "Invalid UTF-8", but at least
3948 * its relevant, and shows the problem text
3951 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
3952 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3959 utf8_fullpath = mono_utf8_from_external (argv[0]);
3960 if(utf8_fullpath == NULL) {
3961 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
3962 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3967 main_args [0] = utf8_fullpath;
3969 for (i = 1; i < argc; ++i) {
3972 utf8_arg=mono_utf8_from_external (argv[i]);
3973 if(utf8_arg==NULL) {
3974 /* Ditto the comment about Invalid UTF-8 here */
3975 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
3976 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
3980 main_args [i] = utf8_arg;
3985 sig = mono_method_signature (method);
3987 g_print ("Unable to load Main method.\n");
3991 if (sig->param_count) {
3992 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
3993 for (i = 0; i < argc; ++i) {
3994 /* The encodings should all work, given that
3995 * we've checked all these args for the
3998 gchar *str = mono_utf8_from_external (argv [i]);
3999 MonoString *arg = mono_string_new (domain, str);
4000 mono_array_setref (args, i, arg);
4004 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
4007 mono_assembly_set_main (method->klass->image->assembly);
4009 return mono_runtime_exec_main (method, args, exc);
4013 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4015 static MonoMethod *serialize_method;
4021 if (!serialize_method) {
4022 MonoClass *klass = mono_class_get_remoting_services_class ();
4023 serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4026 if (!serialize_method) {
4031 g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4036 array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4037 if (*exc == NULL && !mono_error_ok (&error))
4038 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4040 mono_error_cleanup (&error);
4049 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4051 MONO_REQ_GC_UNSAFE_MODE;
4053 static MonoMethod *deserialize_method;
4059 if (!deserialize_method) {
4060 MonoClass *klass = mono_class_get_remoting_services_class ();
4061 deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4063 if (!deserialize_method) {
4071 result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4072 if (*exc == NULL && !mono_error_ok (&error))
4073 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4075 mono_error_cleanup (&error);
4083 #ifndef DISABLE_REMOTING
4085 make_transparent_proxy (MonoObject *obj, gboolean *failure, MonoObject **exc)
4087 MONO_REQ_GC_UNSAFE_MODE;
4089 static MonoMethod *get_proxy_method;
4092 MonoDomain *domain = mono_domain_get ();
4093 MonoRealProxy *real_proxy;
4094 MonoReflectionType *reflection_type;
4095 MonoTransparentProxy *transparent_proxy;
4097 if (!get_proxy_method)
4098 get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4100 g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4102 real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, &error);
4103 mono_error_raise_exception (&error); /* FIXME don't raise here */
4104 reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, &error);
4105 mono_error_raise_exception (&error); /* FIXME don't raise here */
4107 MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4108 MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4112 transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, exc, &error);
4113 if (*exc == NULL && !mono_error_ok (&error))
4114 *exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME change make_transparent_proxy outarg to MonoError */
4116 mono_error_cleanup (&error);
4120 return (MonoObject*) transparent_proxy;
4122 #endif /* DISABLE_REMOTING */
4125 * mono_object_xdomain_representation
4127 * @target_domain: a domain
4128 * @exc: pointer to a MonoObject*
4130 * Creates a representation of obj in the domain target_domain. This
4131 * is either a copy of obj arrived through via serialization and
4132 * deserialization or a proxy, depending on whether the object is
4133 * serializable or marshal by ref. obj must not be in target_domain.
4135 * If the object cannot be represented in target_domain, NULL is
4136 * returned and *exc is set to an appropriate exception.
4139 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoObject **exc)
4141 MONO_REQ_GC_UNSAFE_MODE;
4143 MonoObject *deserialized = NULL;
4144 gboolean failure = FALSE;
4146 g_assert (exc != NULL);
4149 #ifndef DISABLE_REMOTING
4150 if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4151 deserialized = make_transparent_proxy (obj, &failure, exc);
4156 MonoDomain *domain = mono_domain_get ();
4157 MonoObject *serialized;
4159 mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4160 serialized = serialize_object (obj, &failure, exc);
4161 mono_domain_set_internal_with_options (target_domain, FALSE);
4163 deserialized = deserialize_object (serialized, &failure, exc);
4164 if (domain != target_domain)
4165 mono_domain_set_internal_with_options (domain, FALSE);
4168 return deserialized;
4171 /* Used in call_unhandled_exception_delegate */
4173 create_unhandled_exception_eventargs (MonoObject *exc)
4175 MONO_REQ_GC_UNSAFE_MODE;
4180 MonoMethod *method = NULL;
4181 MonoBoolean is_terminating = TRUE;
4184 klass = mono_class_get_unhandled_exception_event_args_class ();
4185 mono_class_init (klass);
4187 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4188 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4192 args [1] = &is_terminating;
4194 obj = mono_object_new_checked (mono_domain_get (), klass, &error);
4195 mono_error_raise_exception (&error); /* FIXME don't raise here */
4197 mono_runtime_invoke_checked (method, obj, args, &error);
4198 mono_error_raise_exception (&error); /* FIXME don't raise here */
4203 /* Used in mono_unhandled_exception */
4205 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4206 MONO_REQ_GC_UNSAFE_MODE;
4208 MonoObject *e = NULL;
4210 MonoDomain *current_domain = mono_domain_get ();
4212 if (domain != current_domain)
4213 mono_domain_set_internal_with_options (domain, FALSE);
4215 g_assert (domain == mono_object_domain (domain->domain));
4217 if (mono_object_domain (exc) != domain) {
4218 MonoObject *serialization_exc;
4220 exc = mono_object_xdomain_representation (exc, domain, &serialization_exc);
4222 if (serialization_exc) {
4224 exc = mono_object_xdomain_representation (serialization_exc, domain, &dummy);
4227 exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4228 "System.Runtime.Serialization", "SerializationException",
4229 "Could not serialize unhandled exception.");
4233 g_assert (mono_object_domain (exc) == domain);
4235 pa [0] = domain->domain;
4236 pa [1] = create_unhandled_exception_eventargs (exc);
4237 mono_runtime_delegate_invoke (delegate, pa, &e);
4239 if (domain != current_domain)
4240 mono_domain_set_internal_with_options (current_domain, FALSE);
4244 gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4245 if (!mono_error_ok (&error)) {
4246 g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4247 mono_error_cleanup (&error);
4249 g_warning ("exception inside UnhandledException handler: %s\n", msg);
4255 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4258 * mono_runtime_unhandled_exception_policy_set:
4259 * @policy: the new policy
4261 * This is a VM internal routine.
4263 * Sets the runtime policy for handling unhandled exceptions.
4266 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4267 runtime_unhandled_exception_policy = policy;
4271 * mono_runtime_unhandled_exception_policy_get:
4273 * This is a VM internal routine.
4275 * Gets the runtime policy for handling unhandled exceptions.
4277 MonoRuntimeUnhandledExceptionPolicy
4278 mono_runtime_unhandled_exception_policy_get (void) {
4279 return runtime_unhandled_exception_policy;
4283 * mono_unhandled_exception:
4284 * @exc: exception thrown
4286 * This is a VM internal routine.
4288 * We call this function when we detect an unhandled exception
4289 * in the default domain.
4291 * It invokes the * UnhandledException event in AppDomain or prints
4292 * a warning to the console
4295 mono_unhandled_exception (MonoObject *exc)
4297 MONO_REQ_GC_UNSAFE_MODE;
4299 MonoClassField *field;
4300 MonoDomain *current_domain, *root_domain;
4301 MonoObject *current_appdomain_delegate = NULL, *root_appdomain_delegate = NULL;
4303 if (mono_class_has_parent (exc->vtable->klass, mono_defaults.threadabortexception_class))
4306 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4309 current_domain = mono_domain_get ();
4310 root_domain = mono_get_root_domain ();
4312 root_appdomain_delegate = mono_field_get_value_object (root_domain, field, (MonoObject*) root_domain->domain);
4313 if (current_domain != root_domain)
4314 current_appdomain_delegate = mono_field_get_value_object (current_domain, field, (MonoObject*) current_domain->domain);
4316 /* set exitcode only if we will abort the process */
4317 if (!current_appdomain_delegate && !root_appdomain_delegate) {
4318 if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4319 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4321 mono_environment_exitcode_set (1);
4324 mono_print_unhandled_exception (exc);
4326 if (root_appdomain_delegate)
4327 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
4328 if (current_appdomain_delegate)
4329 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
4334 * mono_runtime_exec_managed_code:
4335 * @domain: Application domain
4336 * @main_func: function to invoke from the execution thread
4337 * @main_args: parameter to the main_func
4339 * Launch a new thread to execute a function
4341 * main_func is called back from the thread with main_args as the
4342 * parameter. The callback function is expected to start Main()
4343 * eventually. This function then waits for all managed threads to
4345 * It is not necesseray anymore to execute managed code in a subthread,
4346 * so this function should not be used anymore by default: just
4347 * execute the code and then call mono_thread_manage ().
4350 mono_runtime_exec_managed_code (MonoDomain *domain,
4351 MonoMainThreadFunc main_func,
4354 mono_thread_create (domain, main_func, main_args);
4356 mono_thread_manage ();
4360 * Execute a standard Main() method (args doesn't contain the
4364 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4366 MONO_REQ_GC_UNSAFE_MODE;
4372 MonoCustomAttrInfo* cinfo;
4373 gboolean has_stathread_attribute;
4374 MonoInternalThread* thread = mono_thread_internal_current ();
4380 domain = mono_object_domain (args);
4381 if (!domain->entry_assembly) {
4383 MonoAssembly *assembly;
4385 assembly = method->klass->image->assembly;
4386 domain->entry_assembly = assembly;
4387 /* Domains created from another domain already have application_base and configuration_file set */
4388 if (domain->setup->application_base == NULL) {
4389 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
4392 if (domain->setup->configuration_file == NULL) {
4393 str = g_strconcat (assembly->image->name, ".config", NULL);
4394 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
4396 mono_domain_set_options_from_config (domain);
4400 cinfo = mono_custom_attrs_from_method (method);
4402 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4404 mono_custom_attrs_free (cinfo);
4406 has_stathread_attribute = FALSE;
4408 if (has_stathread_attribute) {
4409 thread->apartment_state = ThreadApartmentState_STA;
4411 thread->apartment_state = ThreadApartmentState_MTA;
4413 mono_thread_init_apartment_state ();
4415 /* FIXME: check signature of method */
4416 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4419 res = mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4420 if (*exc == NULL && !mono_error_ok (&error))
4421 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4423 mono_error_cleanup (&error);
4425 res = mono_runtime_invoke_checked (method, NULL, pa, &error);
4426 mono_error_raise_exception (&error); /* FIXME don't raise here */
4430 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4434 mono_environment_exitcode_set (rval);
4437 mono_runtime_try_invoke (method, NULL, pa, exc, &error);
4438 if (*exc == NULL && !mono_error_ok (&error))
4439 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4441 mono_error_cleanup (&error);
4443 mono_runtime_invoke_checked (method, NULL, pa, &error);
4444 mono_error_raise_exception (&error); /* FIXME don't raise here */
4450 /* If the return type of Main is void, only
4451 * set the exitcode if an exception was thrown
4452 * (we don't want to blow away an
4453 * explicitly-set exit code)
4456 mono_environment_exitcode_set (rval);
4464 * mono_runtime_invoke_array:
4465 * @method: method to invoke
4466 * @obJ: object instance
4467 * @params: arguments to the method
4468 * @exc: exception information.
4470 * Invokes the method represented by @method on the object @obj.
4472 * obj is the 'this' pointer, it should be NULL for static
4473 * methods, a MonoObject* for object instances and a pointer to
4474 * the value type for value types.
4476 * The params array contains the arguments to the method with the
4477 * same convention: MonoObject* pointers for object instances and
4478 * pointers to the value type otherwise. The _invoke_array
4479 * variant takes a C# object[] as the params argument (MonoArray
4480 * *params): in this case the value types are boxed inside the
4481 * respective reference representation.
4483 * From unmanaged code you'll usually use the
4484 * mono_runtime_invoke_checked() variant.
4486 * Note that this function doesn't handle virtual methods for
4487 * you, it will exec the exact method you pass: we still need to
4488 * expose a function to lookup the derived class implementation
4489 * of a virtual method (there are examples of this in the code,
4492 * You can pass NULL as the exc argument if you don't want to
4493 * catch exceptions, otherwise, *exc will be set to the exception
4494 * thrown, if any. if an exception is thrown, you can't use the
4495 * MonoObject* result from the function.
4497 * If the method returns a value type, it is boxed in an object
4501 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
4504 MONO_REQ_GC_UNSAFE_MODE;
4507 MonoMethodSignature *sig = mono_method_signature (method);
4508 gpointer *pa = NULL;
4511 gboolean has_byref_nullables = FALSE;
4513 if (NULL != params) {
4514 pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
4515 for (i = 0; i < mono_array_length (params); i++) {
4516 MonoType *t = sig->params [i];
4522 case MONO_TYPE_BOOLEAN:
4525 case MONO_TYPE_CHAR:
4534 case MONO_TYPE_VALUETYPE:
4535 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4536 /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4537 pa [i] = mono_array_get (params, MonoObject*, i);
4539 has_byref_nullables = TRUE;
4541 /* MS seems to create the objects if a null is passed in */
4542 if (!mono_array_get (params, MonoObject*, i)) {
4543 MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (sig->params [i]), &error);
4544 mono_error_raise_exception (&error); /* FIXME don't raise here */
4545 mono_array_setref (params, i, o);
4550 * We can't pass the unboxed vtype byref to the callee, since
4551 * that would mean the callee would be able to modify boxed
4552 * primitive types. So we (and MS) make a copy of the boxed
4553 * object, pass that to the callee, and replace the original
4554 * boxed object in the arg array with the copy.
4556 MonoObject *orig = mono_array_get (params, MonoObject*, i);
4557 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
4558 mono_array_setref (params, i, copy);
4561 pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4564 case MONO_TYPE_STRING:
4565 case MONO_TYPE_OBJECT:
4566 case MONO_TYPE_CLASS:
4567 case MONO_TYPE_ARRAY:
4568 case MONO_TYPE_SZARRAY:
4570 pa [i] = mono_array_addr (params, MonoObject*, i);
4571 // FIXME: I need to check this code path
4573 pa [i] = mono_array_get (params, MonoObject*, i);
4575 case MONO_TYPE_GENERICINST:
4577 t = &t->data.generic_class->container_class->this_arg;
4579 t = &t->data.generic_class->container_class->byval_arg;
4581 case MONO_TYPE_PTR: {
4584 /* The argument should be an IntPtr */
4585 arg = mono_array_get (params, MonoObject*, i);
4589 g_assert (arg->vtable->klass == mono_defaults.int_class);
4590 pa [i] = ((MonoIntPtr*)arg)->m_value;
4595 g_error ("type 0x%x not handled in mono_runtime_invoke_array", sig->params [i]->type);
4600 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
4603 if (mono_class_is_nullable (method->klass)) {
4604 /* Need to create a boxed vtype instead */
4610 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
4614 obj = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4615 g_assert (obj && mono_error_ok (&error)); /*maybe we should raise a TLE instead?*/ /* FIXME don't swallow error */
4616 #ifndef DISABLE_REMOTING
4617 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
4618 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
4621 if (method->klass->valuetype)
4622 o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
4625 } else if (method->klass->valuetype) {
4626 obj = mono_value_box (mono_domain_get (), method->klass, obj);
4630 mono_runtime_try_invoke (method, o, pa, exc, &error);
4631 if (*exc == NULL && !mono_error_ok (&error))
4632 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4634 mono_error_cleanup (&error);
4636 mono_runtime_invoke_checked (method, o, pa, &error);
4637 mono_error_raise_exception (&error); /* FIXME don't raise here */
4640 return (MonoObject *)obj;
4642 if (mono_class_is_nullable (method->klass)) {
4643 MonoObject *nullable;
4645 /* Convert the unboxed vtype into a Nullable structure */
4646 nullable = mono_object_new_checked (mono_domain_get (), method->klass, &error);
4647 mono_error_raise_exception (&error); /* FIXME don't raise here */
4649 mono_nullable_init ((guint8 *)mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
4650 obj = mono_object_unbox (nullable);
4653 /* obj must be already unboxed if needed */
4655 res = mono_runtime_try_invoke (method, obj, pa, exc, &error);
4656 if (*exc == NULL && !mono_error_ok (&error))
4657 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
4659 mono_error_cleanup (&error);
4661 res = mono_runtime_invoke_checked (method, obj, pa, &error);
4662 mono_error_raise_exception (&error); /* FIXME don't raise here */
4665 if (sig->ret->type == MONO_TYPE_PTR) {
4666 MonoClass *pointer_class;
4667 static MonoMethod *box_method;
4669 MonoObject *box_exc;
4672 * The runtime-invoke wrapper returns a boxed IntPtr, need to
4673 * convert it to a Pointer object.
4675 pointer_class = mono_class_get_pointer_class ();
4677 box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
4679 g_assert (res->vtable->klass == mono_defaults.int_class);
4680 box_args [0] = ((MonoIntPtr*)res)->m_value;
4681 box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, &error);
4682 mono_error_raise_exception (&error); /* FIXME don't raise here */
4684 res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, &error);
4685 g_assert (box_exc == NULL);
4686 mono_error_assert_ok (&error);
4689 if (has_byref_nullables) {
4691 * The runtime invoke wrapper already converted byref nullables back,
4692 * and stored them in pa, we just need to copy them back to the
4695 for (i = 0; i < mono_array_length (params); i++) {
4696 MonoType *t = sig->params [i];
4698 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
4699 mono_array_setref (params, i, pa [i]);
4709 * @klass: the class of the object that we want to create
4711 * Returns: a newly created object whose definition is
4712 * looked up using @klass. This will not invoke any constructors,
4713 * so the consumer of this routine has to invoke any constructors on
4714 * its own to initialize the object.
4716 * It returns NULL on failure.
4719 mono_object_new (MonoDomain *domain, MonoClass *klass)
4721 MONO_REQ_GC_UNSAFE_MODE;
4725 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4727 mono_error_raise_exception (&error);
4732 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
4734 MONO_REQ_GC_UNSAFE_MODE;
4738 MonoObject * result = mono_object_new_checked (domain, klass, &error);
4740 mono_error_raise_exception (&error);
4745 * mono_object_new_checked:
4746 * @klass: the class of the object that we want to create
4747 * @error: set on error
4749 * Returns: a newly created object whose definition is
4750 * looked up using @klass. This will not invoke any constructors,
4751 * so the consumer of this routine has to invoke any constructors on
4752 * its own to initialize the object.
4754 * It returns NULL on failure and sets @error.
4757 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
4759 MONO_REQ_GC_UNSAFE_MODE;
4763 vtable = mono_class_vtable (domain, klass);
4764 g_assert (vtable); /* FIXME don't swallow the error */
4766 MonoObject *o = mono_object_new_specific_checked (vtable, error);
4771 * mono_object_new_pinned:
4773 * Same as mono_object_new, but the returned object will be pinned.
4774 * For SGEN, these objects will only be freed at appdomain unload.
4777 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
4779 MONO_REQ_GC_UNSAFE_MODE;
4783 mono_error_init (error);
4785 vtable = mono_class_vtable (domain, klass);
4786 g_assert (vtable); /* FIXME don't swallow the error */
4788 MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
4790 if (G_UNLIKELY (!o))
4791 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
4792 else if (G_UNLIKELY (vtable->klass->has_finalize))
4793 mono_object_register_finalizer (o, error);
4799 * mono_object_new_specific:
4800 * @vtable: the vtable of the object that we want to create
4802 * Returns: A newly created object with class and domain specified
4806 mono_object_new_specific (MonoVTable *vtable)
4809 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4810 mono_error_raise_exception (&error);
4816 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
4818 MONO_REQ_GC_UNSAFE_MODE;
4822 mono_error_init (error);
4824 /* check for is_com_object for COM Interop */
4825 if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
4828 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
4831 MonoClass *klass = mono_class_get_activation_services_class ();
4834 mono_class_init (klass);
4836 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
4838 mono_error_set_generic_error (error, "System", "NotSupportedException", "Linked away.");
4841 vtable->domain->create_proxy_for_type_method = im;
4844 pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
4845 if (!mono_error_ok (error))
4848 o = mono_runtime_invoke_checked (im, NULL, pa, error);
4849 if (!mono_error_ok (error))
4856 return mono_object_new_alloc_specific_checked (vtable, error);
4860 ves_icall_object_new_specific (MonoVTable *vtable)
4863 MonoObject *o = mono_object_new_specific_checked (vtable, &error);
4864 mono_error_raise_exception (&error);
4870 * mono_object_new_alloc_specific:
4871 * @vtable: virtual table for the object.
4873 * This function allocates a new `MonoObject` with the type derived
4874 * from the @vtable information. If the class of this object has a
4875 * finalizer, then the object will be tracked for finalization.
4877 * This method might raise an exception on errors. Use the
4878 * `mono_object_new_fast_checked` method if you want to manually raise
4881 * Returns: the allocated object.
4884 mono_object_new_alloc_specific (MonoVTable *vtable)
4887 MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
4888 mono_error_raise_exception (&error);
4894 * mono_object_new_alloc_specific_checked:
4895 * @vtable: virtual table for the object.
4896 * @error: holds the error return value.
4898 * This function allocates a new `MonoObject` with the type derived
4899 * from the @vtable information. If the class of this object has a
4900 * finalizer, then the object will be tracked for finalization.
4902 * If there is not enough memory, the @error parameter will be set
4903 * and will contain a user-visible message with the amount of bytes
4904 * that were requested.
4906 * Returns: the allocated object, or NULL if there is not enough memory
4910 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
4912 MONO_REQ_GC_UNSAFE_MODE;
4916 mono_error_init (error);
4918 o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4920 if (G_UNLIKELY (!o))
4921 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4922 else if (G_UNLIKELY (vtable->klass->has_finalize))
4923 mono_object_register_finalizer (o, error);
4929 * mono_object_new_fast:
4930 * @vtable: virtual table for the object.
4932 * This function allocates a new `MonoObject` with the type derived
4933 * from the @vtable information. The returned object is not tracked
4934 * for finalization. If your object implements a finalizer, you should
4935 * use `mono_object_new_alloc_specific` instead.
4937 * This method might raise an exception on errors. Use the
4938 * `mono_object_new_fast_checked` method if you want to manually raise
4941 * Returns: the allocated object.
4944 mono_object_new_fast (MonoVTable *vtable)
4947 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4948 mono_error_raise_exception (&error);
4954 * mono_object_new_fast_checked:
4955 * @vtable: virtual table for the object.
4956 * @error: holds the error return value.
4958 * This function allocates a new `MonoObject` with the type derived
4959 * from the @vtable information. The returned object is not tracked
4960 * for finalization. If your object implements a finalizer, you should
4961 * use `mono_object_new_alloc_specific_checked` instead.
4963 * If there is not enough memory, the @error parameter will be set
4964 * and will contain a user-visible message with the amount of bytes
4965 * that were requested.
4967 * Returns: the allocated object, or NULL if there is not enough memory
4971 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
4973 MONO_REQ_GC_UNSAFE_MODE;
4977 mono_error_init (error);
4979 o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
4981 if (G_UNLIKELY (!o))
4982 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
4988 ves_icall_object_new_fast (MonoVTable *vtable)
4991 MonoObject *o = mono_object_new_fast_checked (vtable, &error);
4992 mono_error_raise_exception (&error);
4998 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5000 MONO_REQ_GC_UNSAFE_MODE;
5004 mono_error_init (error);
5006 o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5008 if (G_UNLIKELY (!o))
5009 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5010 else if (G_UNLIKELY (vtable->klass->has_finalize))
5011 mono_object_register_finalizer (o, error);
5017 * mono_class_get_allocation_ftn:
5019 * @for_box: the object will be used for boxing
5020 * @pass_size_in_words:
5022 * Return the allocation function appropriate for the given class.
5026 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
5028 MONO_REQ_GC_NEUTRAL_MODE;
5030 *pass_size_in_words = FALSE;
5032 if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
5033 return ves_icall_object_new_specific;
5035 if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
5037 return ves_icall_object_new_fast;
5040 * FIXME: This is actually slower than ves_icall_object_new_fast, because
5041 * of the overhead of parameter passing.
5044 *pass_size_in_words = TRUE;
5045 #ifdef GC_REDIRECT_TO_LOCAL
5046 return GC_local_gcj_fast_malloc;
5048 return GC_gcj_fast_malloc;
5053 return ves_icall_object_new_specific;
5057 * mono_object_new_from_token:
5058 * @image: Context where the type_token is hosted
5059 * @token: a token of the type that we want to create
5061 * Returns: A newly created object whose definition is
5062 * looked up using @token in the @image image
5065 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
5067 MONO_REQ_GC_UNSAFE_MODE;
5073 klass = mono_class_get_checked (image, token, &error);
5074 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
5076 result = mono_object_new_checked (domain, klass, &error);
5078 mono_error_raise_exception (&error); /* FIXME don't raise here */
5085 * mono_object_clone:
5086 * @obj: the object to clone
5088 * Returns: A newly created object who is a shallow copy of @obj
5091 mono_object_clone (MonoObject *obj)
5094 MonoObject *o = mono_object_clone_checked (obj, &error);
5095 mono_error_raise_exception (&error);
5101 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5103 MONO_REQ_GC_UNSAFE_MODE;
5108 mono_error_init (error);
5110 size = obj->vtable->klass->instance_size;
5112 if (obj->vtable->klass->rank)
5113 return (MonoObject*)mono_array_clone ((MonoArray*)obj);
5115 o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5117 if (G_UNLIKELY (!o)) {
5118 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5122 /* If the object doesn't contain references this will do a simple memmove. */
5123 mono_gc_wbarrier_object_copy (o, obj);
5125 if (obj->vtable->klass->has_finalize)
5126 mono_object_register_finalizer (o, error);
5131 * mono_array_full_copy:
5132 * @src: source array to copy
5133 * @dest: destination array
5135 * Copies the content of one array to another with exactly the same type and size.
5138 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5140 MONO_REQ_GC_UNSAFE_MODE;
5143 MonoClass *klass = src->obj.vtable->klass;
5145 g_assert (klass == dest->obj.vtable->klass);
5147 size = mono_array_length (src);
5148 g_assert (size == mono_array_length (dest));
5149 size *= mono_array_element_size (klass);
5151 if (klass->element_class->valuetype) {
5152 if (klass->element_class->has_references)
5153 mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5155 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5157 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5160 mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5165 * mono_array_clone_in_domain:
5166 * @domain: the domain in which the array will be cloned into
5167 * @array: the array to clone
5169 * This routine returns a copy of the array that is hosted on the
5170 * specified MonoDomain.
5173 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
5175 MONO_REQ_GC_UNSAFE_MODE;
5181 MonoClass *klass = array->obj.vtable->klass;
5183 if (array->bounds == NULL) {
5184 size = mono_array_length (array);
5185 o = mono_array_new_full_checked (domain, klass, &size, NULL, &error);
5186 mono_error_raise_exception (&error); /* FIXME don't raise here */
5188 size *= mono_array_element_size (klass);
5190 if (klass->element_class->valuetype) {
5191 if (klass->element_class->has_references)
5192 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5194 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5196 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5199 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5204 sizes = (uintptr_t *)alloca (klass->rank * sizeof(intptr_t) * 2);
5205 size = mono_array_element_size (klass);
5206 for (i = 0; i < klass->rank; ++i) {
5207 sizes [i] = array->bounds [i].length;
5208 size *= array->bounds [i].length;
5209 sizes [i + klass->rank] = array->bounds [i].lower_bound;
5211 o = mono_array_new_full_checked (domain, klass, sizes, (intptr_t*)sizes + klass->rank, &error);
5212 mono_error_raise_exception (&error); /* FIXME don't raise here */
5214 if (klass->element_class->valuetype) {
5215 if (klass->element_class->has_references)
5216 mono_value_copy_array (o, 0, mono_array_addr_with_size_fast (array, 0, 0), mono_array_length (array));
5218 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5220 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
5223 mono_gc_memmove_atomic (&o->vector, &array->vector, size);
5231 * @array: the array to clone
5233 * Returns: A newly created array who is a shallow copy of @array
5236 mono_array_clone (MonoArray *array)
5238 MONO_REQ_GC_UNSAFE_MODE;
5240 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
5243 /* helper macros to check for overflow when calculating the size of arrays */
5244 #ifdef MONO_BIG_ARRAYS
5245 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5246 #define MYGUINT_MAX MYGUINT64_MAX
5247 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5248 (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5249 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5250 (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) && \
5251 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5253 #define MYGUINT32_MAX 4294967295U
5254 #define MYGUINT_MAX MYGUINT32_MAX
5255 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5256 (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5257 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5258 (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) && \
5259 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5263 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5265 MONO_REQ_GC_NEUTRAL_MODE;
5269 byte_len = mono_array_element_size (klass);
5270 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5273 if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5275 byte_len += MONO_SIZEOF_MONO_ARRAY;
5283 * mono_array_new_full:
5284 * @domain: domain where the object is created
5285 * @array_class: array class
5286 * @lengths: lengths for each dimension in the array
5287 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
5289 * This routine creates a new array objects with the given dimensions,
5290 * lower bounds and type.
5293 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5296 MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5297 mono_error_raise_exception (&error);
5303 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5305 MONO_REQ_GC_UNSAFE_MODE;
5307 uintptr_t byte_len = 0, len, bounds_size;
5310 MonoArrayBounds *bounds;
5314 mono_error_init (error);
5316 if (!array_class->inited)
5317 mono_class_init (array_class);
5321 /* A single dimensional array with a 0 lower bound is the same as an szarray */
5322 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5324 if (len > MONO_ARRAY_MAX_INDEX) {
5325 mono_error_set_generic_error (error, "System", "OverflowException", "");
5330 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5332 for (i = 0; i < array_class->rank; ++i) {
5333 if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5334 mono_error_set_generic_error (error, "System", "OverflowException", "");
5337 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5338 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5345 if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5346 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5352 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5353 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5356 byte_len = (byte_len + 3) & ~3;
5357 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5358 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5361 byte_len += bounds_size;
5364 * Following three lines almost taken from mono_object_new ():
5365 * they need to be kept in sync.
5367 vtable = mono_class_vtable_full (domain, array_class, error);
5368 return_val_if_nok (error, NULL);
5371 o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5373 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5375 if (G_UNLIKELY (!o)) {
5376 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5380 array = (MonoArray*)o;
5382 bounds = array->bounds;
5385 for (i = 0; i < array_class->rank; ++i) {
5386 bounds [i].length = lengths [i];
5388 bounds [i].lower_bound = lower_bounds [i];
5397 * @domain: domain where the object is created
5398 * @eclass: element class
5399 * @n: number of array elements
5401 * This routine creates a new szarray with @n elements of type @eclass.
5404 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5406 MONO_REQ_GC_UNSAFE_MODE;
5412 ac = mono_array_class_get (eclass, 1);
5415 MonoVTable *vtable = mono_class_vtable_full (domain, ac, &error);
5416 mono_error_raise_exception (&error); /* FIXME don't raise here */
5418 arr = mono_array_new_specific_checked (vtable, n, &error);
5419 mono_error_raise_exception (&error); /* FIXME don't raise here */
5425 * mono_array_new_specific:
5426 * @vtable: a vtable in the appropriate domain for an initialized class
5427 * @n: number of array elements
5429 * This routine is a fast alternative to mono_array_new() for code which
5430 * can be sure about the domain it operates in.
5433 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5436 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5437 mono_error_raise_exception (&error); /* FIXME don't raise here */
5443 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5445 MONO_REQ_GC_UNSAFE_MODE;
5450 mono_error_init (error);
5452 if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
5453 mono_error_set_generic_error (error, "System", "OverflowException", "");
5457 if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
5458 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5461 o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
5463 if (G_UNLIKELY (!o)) {
5464 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", byte_len);
5468 return (MonoArray*)o;
5472 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
5475 MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5476 mono_error_raise_exception (&error);
5482 * mono_string_new_utf16:
5483 * @text: a pointer to an utf16 string
5484 * @len: the length of the string
5486 * Returns: A newly created string object which contains @text.
5489 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
5491 MONO_REQ_GC_UNSAFE_MODE;
5494 MonoString *res = NULL;
5495 res = mono_string_new_utf16_checked (domain, text, len, &error);
5496 mono_error_raise_exception (&error);
5502 * mono_string_new_utf16_checked:
5503 * @text: a pointer to an utf16 string
5504 * @len: the length of the string
5505 * @error: written on error.
5507 * Returns: A newly created string object which contains @text.
5508 * On error, returns NULL and sets @error.
5511 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5513 MONO_REQ_GC_UNSAFE_MODE;
5517 mono_error_init (error);
5519 s = mono_string_new_size_checked (domain, len, error);
5521 memcpy (mono_string_chars (s), text, len * 2);
5527 * mono_string_new_utf32:
5528 * @text: a pointer to an utf32 string
5529 * @len: the length of the string
5531 * Returns: A newly created string object which contains @text.
5534 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5536 MONO_REQ_GC_UNSAFE_MODE;
5540 mono_unichar2 *utf16_output = NULL;
5541 gint32 utf16_len = 0;
5542 GError *gerror = NULL;
5543 glong items_written;
5545 utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5548 g_error_free (gerror);
5550 while (utf16_output [utf16_len]) utf16_len++;
5552 s = mono_string_new_size_checked (domain, utf16_len, &error);
5553 mono_error_raise_exception (&error); /* FIXME don't raise here */
5555 memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5557 g_free (utf16_output);
5563 * mono_string_new_size:
5564 * @text: a pointer to an utf16 string
5565 * @len: the length of the string
5567 * Returns: A newly created string object of @len
5570 mono_string_new_size (MonoDomain *domain, gint32 len)
5573 MonoString *str = mono_string_new_size_checked (domain, len, &error);
5574 mono_error_raise_exception (&error);
5580 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5582 MONO_REQ_GC_UNSAFE_MODE;
5588 mono_error_init (error);
5590 /* check for overflow */
5591 if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5592 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5596 size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5597 g_assert (size > 0);
5599 vtable = mono_class_vtable (domain, mono_defaults.string_class);
5602 s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5604 if (G_UNLIKELY (!s)) {
5605 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5613 * mono_string_new_len:
5614 * @text: a pointer to an utf8 string
5615 * @length: number of bytes in @text to consider
5617 * Returns: A newly created string object which contains @text.
5620 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5622 MONO_REQ_GC_UNSAFE_MODE;
5625 GError *eg_error = NULL;
5626 MonoString *o = NULL;
5628 glong items_written;
5630 mono_error_init (&error);
5632 ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
5635 o = mono_string_new_utf16_checked (domain, ut, items_written, &error);
5637 g_error_free (eg_error);
5641 mono_error_raise_exception (&error); /* FIXME don't raise here */
5647 * @text: a pointer to an utf8 string
5649 * Returns: A newly created string object which contains @text.
5651 * This function asserts if it cannot allocate a new string.
5653 * @deprecated Use mono_string_new_checked in new code.
5656 mono_string_new (MonoDomain *domain, const char *text)
5659 MonoString *res = NULL;
5660 res = mono_string_new_checked (domain, text, &error);
5661 mono_error_assert_ok (&error);
5666 * mono_string_new_checked:
5667 * @text: a pointer to an utf8 string
5668 * @merror: set on error
5670 * Returns: A newly created string object which contains @text.
5671 * On error returns NULL and sets @merror.
5674 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
5676 MONO_REQ_GC_UNSAFE_MODE;
5678 GError *eg_error = NULL;
5679 MonoString *o = NULL;
5681 glong items_written;
5684 mono_error_init (error);
5688 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
5691 o = mono_string_new_utf16_checked (domain, ut, items_written, error);
5693 g_error_free (eg_error);
5696 mono_error_raise_exception (error);
5698 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5703 MonoString *o = NULL;
5705 if (!g_utf8_validate (text, -1, &end)) {
5706 mono_error_set_argument (error, "text", "Not a valid utf8 string");
5710 len = g_utf8_strlen (text, -1);
5711 o = mono_string_new_size_checked (domain, len, error);
5714 str = mono_string_chars (o);
5716 while (text < end) {
5717 *str++ = g_utf8_get_char (text);
5718 text = g_utf8_next_char (text);
5727 * mono_string_new_wrapper:
5728 * @text: pointer to utf8 characters.
5730 * Helper function to create a string object from @text in the current domain.
5733 mono_string_new_wrapper (const char *text)
5735 MONO_REQ_GC_UNSAFE_MODE;
5737 MonoDomain *domain = mono_domain_get ();
5740 return mono_string_new (domain, text);
5747 * @class: the class of the value
5748 * @value: a pointer to the unboxed data
5750 * Returns: A newly created object which contains @value.
5753 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5755 MONO_REQ_GC_UNSAFE_MODE;
5762 g_assert (klass->valuetype);
5763 if (mono_class_is_nullable (klass))
5764 return mono_nullable_box ((guint8 *)value, klass);
5766 vtable = mono_class_vtable (domain, klass);
5769 size = mono_class_instance_size (klass);
5770 res = mono_object_new_alloc_specific_checked (vtable, &error);
5771 mono_error_raise_exception (&error); /* FIXME don't raise here */
5773 size = size - sizeof (MonoObject);
5776 g_assert (size == mono_class_value_size (klass, NULL));
5777 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5779 #if NO_UNALIGNED_ACCESS
5780 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5784 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5787 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5790 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5793 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5796 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5800 if (klass->has_finalize) {
5801 mono_object_register_finalizer (res, &error);
5802 mono_error_raise_exception (&error); /* FIXME don't raise here */
5809 * @dest: destination pointer
5810 * @src: source pointer
5811 * @klass: a valuetype class
5813 * Copy a valuetype from @src to @dest. This function must be used
5814 * when @klass contains references fields.
5817 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5819 MONO_REQ_GC_UNSAFE_MODE;
5821 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5825 * mono_value_copy_array:
5826 * @dest: destination array
5827 * @dest_idx: index in the @dest array
5828 * @src: source pointer
5829 * @count: number of items
5831 * Copy @count valuetype items from @src to the array @dest at index @dest_idx.
5832 * This function must be used when @klass contains references fields.
5833 * Overlap is handled.
5836 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5838 MONO_REQ_GC_UNSAFE_MODE;
5840 int size = mono_array_element_size (dest->obj.vtable->klass);
5841 char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5842 g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5843 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5847 * mono_object_get_domain:
5848 * @obj: object to query
5850 * Returns: the MonoDomain where the object is hosted
5853 mono_object_get_domain (MonoObject *obj)
5855 MONO_REQ_GC_UNSAFE_MODE;
5857 return mono_object_domain (obj);
5861 * mono_object_get_class:
5862 * @obj: object to query
5864 * Use this function to obtain the `MonoClass*` for a given `MonoObject`.
5866 * Returns: the MonoClass of the object.
5869 mono_object_get_class (MonoObject *obj)
5871 MONO_REQ_GC_UNSAFE_MODE;
5873 return mono_object_class (obj);
5876 * mono_object_get_size:
5877 * @o: object to query
5879 * Returns: the size, in bytes, of @o
5882 mono_object_get_size (MonoObject* o)
5884 MONO_REQ_GC_UNSAFE_MODE;
5886 MonoClass* klass = mono_object_class (o);
5887 if (klass == mono_defaults.string_class) {
5888 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5889 } else if (o->vtable->rank) {
5890 MonoArray *array = (MonoArray*)o;
5891 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5892 if (array->bounds) {
5895 size += sizeof (MonoArrayBounds) * o->vtable->rank;
5899 return mono_class_instance_size (klass);
5904 * mono_object_unbox:
5905 * @obj: object to unbox
5907 * Returns: a pointer to the start of the valuetype boxed in this
5910 * This method will assert if the object passed is not a valuetype.
5913 mono_object_unbox (MonoObject *obj)
5915 MONO_REQ_GC_UNSAFE_MODE;
5917 /* add assert for valuetypes? */
5918 g_assert (obj->vtable->klass->valuetype);
5919 return ((char*)obj) + sizeof (MonoObject);
5923 * mono_object_isinst:
5925 * @klass: a pointer to a class
5927 * Returns: @obj if @obj is derived from @klass
5930 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5932 MONO_REQ_GC_UNSAFE_MODE;
5935 mono_class_init (klass);
5937 if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5938 return mono_object_isinst_mbyref (obj, klass);
5943 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5947 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5949 MONO_REQ_GC_UNSAFE_MODE;
5959 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5960 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5964 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5965 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5968 MonoClass *oklass = vt->klass;
5969 if (mono_class_is_transparent_proxy (oklass))
5970 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5972 mono_class_setup_supertypes (klass);
5973 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5976 #ifndef DISABLE_REMOTING
5977 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
5979 MonoDomain *domain = mono_domain_get ();
5981 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5982 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5983 MonoMethod *im = NULL;
5986 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5988 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5989 im = mono_object_get_virtual_method (rp, im);
5992 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5993 mono_error_raise_exception (&error); /* FIXME don't raise here */
5996 res = mono_runtime_invoke_checked (im, rp, pa, &error);
5997 mono_error_raise_exception (&error); /* FIXME don't raise here */
5999 if (*(MonoBoolean *) mono_object_unbox(res)) {
6000 /* Update the vtable of the remote type, so it can safely cast to this new type */
6001 mono_upgrade_remote_class (domain, obj, klass);
6005 #endif /* DISABLE_REMOTING */
6010 * mono_object_castclass_mbyref:
6012 * @klass: a pointer to a class
6014 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
6017 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
6019 MONO_REQ_GC_UNSAFE_MODE;
6021 if (!obj) return NULL;
6022 if (mono_object_isinst_mbyref (obj, klass)) return obj;
6024 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
6026 "InvalidCastException"));
6031 MonoDomain *orig_domain;
6037 str_lookup (MonoDomain *domain, gpointer user_data)
6039 MONO_REQ_GC_UNSAFE_MODE;
6041 LDStrInfo *info = (LDStrInfo *)user_data;
6042 if (info->res || domain == info->orig_domain)
6044 info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6048 mono_string_get_pinned (MonoString *str, MonoError *error)
6050 MONO_REQ_GC_UNSAFE_MODE;
6052 mono_error_init (error);
6054 /* We only need to make a pinned version of a string if this is a moving GC */
6055 if (!mono_gc_is_moving ())
6059 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6060 news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6062 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6063 news->length = mono_string_length (str);
6065 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6071 mono_string_is_interned_lookup (MonoString *str, int insert)
6073 MONO_REQ_GC_UNSAFE_MODE;
6076 MonoGHashTable *ldstr_table;
6077 MonoString *s, *res;
6080 domain = ((MonoObject *)str)->vtable->domain;
6081 ldstr_table = domain->ldstr_table;
6083 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6089 /* Allocate outside the lock */
6091 s = mono_string_get_pinned (str, &error);
6092 mono_error_raise_exception (&error); /* FIXME don't raise here */
6095 res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6100 mono_g_hash_table_insert (ldstr_table, s, s);
6105 LDStrInfo ldstr_info;
6106 ldstr_info.orig_domain = domain;
6107 ldstr_info.ins = str;
6108 ldstr_info.res = NULL;
6110 mono_domain_foreach (str_lookup, &ldstr_info);
6111 if (ldstr_info.res) {
6113 * the string was already interned in some other domain:
6114 * intern it in the current one as well.
6116 mono_g_hash_table_insert (ldstr_table, str, str);
6126 * mono_string_is_interned:
6127 * @o: String to probe
6129 * Returns whether the string has been interned.
6132 mono_string_is_interned (MonoString *o)
6134 MONO_REQ_GC_UNSAFE_MODE;
6136 return mono_string_is_interned_lookup (o, FALSE);
6140 * mono_string_intern:
6141 * @o: String to intern
6143 * Interns the string passed.
6144 * Returns: The interned string.
6147 mono_string_intern (MonoString *str)
6149 MONO_REQ_GC_UNSAFE_MODE;
6151 return mono_string_is_interned_lookup (str, TRUE);
6156 * @domain: the domain where the string will be used.
6157 * @image: a metadata context
6158 * @idx: index into the user string table.
6160 * Implementation for the ldstr opcode.
6161 * Returns: a loaded string from the @image/@idx combination.
6164 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6166 MONO_REQ_GC_UNSAFE_MODE;
6168 if (image->dynamic) {
6169 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
6172 if (!mono_verifier_verify_string_signature (image, idx, NULL))
6173 return NULL; /*FIXME we should probably be raising an exception here*/
6174 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
6179 * mono_ldstr_metadata_sig
6180 * @domain: the domain for the string
6181 * @sig: the signature of a metadata string
6183 * Returns: a MonoString for a string stored in the metadata
6186 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
6188 MONO_REQ_GC_UNSAFE_MODE;
6191 const char *str = sig;
6192 MonoString *o, *interned;
6195 len2 = mono_metadata_decode_blob_size (str, &str);
6198 o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, &error);
6199 mono_error_raise_exception (&error); /* FIXME don't raise here */
6200 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6203 guint16 *p2 = (guint16*)mono_string_chars (o);
6204 for (i = 0; i < len2; ++i) {
6205 *p2 = GUINT16_FROM_LE (*p2);
6211 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6214 return interned; /* o will get garbage collected */
6216 o = mono_string_get_pinned (o, &error);
6217 mono_error_raise_exception (&error); /* FIXME don't raise here */
6220 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6222 mono_g_hash_table_insert (domain->ldstr_table, o, o);
6232 * mono_string_to_utf8:
6233 * @s: a System.String
6235 * Returns the UTF8 representation for @s.
6236 * The resulting buffer needs to be freed with mono_free().
6238 * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
6241 mono_string_to_utf8 (MonoString *s)
6243 MONO_REQ_GC_UNSAFE_MODE;
6246 char *result = mono_string_to_utf8_checked (s, &error);
6248 if (!mono_error_ok (&error))
6249 mono_error_raise_exception (&error);
6254 * mono_string_to_utf8_checked:
6255 * @s: a System.String
6256 * @error: a MonoError.
6258 * Converts a MonoString to its UTF8 representation. May fail; check
6259 * @error to determine whether the conversion was successful.
6260 * The resulting buffer should be freed with mono_free().
6263 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
6265 MONO_REQ_GC_UNSAFE_MODE;
6269 GError *gerror = NULL;
6271 mono_error_init (error);
6277 return g_strdup ("");
6279 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
6281 mono_error_set_argument (error, "string", "%s", gerror->message);
6282 g_error_free (gerror);
6285 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6286 if (s->length > written) {
6287 /* allocate the total length and copy the part of the string that has been converted */
6288 char *as2 = (char *)g_malloc0 (s->length);
6289 memcpy (as2, as, written);
6298 * mono_string_to_utf8_ignore:
6301 * Converts a MonoString to its UTF8 representation. Will ignore
6302 * invalid surrogate pairs.
6303 * The resulting buffer should be freed with mono_free().
6307 mono_string_to_utf8_ignore (MonoString *s)
6309 MONO_REQ_GC_UNSAFE_MODE;
6318 return g_strdup ("");
6320 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
6322 /* g_utf16_to_utf8 may not be able to complete the convertion (e.g. NULL values were found, #335488) */
6323 if (s->length > written) {
6324 /* allocate the total length and copy the part of the string that has been converted */
6325 char *as2 = (char *)g_malloc0 (s->length);
6326 memcpy (as2, as, written);
6335 * mono_string_to_utf8_image_ignore:
6336 * @s: a System.String
6338 * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
6341 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
6343 MONO_REQ_GC_UNSAFE_MODE;
6345 return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
6349 * mono_string_to_utf8_mp_ignore:
6350 * @s: a System.String
6352 * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
6355 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
6357 MONO_REQ_GC_UNSAFE_MODE;
6359 return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
6364 * mono_string_to_utf16:
6367 * Return an null-terminated array of the utf-16 chars
6368 * contained in @s. The result must be freed with g_free().
6369 * This is a temporary helper until our string implementation
6370 * is reworked to always include the null terminating char.
6373 mono_string_to_utf16 (MonoString *s)
6375 MONO_REQ_GC_UNSAFE_MODE;
6382 as = (char *)g_malloc ((s->length * 2) + 2);
6383 as [(s->length * 2)] = '\0';
6384 as [(s->length * 2) + 1] = '\0';
6387 return (gunichar2 *)(as);
6390 memcpy (as, mono_string_chars(s), s->length * 2);
6391 return (gunichar2 *)(as);
6395 * mono_string_to_utf32:
6398 * Return an null-terminated array of the UTF-32 (UCS-4) chars
6399 * contained in @s. The result must be freed with g_free().
6402 mono_string_to_utf32 (MonoString *s)
6404 MONO_REQ_GC_UNSAFE_MODE;
6406 mono_unichar4 *utf32_output = NULL;
6407 GError *error = NULL;
6408 glong items_written;
6413 utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6416 g_error_free (error);
6418 return utf32_output;
6422 * mono_string_from_utf16:
6423 * @data: the UTF16 string (LPWSTR) to convert
6425 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6427 * Returns: a MonoString.
6430 mono_string_from_utf16 (gunichar2 *data)
6432 MONO_REQ_GC_UNSAFE_MODE;
6435 MonoString *res = NULL;
6436 MonoDomain *domain = mono_domain_get ();
6442 while (data [len]) len++;
6444 res = mono_string_new_utf16_checked (domain, data, len, &error);
6445 mono_error_raise_exception (&error); /* FIXME don't raise here */
6450 * mono_string_from_utf32:
6451 * @data: the UTF32 string (LPWSTR) to convert
6453 * Converts a UTF32 (UCS-4)to a MonoString.
6455 * Returns: a MonoString.
6458 mono_string_from_utf32 (mono_unichar4 *data)
6460 MONO_REQ_GC_UNSAFE_MODE;
6462 MonoString* result = NULL;
6463 mono_unichar2 *utf16_output = NULL;
6464 GError *error = NULL;
6465 glong items_written;
6471 while (data [len]) len++;
6473 utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6476 g_error_free (error);
6478 result = mono_string_from_utf16 (utf16_output);
6479 g_free (utf16_output);
6484 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6486 MONO_REQ_GC_UNSAFE_MODE;
6493 r = mono_string_to_utf8_ignore (s);
6495 r = mono_string_to_utf8_checked (s, error);
6496 if (!mono_error_ok (error))
6503 len = strlen (r) + 1;
6505 mp_s = (char *)mono_mempool_alloc (mp, len);
6507 mp_s = (char *)mono_image_alloc (image, len);
6509 memcpy (mp_s, r, len);
6517 * mono_string_to_utf8_image:
6518 * @s: a System.String
6520 * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6523 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6525 MONO_REQ_GC_UNSAFE_MODE;
6527 return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6531 * mono_string_to_utf8_mp:
6532 * @s: a System.String
6534 * Same as mono_string_to_utf8, but allocate the string from a mempool.
6537 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6539 MONO_REQ_GC_UNSAFE_MODE;
6541 return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6545 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6548 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6550 eh_callbacks = *cbs;
6553 MonoRuntimeExceptionHandlingCallbacks *
6554 mono_get_eh_callbacks (void)
6556 return &eh_callbacks;
6560 * mono_raise_exception:
6561 * @ex: exception object
6563 * Signal the runtime that the exception @ex has been raised in unmanaged code.
6566 mono_raise_exception (MonoException *ex)
6568 MONO_REQ_GC_UNSAFE_MODE;
6571 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6572 * that will cause gcc to omit the function epilog, causing problems when
6573 * the JIT tries to walk the stack, since the return address on the stack
6574 * will point into the next function in the executable, not this one.
6576 eh_callbacks.mono_raise_exception (ex);
6580 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
6582 MONO_REQ_GC_UNSAFE_MODE;
6584 eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6588 * mono_wait_handle_new:
6589 * @domain: Domain where the object will be created
6590 * @handle: Handle for the wait handle
6592 * Returns: A new MonoWaitHandle created in the given domain for the given handle
6595 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6597 MONO_REQ_GC_UNSAFE_MODE;
6600 MonoWaitHandle *res;
6601 gpointer params [1];
6602 static MonoMethod *handle_set;
6604 res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, &error);
6605 mono_error_raise_exception (&error); /* FIXME don't raise here */
6607 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
6609 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6611 params [0] = &handle;
6613 mono_runtime_invoke_checked (handle_set, res, params, &error);
6614 mono_error_raise_exception (&error); /* FIXME don't raise here */
6620 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6622 MONO_REQ_GC_UNSAFE_MODE;
6624 static MonoClassField *f_safe_handle = NULL;
6627 if (!f_safe_handle) {
6628 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
6629 g_assert (f_safe_handle);
6632 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6638 mono_runtime_capture_context (MonoDomain *domain)
6640 MONO_REQ_GC_UNSAFE_MODE;
6642 RuntimeInvokeFunction runtime_invoke;
6644 if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6645 MonoMethod *method = mono_get_context_capture_method ();
6646 MonoMethod *wrapper;
6649 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6650 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6651 domain->capture_context_method = mono_compile_method (method);
6654 runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6656 return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6659 * mono_async_result_new:
6660 * @domain:domain where the object will be created.
6661 * @handle: wait handle.
6662 * @state: state to pass to AsyncResult
6663 * @data: C closure data.
6665 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6666 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6670 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6672 MONO_REQ_GC_UNSAFE_MODE;
6675 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, &error);
6676 mono_error_raise_exception (&error); /* FIXME don't raise here */
6677 MonoObject *context = mono_runtime_capture_context (domain);
6678 /* we must capture the execution context from the original thread */
6680 MONO_OBJECT_SETREF (res, execution_context, context);
6681 /* note: result may be null if the flow is suppressed */
6684 res->data = (void **)data;
6685 MONO_OBJECT_SETREF (res, object_data, object_data);
6686 MONO_OBJECT_SETREF (res, async_state, state);
6688 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6690 res->sync_completed = FALSE;
6691 res->completed = FALSE;
6697 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6699 MONO_REQ_GC_UNSAFE_MODE;
6706 g_assert (ares->async_delegate);
6708 ac = (MonoAsyncCall*) ares->object_data;
6710 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6712 gpointer wait_event = NULL;
6714 ac->msg->exc = NULL;
6715 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6716 MONO_OBJECT_SETREF (ac, res, res);
6718 mono_monitor_enter ((MonoObject*) ares);
6719 ares->completed = 1;
6721 wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6722 mono_monitor_exit ((MonoObject*) ares);
6724 if (wait_event != NULL)
6725 SetEvent (wait_event);
6727 if (ac->cb_method) {
6728 mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
6729 mono_error_raise_exception (&error);
6737 mono_message_init (MonoDomain *domain,
6738 MonoMethodMessage *this_obj,
6739 MonoReflectionMethod *method,
6740 MonoArray *out_args)
6742 MONO_REQ_GC_UNSAFE_MODE;
6744 static MonoClass *object_array_klass;
6745 static MonoClass *byte_array_klass;
6746 static MonoClass *string_array_klass;
6748 MonoMethodSignature *sig = mono_method_signature (method->method);
6755 if (!object_array_klass) {
6758 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6760 byte_array_klass = klass;
6762 klass = mono_array_class_get (mono_defaults.string_class, 1);
6764 string_array_klass = klass;
6766 klass = mono_array_class_get (mono_defaults.object_class, 1);
6769 mono_atomic_store_release (&object_array_klass, klass);
6772 MONO_OBJECT_SETREF (this_obj, method, method);
6774 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6775 mono_error_raise_exception (&error); /* FIXME don't raise here */
6777 MONO_OBJECT_SETREF (this_obj, args, arr);
6779 arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6780 mono_error_raise_exception (&error); /* FIXME don't raise here */
6782 MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6784 this_obj->async_result = NULL;
6785 this_obj->call_type = CallType_Sync;
6787 names = g_new (char *, sig->param_count);
6788 mono_method_get_param_names (method->method, (const char **) names);
6790 arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6791 mono_error_raise_exception (&error); /* FIXME don't raise here */
6793 MONO_OBJECT_SETREF (this_obj, names, arr);
6795 for (i = 0; i < sig->param_count; i++) {
6796 name = mono_string_new (domain, names [i]);
6797 mono_array_setref (this_obj->names, i, name);
6801 for (i = 0, j = 0; i < sig->param_count; i++) {
6802 if (sig->params [i]->byref) {
6804 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6805 mono_array_setref (this_obj->args, i, arg);
6809 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6813 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6816 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6820 #ifndef DISABLE_REMOTING
6822 * mono_remoting_invoke:
6823 * @real_proxy: pointer to a RealProxy object
6824 * @msg: The MonoMethodMessage to execute
6825 * @exc: used to store exceptions
6826 * @out_args: used to store output arguments
6828 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6829 * IMessage interface and it is not trivial to extract results from there. So
6830 * we call an helper method PrivateInvoke instead of calling
6831 * RealProxy::Invoke() directly.
6833 * Returns: the result object.
6836 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
6837 MonoObject **exc, MonoArray **out_args)
6839 MONO_REQ_GC_UNSAFE_MODE;
6843 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6846 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6849 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6851 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6852 real_proxy->vtable->domain->private_invoke_method = im;
6855 pa [0] = real_proxy;
6861 o = mono_runtime_try_invoke (im, NULL, pa, exc, &error);
6863 o = mono_runtime_invoke_checked (im, NULL, pa, &error);
6865 mono_error_raise_exception (&error); /* FIXME don't raise here */
6872 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
6873 MonoObject **exc, MonoArray **out_args)
6875 MONO_REQ_GC_UNSAFE_MODE;
6877 static MonoClass *object_array_klass;
6881 MonoMethodSignature *sig;
6884 int i, j, outarg_count = 0;
6886 #ifndef DISABLE_REMOTING
6887 if (target && mono_object_is_transparent_proxy (target)) {
6888 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6889 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6890 target = tp->rp->unwrapped_server;
6892 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6897 domain = mono_domain_get ();
6898 method = msg->method->method;
6899 sig = mono_method_signature (method);
6901 for (i = 0; i < sig->param_count; i++) {
6902 if (sig->params [i]->byref)
6906 if (!object_array_klass) {
6909 klass = mono_array_class_get (mono_defaults.object_class, 1);
6912 mono_memory_barrier ();
6913 object_array_klass = klass;
6916 arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6917 mono_error_raise_exception (&error); /* FIXME don't raise here */
6919 mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6922 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6924 for (i = 0, j = 0; i < sig->param_count; i++) {
6925 if (sig->params [i]->byref) {
6927 arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6928 mono_array_setref (*out_args, j, arg);
6937 * mono_object_to_string:
6939 * @exc: Any exception thrown by ToString (). May be NULL.
6941 * Returns: the result of calling ToString () on an object.
6944 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6946 MONO_REQ_GC_UNSAFE_MODE;
6948 static MonoMethod *to_string = NULL;
6957 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6959 method = mono_object_get_virtual_method (obj, to_string);
6961 // Unbox value type if needed
6962 if (mono_class_is_valuetype (mono_method_get_class (method))) {
6963 target = mono_object_unbox (obj);
6967 s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
6968 if (*exc == NULL && !mono_error_ok (&error))
6969 *exc = (MonoObject*) mono_error_convert_to_exception (&error);
6971 mono_error_cleanup (&error);
6973 s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
6974 mono_error_raise_exception (&error); /* FIXME don't raise here */
6981 * mono_print_unhandled_exception:
6982 * @exc: The exception
6984 * Prints the unhandled exception.
6987 mono_print_unhandled_exception (MonoObject *exc)
6989 MONO_REQ_GC_UNSAFE_MODE;
6992 char *message = (char*)"";
6993 gboolean free_message = FALSE;
6996 if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6997 message = g_strdup ("OutOfMemoryException");
6998 free_message = TRUE;
6999 } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7000 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7001 free_message = TRUE;
7004 if (((MonoException*)exc)->native_trace_ips) {
7005 message = mono_exception_get_native_backtrace ((MonoException*)exc);
7006 free_message = TRUE;
7008 MonoObject *other_exc = NULL;
7009 str = mono_object_to_string (exc, &other_exc);
7011 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7012 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7014 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7015 original_backtrace, nested_backtrace);
7017 g_free (original_backtrace);
7018 g_free (nested_backtrace);
7019 free_message = TRUE;
7021 message = mono_string_to_utf8_checked (str, &error);
7022 if (!mono_error_ok (&error)) {
7023 mono_error_cleanup (&error);
7024 message = (char *) "";
7026 free_message = TRUE;
7033 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7034 * exc->vtable->klass->name, message);
7036 g_printerr ("\nUnhandled Exception:\n%s\n", message);
7043 * mono_delegate_ctor:
7044 * @this: pointer to an uninitialized delegate object
7045 * @target: target object
7046 * @addr: pointer to native code
7049 * Initialize a delegate and sets a specific method, not the one
7050 * associated with addr. This is useful when sharing generic code.
7051 * In that case addr will most probably not be associated with the
7052 * correct instantiation of the method.
7055 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
7057 MONO_REQ_GC_UNSAFE_MODE;
7059 MonoDelegate *delegate = (MonoDelegate *)this_obj;
7061 g_assert (this_obj);
7064 g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
7067 delegate->method = method;
7069 mono_stats.delegate_creations++;
7071 #ifndef DISABLE_REMOTING
7072 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
7074 method = mono_marshal_get_remoting_invoke (method);
7075 delegate->method_ptr = mono_compile_method (method);
7076 MONO_OBJECT_SETREF (delegate, target, target);
7080 delegate->method_ptr = addr;
7081 MONO_OBJECT_SETREF (delegate, target, target);
7084 delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
7085 if (callbacks.init_delegate)
7086 callbacks.init_delegate (delegate);
7090 * mono_delegate_ctor:
7091 * @this: pointer to an uninitialized delegate object
7092 * @target: target object
7093 * @addr: pointer to native code
7095 * This is used to initialize a delegate.
7098 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
7100 MONO_REQ_GC_UNSAFE_MODE;
7102 MonoDomain *domain = mono_domain_get ();
7104 MonoMethod *method = NULL;
7108 ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7110 if (!ji && domain != mono_get_root_domain ())
7111 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
7113 method = mono_jit_info_get_method (ji);
7114 g_assert (!method->klass->generic_container);
7117 mono_delegate_ctor_with_method (this_obj, target, addr, method);
7121 * mono_method_call_message_new:
7122 * @method: method to encapsulate
7123 * @params: parameters to the method
7124 * @invoke: optional, delegate invoke.
7125 * @cb: async callback delegate.
7126 * @state: state passed to the async callback.
7128 * Translates arguments pointers into a MonoMethodMessage.
7131 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
7132 MonoDelegate **cb, MonoObject **state)
7134 MONO_REQ_GC_UNSAFE_MODE;
7138 MonoDomain *domain = mono_domain_get ();
7139 MonoMethodSignature *sig = mono_method_signature (method);
7140 MonoMethodMessage *msg;
7143 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7144 mono_error_raise_exception (&error); /* FIXME don't raise here */
7147 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, &error);
7148 mono_error_raise_exception (&error); /* FIXME don't raise here */
7149 mono_message_init (domain, msg, rm, NULL);
7150 count = sig->param_count - 2;
7152 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error);
7153 mono_error_raise_exception (&error); /* FIXME don't raise here */
7154 mono_message_init (domain, msg, rm, NULL);
7155 count = sig->param_count;
7158 for (i = 0; i < count; i++) {
7163 if (sig->params [i]->byref)
7164 vpos = *((gpointer *)params [i]);
7168 klass = mono_class_from_mono_type (sig->params [i]);
7170 if (klass->valuetype)
7171 arg = mono_value_box (domain, klass, vpos);
7173 arg = *((MonoObject **)vpos);
7175 mono_array_setref (msg->args, i, arg);
7178 if (cb != NULL && state != NULL) {
7179 *cb = *((MonoDelegate **)params [i]);
7181 *state = *((MonoObject **)params [i]);
7188 * mono_method_return_message_restore:
7190 * Restore results from message based processing back to arguments pointers
7193 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
7195 MONO_REQ_GC_UNSAFE_MODE;
7197 MonoMethodSignature *sig = mono_method_signature (method);
7198 int i, j, type, size, out_len;
7200 if (out_args == NULL)
7202 out_len = mono_array_length (out_args);
7206 for (i = 0, j = 0; i < sig->param_count; i++) {
7207 MonoType *pt = sig->params [i];
7212 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
7214 arg = (char *)mono_array_get (out_args, gpointer, j);
7217 g_assert (type != MONO_TYPE_VOID);
7219 if (MONO_TYPE_IS_REFERENCE (pt)) {
7220 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
7223 MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
7224 size = mono_class_value_size (klass, NULL);
7225 if (klass->has_references)
7226 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
7228 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
7230 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
7231 mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
7240 #ifndef DISABLE_REMOTING
7243 * mono_load_remote_field:
7244 * @this: pointer to an object
7245 * @klass: klass of the object containing @field
7246 * @field: the field to load
7247 * @res: a storage to store the result
7249 * This method is called by the runtime on attempts to load fields of
7250 * transparent proxy objects. @this points to such TP, @klass is the class of
7251 * the object containing @field. @res is a storage location which can be
7252 * used to store the result.
7254 * Returns: an address pointing to the value of field.
7257 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
7259 MONO_REQ_GC_UNSAFE_MODE;
7263 static MonoMethod *getter = NULL;
7264 MonoDomain *domain = mono_domain_get ();
7265 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7266 MonoClass *field_class;
7267 MonoMethodMessage *msg;
7268 MonoArray *out_args;
7272 g_assert (mono_object_is_transparent_proxy (this_obj));
7273 g_assert (res != NULL);
7275 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7276 mono_field_get_value (tp->rp->unwrapped_server, field, res);
7281 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7283 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7286 field_class = mono_class_from_mono_type (field->type);
7288 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7289 mono_error_raise_exception (&error); /* FIXME don't raise here */
7290 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7291 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7292 mono_error_raise_exception (&error); /* FIXME don't raise here */
7293 mono_message_init (domain, msg, rm, out_args);
7295 full_name = mono_type_get_full_name (klass);
7296 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7297 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7300 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7302 if (exc) mono_raise_exception ((MonoException *)exc);
7304 if (mono_array_length (out_args) == 0)
7307 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
7309 if (field_class->valuetype) {
7310 return ((char *)*res) + sizeof (MonoObject);
7316 * mono_load_remote_field_new:
7321 * Missing documentation.
7324 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
7326 MONO_REQ_GC_UNSAFE_MODE;
7330 static MonoMethod *getter = NULL;
7331 MonoDomain *domain = mono_domain_get ();
7332 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7333 MonoClass *field_class;
7334 MonoMethodMessage *msg;
7335 MonoArray *out_args;
7336 MonoObject *exc, *res;
7339 g_assert (mono_object_is_transparent_proxy (this_obj));
7341 field_class = mono_class_from_mono_type (field->type);
7343 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7345 if (field_class->valuetype) {
7346 res = mono_object_new_checked (domain, field_class, &error);
7347 mono_error_raise_exception (&error); /* FIXME don't raise here */
7348 val = ((gchar *) res) + sizeof (MonoObject);
7352 mono_field_get_value (tp->rp->unwrapped_server, field, val);
7357 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
7359 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7362 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7363 mono_error_raise_exception (&error); /* FIXME don't raise here */
7364 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
7366 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, &error);
7367 mono_error_raise_exception (&error); /* FIXME don't raise here */
7368 mono_message_init (domain, msg, rm, out_args);
7370 full_name = mono_type_get_full_name (klass);
7371 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7372 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7375 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7377 if (exc) mono_raise_exception ((MonoException *)exc);
7379 if (mono_array_length (out_args) == 0)
7382 res = mono_array_get (out_args, MonoObject *, 0);
7388 * mono_store_remote_field:
7389 * @this_obj: pointer to an object
7390 * @klass: klass of the object containing @field
7391 * @field: the field to load
7392 * @val: the value/object to store
7394 * This method is called by the runtime on attempts to store fields of
7395 * transparent proxy objects. @this_obj points to such TP, @klass is the class of
7396 * the object containing @field. @val is the new value to store in @field.
7399 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
7401 MONO_REQ_GC_UNSAFE_MODE;
7405 static MonoMethod *setter = NULL;
7406 MonoDomain *domain = mono_domain_get ();
7407 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7408 MonoClass *field_class;
7409 MonoMethodMessage *msg;
7410 MonoArray *out_args;
7415 g_assert (mono_object_is_transparent_proxy (this_obj));
7417 field_class = mono_class_from_mono_type (field->type);
7419 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7420 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7421 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7426 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7428 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7431 if (field_class->valuetype)
7432 arg = mono_value_box (domain, field_class, val);
7434 arg = *((MonoObject **)val);
7437 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7438 mono_error_raise_exception (&error); /* FIXME don't raise here */
7439 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7440 mono_error_raise_exception (&error); /* FIXME don't raise here */
7441 mono_message_init (domain, msg, rm, NULL);
7443 full_name = mono_type_get_full_name (klass);
7444 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7445 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7446 mono_array_setref (msg->args, 2, arg);
7449 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7451 if (exc) mono_raise_exception ((MonoException *)exc);
7455 * mono_store_remote_field_new:
7461 * Missing documentation
7464 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7466 MONO_REQ_GC_UNSAFE_MODE;
7470 static MonoMethod *setter = NULL;
7471 MonoDomain *domain = mono_domain_get ();
7472 MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7473 MonoClass *field_class;
7474 MonoMethodMessage *msg;
7475 MonoArray *out_args;
7479 g_assert (mono_object_is_transparent_proxy (this_obj));
7481 field_class = mono_class_from_mono_type (field->type);
7483 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7484 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7485 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7490 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7492 mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7495 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
7496 mono_error_raise_exception (&error); /* FIXME don't raise here */
7497 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, setter, NULL, &error);
7498 mono_error_raise_exception (&error); /* FIXME don't raise here */
7499 mono_message_init (domain, msg, rm, NULL);
7501 full_name = mono_type_get_full_name (klass);
7502 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7503 mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7504 mono_array_setref (msg->args, 2, arg);
7507 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7509 if (exc) mono_raise_exception ((MonoException *)exc);
7514 * mono_create_ftnptr:
7516 * Given a function address, create a function descriptor for it.
7517 * This is only needed on some platforms.
7520 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7522 return callbacks.create_ftnptr (domain, addr);
7526 * mono_get_addr_from_ftnptr:
7528 * Given a pointer to a function descriptor, return the function address.
7529 * This is only needed on some platforms.
7532 mono_get_addr_from_ftnptr (gpointer descr)
7534 return callbacks.get_addr_from_ftnptr (descr);
7538 * mono_string_chars:
7541 * Returns a pointer to the UCS16 characters stored in the MonoString
7544 mono_string_chars (MonoString *s)
7546 // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7552 * mono_string_length:
7555 * Returns the lenght in characters of the string
7558 mono_string_length (MonoString *s)
7560 MONO_REQ_GC_UNSAFE_MODE;
7566 * mono_array_length:
7567 * @array: a MonoArray*
7569 * Returns the total number of elements in the array. This works for
7570 * both vectors and multidimensional arrays.
7573 mono_array_length (MonoArray *array)
7575 MONO_REQ_GC_UNSAFE_MODE;
7577 return array->max_length;
7581 * mono_array_addr_with_size:
7582 * @array: a MonoArray*
7583 * @size: size of the array elements
7584 * @idx: index into the array
7586 * Use this function to obtain the address for the @idx item on the
7587 * @array containing elements of size @size.
7589 * This method performs no bounds checking or type checking.
7591 * Returns the address of the @idx element in the array.
7594 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7596 MONO_REQ_GC_UNSAFE_MODE;
7598 return ((char*)(array)->vector) + size * idx;
7603 mono_glist_to_array (GList *list, MonoClass *eclass)
7605 MonoDomain *domain = mono_domain_get ();
7612 len = g_list_length (list);
7613 res = mono_array_new (domain, eclass, len);
7615 for (i = 0; list; list = list->next, i++)
7616 mono_array_set (res, gpointer, i, list->data);
7623 * The following section is purely to declare prototypes and
7624 * document the API, as these C files are processed by our
7630 * @array: array to alter
7631 * @element_type: A C type name, this macro will use the sizeof(type) to determine the element size
7632 * @index: index into the array
7633 * @value: value to set
7635 * Value Type version: This sets the @index's element of the @array
7636 * with elements of size sizeof(type) to the provided @value.
7638 * This macro does not attempt to perform type checking or bounds checking.
7640 * Use this to set value types in a `MonoArray`.
7642 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
7647 * mono_array_setref:
7648 * @array: array to alter
7649 * @index: index into the array
7650 * @value: value to set
7652 * Reference Type version: This sets the @index's element of the
7653 * @array with elements of size sizeof(type) to the provided @value.
7655 * This macro does not attempt to perform type checking or bounds checking.
7657 * Use this to reference types in a `MonoArray`.
7659 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
7665 * @array: array on which to operate on
7666 * @element_type: C element type (example: MonoString *, int, MonoObject *)
7667 * @index: index into the array
7669 * Use this macro to retrieve the @index element of an @array and
7670 * extract the value assuming that the elements of the array match
7671 * the provided type value.
7673 * This method can be used with both arrays holding value types and
7674 * reference types. For reference types, the @type parameter should
7675 * be a `MonoObject*` or any subclass of it, like `MonoString*`.
7677 * This macro does not attempt to perform type checking or bounds checking.
7679 * Returns: The element at the @index position in the @array.
7681 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)